Compare commits

...

21 Commits

Author SHA1 Message Date
Avuton Olrich
b1cc760aa5 mpd version 0.15.7 2009-12-27 08:31:47 -08:00
Max Kellermann
d66c055fec dbUtils: return multiple tag values per song
When collecting tag values for the result set, add all of a song's tag
values of the searched type.  This affects the "list" command.
Previously, "list" only considered the first tag value of a song.
2009-12-27 16:49:04 +01:00
Max Kellermann
915d1d0738 decoder_thread: eliminate jitter after seek failure
Don't clear the music pipe when seeking has failed - check the
"seeking" flag instead of "command==SEEK".  Clear the "seeking" flag
in decoder_seek_error().
2009-12-26 02:58:30 +01:00
Max Kellermann
8a6d448aaf decoder/wavpack: allow fine-grained seeking
First multiply the floating point return value of
decoder_seek_where(), then cast to integer.
2009-12-26 02:58:30 +01:00
Max Kellermann
a1939f3966 Makefile.am: create doxygen output directory 2009-12-26 02:58:30 +01:00
Max Kellermann
9179f108a5 iso, zip: fixed memory leak in destructor
Free the "context" pointer in the method archive_plugin.close().
2009-12-15 19:57:00 +01:00
Max Kellermann
3411f6cffd archive: close archive when stream is closed
Fixes a memory leak: the "archive" input plugin opens the archive, but
never closes it.  This patch moves the responsibility for doing that
to archive_plugin.open_stream().  This is an slight internal API
change, but it is the simplest and least intrusive fix for the memory
leak.
2009-12-15 19:45:50 +01:00
Max Kellermann
6c0f50efb5 archive/bz2: removed NULL check before g_free()
g_free(NULL) is allowed.
2009-12-15 19:42:54 +01:00
Max Kellermann
2234d491b7 input/archive: close the archive file on error
Fixed memory leak in error handler.
2009-12-15 19:41:00 +01:00
Max Kellermann
81aa58efa8 test/run_input: deinitialize everything after open() error
This enables valgrind debugging after an error occurred.
2009-12-15 19:40:47 +01:00
Max Kellermann
83aac2a057 test/run_input: initialize archive plugins
Enable archive plugin debugging.
2009-12-15 19:40:14 +01:00
Max Kellermann
f01d7d230b input/file: don't fall back to parent directory
This code has never made any sense, and has broken some of the archive
plugin.
2009-12-15 19:16:28 +01:00
Max Kellermann
8f7bc70bf5 decoder/wavpack: don't use the nonstandard "uchar" type
Use the signed C99 type int8_t instead.
2009-12-11 12:45:57 +01:00
Max Kellermann
5a354a1ed4 mixer: explicitly close all mixers on shutdown
Mixers with the "global" flag set aren't closed automatically when the
output device is closed.  Thus, they might still be open when MPD
shuts down.
2009-12-08 08:47:47 +01:00
Max Kellermann
f4b707b4ca mapper: apply filesystem_charset to playlists
This fixes an inconsistency in the stored playlist subsystem: when
obtaining the list of playlists (listplaylist, listplaylistinfo), the
file names in the playlist directory are converted to UTF-8 (according
to filesystem_charset), but when saving or loading playlists, the
filesystem_charset setting was ignored.
2009-12-08 08:33:14 +01:00
Max Kellermann
cd69fee0a4 command: verify playlist name in the "rm" command
Call spl_valid_name() in spl_delete().
2009-12-08 08:32:26 +01:00
Max Kellermann
23e46b38ca mapper: fix memory leak when playlist_directory is not set
Don't allocate the file name before the playlist_dir==NULL check.
2009-12-08 08:06:10 +01:00
svitoos
7162fe85ce tag_id3: fix ID3v1 charset conversion
If we define id3v1_encoding, then the tags are not added to the
database.
2009-11-30 17:42:46 +01:00
Max Kellermann
16123f1b8e ffmpeg: don't try to force stereo
The plugin code tried to force libavcodec to supply stereo samples.
That however has never actually worked.  By removing this code, we are
able to play surround files for the first time.
2009-11-30 09:59:05 +01:00
Max Kellermann
21fdf47b56 decoder/flac: fixed compiler warning
Removed the "vtrack" local variable (which triggered a gcc warning
because it was after the newly introduced NULL check), and run
strtol() on the original parameter.
2009-11-19 19:49:44 +01:00
Avuton Olrich
d1aee3ae74 Modify version string to post-release version 0.15.7~git 2009-11-18 18:49:25 -08:00
21 changed files with 163 additions and 92 deletions

@@ -748,6 +748,7 @@ DOCBOOK_HTML =
endif
doc/api/html/index.html: doc/doxygen.conf
@mkdir -p $(@D)
$(DOXYGEN) $<
all-local: $(DOCBOOK_HTML) doc/api/html/index.html

20
NEWS

@@ -1,3 +1,23 @@
ver 0.15.7 (2009/12/27)
* archive:
- close archive when stream is closed
- iso, zip: fixed memory leak in destructor
* input:
- file: don't fall back to parent directory
- archive: fixed memory leak in error handler
* tags:
- id3: fix ID3v1 charset conversion
* decoders:
- eliminate jitter after seek failure
- ffmpeg: don't try to force stereo
- wavpack: allow fine-grained seeking
* mixer: explicitly close all mixers on shutdown
* mapper: fix memory leak when playlist_directory is not set
* mapper: apply filesystem_charset to playlists
* command: verify playlist name in the "rm" command
* database: return multiple tag values per song
ver 0.15.6 (2009/11/18)
* input:
- lastfm: fixed variable name in GLib<2.16 code path

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.15.6, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.15.7, musicpd-dev-team@lists.sourceforge.net)
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2])
AM_CONFIG_HEADER(config.h)

@@ -140,8 +140,8 @@ static void
bz2_close(struct archive_file *file)
{
bz2_context *context = (bz2_context *) file;
if (context->name)
g_free(context->name);
g_free(context->name);
input_stream_close(&context->istream);
g_free(context);
@@ -173,6 +173,8 @@ bz2_is_close(struct input_stream *is)
bz2_context *context = (bz2_context *) is->data;
bz2_destroy(context);
is->data = NULL;
bz2_close((struct archive_file *)context);
}
static int

@@ -132,7 +132,8 @@ iso_close(struct archive_file *file)
}
//close archive
iso9660_close(context->iso);
context->iso = NULL;
g_free(context);
}
/* single archive handling */
@@ -165,6 +166,8 @@ iso_is_close(struct input_stream *is)
{
iso_context *context = (iso_context *) is->data;
g_free(context->statbuf);
iso_close((struct archive_file *)context);
}

@@ -99,7 +99,8 @@ zip_close(struct archive_file *file)
}
//close archive
zzip_dir_close (context->dir);
context->dir = NULL;
g_free(context);
}
/* single archive handling */
@@ -133,6 +134,8 @@ zip_is_close(struct input_stream *is)
{
zip_context *context = (zip_context *) is->data;
zzip_file_close (context->file);
zip_close((struct archive_file *)context);
}
static size_t

@@ -73,6 +73,9 @@ struct archive_plugin {
/**
* Opens an input_stream of a file within the archive.
*
* If this function succeeds, then the #input_stream "owns"
* the archive file and will automatically close it.
*
* @param path the path within the archive
*/
bool (*open_stream)(struct archive_file *, struct input_stream *is,

@@ -246,7 +246,6 @@ visitTag(struct client *client, struct strset *set,
for (unsigned i = 0; i < tag->num_items; i++) {
if (tag->items[i]->type == tagType) {
strset_add(set, tag->items[i]->value);
return;
}
}

@@ -419,9 +419,7 @@ flac_vtrack_tnum(const char* fname)
return 0;
// copy ascii tracknumber to int
char vtrack[4];
g_strlcpy(vtrack, ++ptr, 4);
return (unsigned int)strtol(vtrack, NULL, 10);
return (unsigned int)strtol(++ptr, NULL, 10);
}
#endif /* FLAC_API_VERSION_CURRENT >= 7 */

@@ -289,10 +289,6 @@ ffmpeg_decode_internal(struct ffmpeg_context *ctx)
total_time = 0;
if (codec_context->channels > 2) {
codec_context->channels = 2;
}
#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(41<<8)+0)
audio_format.bits = (uint8_t) av_get_bits_per_sample_format(codec_context->sample_fmt);
#else

@@ -72,7 +72,7 @@ format_samples_int(int bytes_per_sample, void *buffer, uint32_t count)
switch (bytes_per_sample) {
case 1: {
uchar *dst = buffer;
int8_t *dst = buffer;
/*
* The asserts like the following one are because we do the
* formatting of samples within a single buffer. The size
@@ -185,10 +185,9 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek,
do {
if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) {
if (can_seek) {
int where;
unsigned where = decoder_seek_where(decoder) *
audio_format.sample_rate;
where = decoder_seek_where(decoder);
where *= audio_format.sample_rate;
if (WavpackSeekSample(wpc, where)) {
position = where;
decoder_command_finished(decoder);

@@ -93,7 +93,9 @@ void decoder_command_finished(G_GNUC_UNUSED struct decoder * decoder)
dc.seek_error || decoder->seeking);
assert(dc.pipe != NULL);
if (dc.command == DECODE_COMMAND_SEEK) {
if (decoder->seeking) {
decoder->seeking = false;
/* delete frames from the old song position */
if (decoder->chunk != NULL) {
@@ -124,6 +126,8 @@ void decoder_seek_error(struct decoder * decoder)
assert(dc.pipe != NULL);
dc.seek_error = true;
decoder->seeking = false;
decoder_command_finished(decoder);
}

@@ -66,6 +66,7 @@ input_archive_open(struct input_stream *is, const char *pathname)
if (!opened) {
g_warning("open inarchive file %s failed\n\n",filename);
arplug->close(file);
} else {
is->ready = true;
}

@@ -36,25 +36,14 @@ input_file_open(struct input_stream *is, const char *filename)
int fd, ret;
struct stat st;
char* pathname = g_strdup(filename);
if (filename[0] != '/')
{
g_free(pathname);
return false;
}
if (stat(filename, &st) < 0) {
char* slash = strrchr(pathname, '/');
*slash = '\0';
}
fd = open(pathname, O_RDONLY);
fd = open(filename, O_RDONLY);
if (fd < 0) {
is->error = errno;
g_debug("Failed to open \"%s\": %s",
pathname, g_strerror(errno));
g_free(pathname);
filename, g_strerror(errno));
return false;
}
@@ -64,15 +53,13 @@ input_file_open(struct input_stream *is, const char *filename)
if (ret < 0) {
is->error = errno;
close(fd);
g_free(pathname);
return false;
}
if (!S_ISREG(st.st_mode)) {
g_debug("Not a regular file: %s", pathname);
g_debug("Not a regular file: %s", filename);
is->error = EINVAL;
close(fd);
g_free(pathname);
return false;
}
@@ -86,8 +73,6 @@ input_file_open(struct input_stream *is, const char *filename)
is->data = GINT_TO_POINTER(fd);
is->ready = true;
g_free(pathname);
return true;
}

@@ -221,14 +221,19 @@ map_spl_path(void)
char *
map_spl_utf8_to_fs(const char *name)
{
char *filename = g_strconcat(name, PLAYLIST_FILE_SUFFIX, NULL);
char *path;
char *filename_utf8, *filename_fs, *path;
if (playlist_dir == NULL)
return NULL;
path = g_build_filename(playlist_dir, filename, NULL);
g_free(filename);
filename_utf8 = g_strconcat(name, PLAYLIST_FILE_SUFFIX, NULL);
filename_fs = utf8_to_fs_charset(filename_utf8);
g_free(filename_utf8);
if (filename_fs == NULL)
return NULL;
path = g_build_filename(playlist_dir, filename_fs, NULL);
g_free(filename_fs);
return path;
}

@@ -99,6 +99,8 @@ map_spl_path(void);
* Maps a playlist name (without the ".m3u" suffix) to a file system
* path. The return value is allocated on the heap and must be freed
* with g_free().
*
* @return the path in file system encoding, or NULL if mapping failed
*/
char *
map_spl_utf8_to_fs(const char *name);

@@ -62,6 +62,10 @@ mixer_free(struct mixer *mixer)
assert(mixer->plugin != NULL);
assert(mixer->mutex != NULL);
/* mixers with the "global" flag set might still be open at
this point (see mixer_auto_close()) */
mixer_close(mixer);
g_mutex_free(mixer->mutex);
mixer->plugin->finish(mixer);

@@ -71,12 +71,15 @@ spl_save_queue(const char *name_utf8, const struct queue *queue)
char *path_fs;
FILE *file;
if (map_spl_path() == NULL)
return PLAYLIST_RESULT_DISABLED;
if (!spl_valid_name(name_utf8))
return PLAYLIST_RESULT_BAD_NAME;
path_fs = map_spl_utf8_to_fs(name_utf8);
if (path_fs == NULL)
return PLAYLIST_RESULT_DISABLED;
return PLAYLIST_RESULT_BAD_NAME;
if (g_file_test(path_fs, G_FILE_TEST_EXISTS)) {
g_free(path_fs);

@@ -152,9 +152,12 @@ spl_save(GPtrArray *list, const char *utf8path)
assert(utf8path != NULL);
if (map_spl_path() == NULL)
return PLAYLIST_RESULT_DISABLED;
path_fs = map_spl_utf8_to_fs(utf8path);
if (path_fs == NULL)
return PLAYLIST_RESULT_DISABLED;
return PLAYLIST_RESULT_BAD_NAME;
while (!(file = fopen(path_fs, "w")) && errno == EINTR);
g_free(path_fs);
@@ -178,7 +181,7 @@ spl_load(const char *utf8path)
char buffer[MPD_PATH_MAX];
char *path_fs;
if (!spl_valid_name(utf8path))
if (!spl_valid_name(utf8path) || map_spl_path() == NULL)
return NULL;
path_fs = map_spl_utf8_to_fs(utf8path);
@@ -299,12 +302,15 @@ spl_clear(const char *utf8path)
char *path_fs;
FILE *file;
if (map_spl_path() == NULL)
return PLAYLIST_RESULT_DISABLED;
if (!spl_valid_name(utf8path))
return PLAYLIST_RESULT_BAD_NAME;
path_fs = map_spl_utf8_to_fs(utf8path);
if (path_fs == NULL)
return PLAYLIST_RESULT_DISABLED;
return PLAYLIST_RESULT_BAD_NAME;
while (!(file = fopen(path_fs, "w")) && errno == EINTR);
g_free(path_fs);
@@ -323,9 +329,15 @@ spl_delete(const char *name_utf8)
char *path_fs;
int ret;
if (map_spl_path() == NULL)
return PLAYLIST_RESULT_DISABLED;
if (!spl_valid_name(name_utf8))
return PLAYLIST_RESULT_BAD_NAME;
path_fs = map_spl_utf8_to_fs(name_utf8);
if (path_fs == NULL)
return PLAYLIST_RESULT_DISABLED;
return PLAYLIST_RESULT_BAD_NAME;
ret = unlink(path_fs);
g_free(path_fs);
@@ -370,12 +382,15 @@ spl_append_song(const char *utf8path, struct song *song)
struct stat st;
char *path_fs;
if (map_spl_path() == NULL)
return PLAYLIST_RESULT_DISABLED;
if (!spl_valid_name(utf8path))
return PLAYLIST_RESULT_BAD_NAME;
path_fs = map_spl_utf8_to_fs(utf8path);
if (path_fs == NULL)
return PLAYLIST_RESULT_DISABLED;
return PLAYLIST_RESULT_BAD_NAME;
while (!(file = fopen(path_fs, "a")) && errno == EINTR);
g_free(path_fs);
@@ -445,6 +460,9 @@ spl_rename(const char *utf8from, const char *utf8to)
char *from_path_fs, *to_path_fs;
static enum playlist_result ret;
if (map_spl_path() == NULL)
return PLAYLIST_RESULT_DISABLED;
if (!spl_valid_name(utf8from) || !spl_valid_name(utf8to))
return PLAYLIST_RESULT_BAD_NAME;
@@ -454,7 +472,7 @@ spl_rename(const char *utf8from, const char *utf8to)
if (from_path_fs != NULL && to_path_fs != NULL)
ret = spl_rename_internal(from_path_fs, to_path_fs);
else
ret = PLAYLIST_RESULT_DISABLED;
ret = PLAYLIST_RESULT_BAD_NAME;
g_free(from_path_fs);
g_free(to_path_fs);

@@ -90,7 +90,7 @@ static id3_utf8_t * processID3FieldString (int is_id3v1, const id3_ucs4_t *ucs4,
utf8 = (id3_utf8_t *)
g_convert_with_fallback((const char*)isostr, -1,
encoding, "utf-8",
"utf-8", encoding,
NULL, NULL, NULL, NULL);
if (utf8 == NULL) {
g_debug("Unable to convert %s string to UTF-8: '%s'",

@@ -17,11 +17,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "input_stream.h"
#include "tag_pool.h"
#include "tag_save.h"
#include "conf.h"
#ifdef ENABLE_ARCHIVE
#include "archive_list.h"
#endif
#include <glib.h>
#include <unistd.h>
@@ -36,14 +41,58 @@ my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level,
g_printerr("%s\n", message);
}
int main(int argc, char **argv)
static int
dump_input_stream(struct input_stream *is)
{
struct input_stream is;
bool success;
char buffer[4096];
size_t num_read;
ssize_t num_written;
/* wait until the stream becomes ready */
while (!is->ready) {
int ret = input_stream_buffer(is);
if (ret < 0)
/* error */
return 2;
if (ret == 0)
/* nothing was buffered - wait */
g_usleep(10000);
}
/* print meta data */
if (is->mime != NULL)
g_printerr("MIME type: %s\n", is->mime);
/* read data and tags from the stream */
while (!input_stream_eof(is)) {
struct tag *tag = input_stream_tag(is);
if (tag != NULL) {
g_printerr("Received a tag:\n");
tag_save(stderr, tag);
tag_free(tag);
}
num_read = input_stream_read(is, buffer, sizeof(buffer));
if (num_read == 0)
break;
num_written = write(1, buffer, num_read);
if (num_written <= 0)
break;
}
return 0;
}
int main(int argc, char **argv)
{
struct input_stream is;
int ret;
if (argc != 2) {
g_printerr("Usage: run_input URI\n");
return 1;
@@ -58,57 +107,33 @@ int main(int argc, char **argv)
tag_pool_init();
config_global_init();
#ifdef ENABLE_ARCHIVE
archive_plugin_init_all();
#endif
input_stream_global_init();
/* open the stream and wait until it becomes ready */
/* open the stream and dump it */
success = input_stream_open(&is, argv[1]);
if (!success) {
if (input_stream_open(&is, argv[1])) {
ret = dump_input_stream(&is);
input_stream_close(&is);
} else {
g_printerr("input_stream_open() failed\n");
return 2;
}
while (!is.ready) {
int ret = input_stream_buffer(&is);
if (ret < 0)
/* error */
return 2;
if (ret == 0)
/* nothing was buffered - wait */
g_usleep(10000);
}
/* print meta data */
if (is.mime != NULL)
g_printerr("MIME type: %s\n", is.mime);
/* read data and tags from the stream */
while (!input_stream_eof(&is)) {
struct tag *tag = input_stream_tag(&is);
if (tag != NULL) {
g_printerr("Received a tag:\n");
tag_save(stderr, tag);
tag_free(tag);
}
num_read = input_stream_read(&is, buffer, sizeof(buffer));
if (num_read == 0)
break;
num_written = write(1, buffer, num_read);
if (num_written <= 0)
break;
ret = 2;
}
/* deinitialize everything */
input_stream_close(&is);
input_stream_global_finish();
#ifdef ENABLE_ARCHIVE
archive_plugin_deinit_all();
#endif
config_global_finish();
tag_pool_deinit();
return 0;
return ret;
}