diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/client.c | 13 | ||||
-rw-r--r-- | src/command.c | 15 | ||||
-rw-r--r-- | src/conf.c | 2 | ||||
-rw-r--r-- | src/conf.h | 2 | ||||
-rw-r--r-- | src/decoder/ffmpeg_plugin.c | 59 | ||||
-rw-r--r-- | src/decoder/mp3_plugin.c | 8 | ||||
-rw-r--r-- | src/decoder_api.c | 7 | ||||
-rw-r--r-- | src/listen.c | 3 | ||||
-rw-r--r-- | src/locate.c | 2 | ||||
-rw-r--r-- | src/log.c | 6 | ||||
-rw-r--r-- | src/ls.c | 61 | ||||
-rw-r--r-- | src/ls.h | 12 | ||||
-rw-r--r-- | src/mapper.c | 12 | ||||
-rw-r--r-- | src/mapper.h | 8 | ||||
-rw-r--r-- | src/output/ao_plugin.c | 6 | ||||
-rw-r--r-- | src/output/osx_plugin.c | 49 | ||||
-rw-r--r-- | src/output/shout_plugin.c | 6 | ||||
-rw-r--r-- | src/output_thread.c | 10 | ||||
-rw-r--r-- | src/pcm_utils.c | 6 | ||||
-rw-r--r-- | src/player_control.c | 25 | ||||
-rw-r--r-- | src/player_control.h | 8 | ||||
-rw-r--r-- | src/playlist.c | 12 | ||||
-rw-r--r-- | src/playlist_save.c | 4 | ||||
-rw-r--r-- | src/stored_playlist.c | 6 | ||||
-rw-r--r-- | src/stored_playlist.h | 1 | ||||
-rw-r--r-- | src/update.c | 2 |
27 files changed, 209 insertions, 141 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 0ec95ee82..38ba8b223 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -325,10 +325,13 @@ mpd_LDADD = $(MPD_LIBS) \ # URL: git://www.kernel.org/pub/scm/devel/sparse/sparse.git SPARSE = sparse SPARSE_FLAGS = +SPARSE_CPPFLAGS = $(DEFAULT_INCLUDES) \ + -I$(shell $(CC) -print-file-name=include) \ + -I$(shell $(CC) -print-file-name=include-fixed) sparse-check: for i in $(mpd_SOURCES); \ do \ - $(SPARSE) -I. $(mpd_CFLAGS) $(SPARSE_FLAGS) $(srcdir)/$$i || exit; \ + $(SPARSE) -I. $(mpd_CFLAGS) $(mpd_CPPFLAGS) $(SPARSE_FLAGS) $(SPARSE_CPPFLAGS) $(srcdir)/$$i || exit; \ done TEST_CFLAGS = -DUNIT_TEST diff --git a/src/client.c b/src/client.c index f654797b7..74b31392a 100644 --- a/src/client.c +++ b/src/client.c @@ -700,10 +700,19 @@ static void client_write_output(struct client *client) if (client_is_expired(client) || !client->send_buf_used) return; - if (!g_queue_is_empty(client->deferred_send)) + if (!g_queue_is_empty(client->deferred_send)) { client_defer_output(client, client->send_buf, client->send_buf_used); - else + + /* try to flush the deferred buffers now; the current + server command may take too long to finish, and + meanwhile try to feed output to the client, + otherwise it will time out. One reason why + deferring is slow might be that currently each + client_write() allocates a new deferred buffer. + This should be optimized after MPD 0.14. */ + client_write_deferred(client); + } else client_write_direct(client, client->send_buf, client->send_buf_used); diff --git a/src/command.c b/src/command.c index c725282aa..9793830c1 100644 --- a/src/command.c +++ b/src/command.c @@ -275,7 +275,8 @@ handle_urlhandlers(struct client *client, { if (client_get_uid(client) > 0) client_puts(client, "handler: file://\n"); - return printRemoteUrlHandlers(client); + printRemoteUrlHandlers(client); + return COMMAND_RETURN_OK; } static enum command_return @@ -449,6 +450,12 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (isRemoteUrl(path)) return addToPlaylist(path, NULL); + if (uri_has_scheme(path)) { + command_error(client, ACK_ERROR_NO_EXIST, + "unsupported URI scheme"); + return COMMAND_RETURN_ERROR; + } + result = addAllIn(path); if (result == (enum playlist_result)-1) { command_error(client, ACK_ERROR_NO_EXIST, @@ -1222,7 +1229,11 @@ handle_playlistadd(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (isRemoteUrl(path)) result = spl_append_uri(path, playlist); - else + else if (uri_has_scheme(path)) { + command_error(client, ACK_ERROR_NO_EXIST, + "unsupported URI scheme"); + return COMMAND_RETURN_ERROR; + } else result = addAllInToStoredPlaylist(path, playlist); if (result == (enum playlist_result)-1) { diff --git a/src/conf.c b/src/conf.c index cdcb917f6..680a5fb1c 100644 --- a/src/conf.c +++ b/src/conf.c @@ -171,8 +171,6 @@ void initConf(void) registerConfigParam(CONF_SAMPLERATE_CONVERTER, 0, 0); registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0); registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0); - registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0); - registerConfigParam(CONF_HTTP_PREBUFFER_SIZE, 0, 0); registerConfigParam(CONF_HTTP_PROXY_HOST, 0, 0); registerConfigParam(CONF_HTTP_PROXY_PORT, 0, 0); registerConfigParam(CONF_HTTP_PROXY_USER, 0, 0); diff --git a/src/conf.h b/src/conf.h index e2e50c5bc..2b73bb6d7 100644 --- a/src/conf.h +++ b/src/conf.h @@ -49,8 +49,6 @@ #define CONF_SAMPLERATE_CONVERTER "samplerate_converter" #define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size" #define CONF_BUFFER_BEFORE_PLAY "buffer_before_play" -#define CONF_HTTP_BUFFER_SIZE "http_buffer_size" -#define CONF_HTTP_PREBUFFER_SIZE "http_prebuffer_size" #define CONF_HTTP_PROXY_HOST "http_proxy_host" #define CONF_HTTP_PROXY_PORT "http_proxy_port" #define CONF_HTTP_PROXY_USER "http_proxy_user" diff --git a/src/decoder/ffmpeg_plugin.c b/src/decoder/ffmpeg_plugin.c index f9e40e2f5..7f7978b9d 100644 --- a/src/decoder/ffmpeg_plugin.c +++ b/src/decoder/ffmpeg_plugin.c @@ -106,7 +106,7 @@ static int64_t mpd_ffmpeg_seek(URLContext *h, int64_t pos, int whence) static int mpd_ffmpeg_close(URLContext *h) { - h->priv_data = 0; + h->priv_data = NULL; return 0; } @@ -208,30 +208,46 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is, AVCodecContext *codec_context, const AVRational *time_base) { + enum decoder_command cmd = DECODE_COMMAND_NONE; int position; uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; int len, audio_size; + uint8_t *packet_data; + int packet_size; - position = av_rescale_q(packet->pts, *time_base, - (AVRational){1, 1}); + packet_data = packet->data; + packet_size = packet->size; - audio_size = sizeof(audio_buf); - len = avcodec_decode_audio2(codec_context, - (int16_t *)audio_buf, - &audio_size, - packet->data, packet->size); + while ((packet_size > 0) && (cmd == DECODE_COMMAND_NONE)) { + audio_size = sizeof(audio_buf); + len = avcodec_decode_audio2(codec_context, + (int16_t *)audio_buf, + &audio_size, + packet_data, packet_size); - if (len < 0) { - g_message("skipping frame\n"); - return decoder_get_command(decoder); - } - assert(audio_size >= 0); + position = av_rescale_q(packet->pts, *time_base, + (AVRational){1, 1}); + + if (len < 0) { + /* if error, we skip the frame */ + g_message("decoding failed\n"); + break; + } - return decoder_data(decoder, is, - audio_buf, audio_size, - position, - codec_context->bit_rate / 1000, NULL); + packet_data += len; + packet_size -= len; + + if (audio_size <= 0) { + g_message("no audio frame\n"); + continue; + } + cmd = decoder_data(decoder, is, + audio_buf, audio_size, + position, + codec_context->bit_rate / 1000, NULL); + } + return cmd; } static bool @@ -263,7 +279,7 @@ ffmpeg_decode_internal(struct ffmpeg_context *ctx) } //there is some problem with this on some demux (mp3 at least) - if (format_context->duration != (int)AV_NOPTS_VALUE) { + if (format_context->duration != (int64_t)AV_NOPTS_VALUE) { total_time = format_context->duration / AV_TIME_BASE; } @@ -314,7 +330,7 @@ static bool ffmpeg_tag_internal(struct ffmpeg_context *ctx) const AVFormatContext *f = ctx->format_context; tag->time = 0; - if (f->duration != (int)AV_NOPTS_VALUE) + if (f->duration != (int64_t)AV_NOPTS_VALUE) tag->time = f->duration / AV_TIME_BASE; if (f->author[0]) tag_add_item(tag, TAG_ITEM_ARTIST, f->author); @@ -368,8 +384,9 @@ static struct tag *ffmpeg_tag(const char *file) */ static const char *const ffmpeg_suffixes[] = { - "wma", "asf", "wmv", "mpeg", "mpg", "avi", "vob", "mov", "qt", "swf", "rm", "swf", - "mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav", "au", "aiff", "aif", "ac3", "aac", "mpc", + "wma", "asf", "wmv", "mpeg", "mpg", "avi", "vob", "mov", "qt", "swf", + "rm", "swf", "mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav", + "au", "aiff", "aif", "ac3", "aac", "mpc", "ape", NULL }; diff --git a/src/decoder/mp3_plugin.c b/src/decoder/mp3_plugin.c index a3643b842..3a908299f 100644 --- a/src/decoder/mp3_plugin.c +++ b/src/decoder/mp3_plugin.c @@ -323,8 +323,8 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize, #endif static enum mp3_action -decode_next_frame_header(struct mp3_data *data, struct tag **tag, - struct replay_gain_info **replay_gain_info_r) +decode_next_frame_header(struct mp3_data *data, G_GNUC_UNUSED struct tag **tag, + G_GNUC_UNUSED struct replay_gain_info **replay_gain_info_r) { enum mad_layer layer; @@ -705,7 +705,7 @@ mp3_decode_first_frame(struct mp3_data *data, struct tag **tag, struct lame lame; struct mad_bitptr ptr; int bitlen; - int ret; + enum mp3_action ret; /* stfu gcc */ memset(&xing, 0, sizeof(struct xing)); @@ -976,7 +976,7 @@ static bool mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r) { struct decoder *decoder = data->decoder; - int ret; + enum mp3_action ret; enum decoder_command cmd; mp3_update_timer_next_frame(data); diff --git a/src/decoder_api.c b/src/decoder_api.c index bf389222b..dd7096017 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -249,6 +249,13 @@ decoder_data(struct decoder *decoder, length = pcm_convert(&dc.in_audio_format, _data, length, &dc.out_audio_format, data, &decoder->conv_state); + + /* under certain circumstances, pcm_convert() may + return an empty buffer - this condition should be + investigated further, but for now, do this check as + a workaround: */ + if (length == 0) + return DECODE_COMMAND_NONE; } if (replay_gain_info != NULL && (replay_gain_mode != REPLAY_GAIN_OFF)) diff --git a/src/listen.c b/src/listen.c index 0e3467364..5a2b8d3da 100644 --- a/src/listen.c +++ b/src/listen.c @@ -112,7 +112,8 @@ static int establishListen(int pf, const struct sockaddr *addrp, return 0; } -static void parseListenConfigParam(unsigned int port, ConfigParam * param) +static void +parseListenConfigParam(G_GNUC_UNUSED unsigned int port, ConfigParam * param) { const struct sockaddr *addrp; socklen_t addrlen; diff --git a/src/locate.c b/src/locate.c index 6b8e87734..2004b132d 100644 --- a/src/locate.c +++ b/src/locate.c @@ -138,7 +138,7 @@ strstrSearchTag(struct song *song, enum tag_type type, char *str) song_get_url(song, path_max_tmp); p = g_utf8_casefold(path_max_tmp, -1); - if (strstr(path_max_tmp, str)) + if (strstr(p, str)) ret = 1; g_free(p); if (ret == 1 || type == LOCATE_TAG_FILE_TYPE) @@ -33,12 +33,12 @@ #include <pthread.h> #include <glib.h> -#define LOG_LEVEL_SECURE G_LOG_LEVEL_MESSAGE +#define LOG_LEVEL_SECURE G_LOG_LEVEL_INFO #define LOG_DATE_BUF_SIZE 16 #define LOG_DATE_LEN (LOG_DATE_BUF_SIZE - 1) -static unsigned int log_threshold = G_LOG_LEVEL_INFO; +static unsigned int log_threshold = G_LOG_LEVEL_MESSAGE; static const char *log_charset; @@ -116,7 +116,7 @@ void initLog(bool verbose) if (!(param = getConfigParam(CONF_LOG_LEVEL))) return; if (0 == strcmp(param->value, "default")) { - log_threshold = G_LOG_LEVEL_INFO; + log_threshold = G_LOG_LEVEL_MESSAGE; } else if (0 == strcmp(param->value, "secure")) { log_threshold = LOG_LEVEL_SECURE; } else if (0 == strcmp(param->value, "verbose")) { @@ -32,7 +32,7 @@ static const char *remoteUrlPrefixes[] = { NULL }; -int printRemoteUrlHandlers(struct client *client) +void printRemoteUrlHandlers(struct client *client) { const char **prefixes = remoteUrlPrefixes; @@ -40,77 +40,32 @@ int printRemoteUrlHandlers(struct client *client) client_printf(client, "handler: %s\n", *prefixes); prefixes++; } - - return 0; } -int isValidRemoteUtf8Url(const char *utf8url) +bool uri_has_scheme(const char *uri) { - int ret = 0; - const char *temp; - - switch (isRemoteUrl(utf8url)) { - case 1: - ret = 1; - temp = utf8url; - while (*temp) { - if ((*temp >= 'a' && *temp <= 'z') || - (*temp >= 'A' && *temp <= 'Z') || - (*temp >= '0' && *temp <= '9') || - *temp == '$' || - *temp == '-' || - *temp == '.' || - *temp == '+' || - *temp == '!' || - *temp == '*' || - *temp == '\'' || - *temp == '(' || - *temp == ')' || - *temp == ',' || - *temp == '%' || - *temp == '/' || - *temp == ':' || - *temp == '?' || - *temp == ';' || *temp == '&' || *temp == '=') { - } else { - ret = 1; - break; - } - temp++; - } - break; - } - - return ret; + return strstr(uri, "://") != NULL; } -int isRemoteUrl(const char *url) +bool isRemoteUrl(const char *url) { - int count = 0; const char **urlPrefixes = remoteUrlPrefixes; while (*urlPrefixes) { - count++; if (g_str_has_prefix(url, *urlPrefixes)) - return count; + return true; urlPrefixes++; } - return 0; + return false; } /* suffixes should be ascii only characters */ const char *getSuffix(const char *utf8file) { - const char *ret = NULL; - - while (*utf8file) { - if (*utf8file == '.') - ret = utf8file + 1; - utf8file++; - } + const char *dot = strrchr(g_basename(utf8file), '.'); - return ret; + return dot != NULL ? dot + 1 : NULL; } const struct decoder_plugin * @@ -22,16 +22,20 @@ #include "decoder_list.h" #include "archive_list.h" -#include <sys/time.h> +#include <stdbool.h> struct stat; struct client; const char *getSuffix(const char *utf8file); -int isValidRemoteUtf8Url(const char *utf8url); +/** + * Checks whether the specified URI has a schema in the form + * "scheme://". + */ +bool uri_has_scheme(const char *uri); -int isRemoteUrl(const char *url); +bool isRemoteUrl(const char *url); const struct decoder_plugin * hasMusicSuffix(const char *utf8file, unsigned int next); @@ -39,6 +43,6 @@ hasMusicSuffix(const char *utf8file, unsigned int next); const struct archive_plugin * get_archive_by_suffix(const char *utf8file); -int printRemoteUrlHandlers(struct client *client); +void printRemoteUrlHandlers(struct client *client); #endif diff --git a/src/mapper.c b/src/mapper.c index 6317c2f77..b3f86da00 100644 --- a/src/mapper.c +++ b/src/mapper.c @@ -84,13 +84,23 @@ rmp2amp_r(char *dst, const char *rel_path) } const char * +map_uri_fs(const char *uri, char *buffer) +{ + assert(uri != NULL); + assert(*uri != '/'); + assert(buffer != NULL); + + return rmp2amp_r(buffer, utf8_to_fs_charset(buffer, uri)); +} + +const char * map_directory_fs(const struct directory *directory, char *buffer) { const char *dirname = directory_get_path(directory); if (isRootDirectory(dirname)) return music_dir; - return rmp2amp_r(buffer, utf8_to_fs_charset(buffer, dirname)); + return map_uri_fs(dirname, buffer); } const char * diff --git a/src/mapper.h b/src/mapper.h index e8249b27d..2aecd9a52 100644 --- a/src/mapper.h +++ b/src/mapper.h @@ -33,6 +33,14 @@ void mapper_init(void); void mapper_finish(void); /** + * Determines the absolute file system path of a relative URI. This + * is basically done by converting the URI to the file system charset + * and prepending the music directory. + */ +const char * +map_uri_fs(const char *uri, char *buffer); + +/** * Determines the file system path of a directory object. * * @param directory the directory object diff --git a/src/output/ao_plugin.c b/src/output/ao_plugin.c index 3907448ae..4c69592ff 100644 --- a/src/output/ao_plugin.c +++ b/src/output/ao_plugin.c @@ -201,6 +201,12 @@ audioOutputAo_openDevice(void *data, struct audio_format *audio_format) audioOutputAo_closeDevice(ad); } + /* support for 24 bit samples in libao is currently dubious, + and until we have sorted that out, resample everything to + 16 bit */ + if (audio_format->bits > 16) + audio_format->bits = 16; + format.bits = audio_format->bits; format.rate = audio_format->sample_rate; format.byte_format = AO_FMT_NATIVE; diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c index b368ed8a1..3a7c009ed 100644 --- a/src/output/osx_plugin.c +++ b/src/output/osx_plugin.c @@ -18,10 +18,14 @@ #include "../output_api.h" #include "../utils.h" -#include "../log.h" +#include <glib.h> +#include <pthread.h> #include <AudioUnit/AudioUnit.h> +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "osx" + typedef struct _OsxData { AudioUnit au; pthread_mutex_t mutex; @@ -35,7 +39,7 @@ typedef struct _OsxData { static OsxData *newOsxData(void) { - OsxData *ret = xmalloc(sizeof(OsxData)); + OsxData *ret = g_new(OsxData, 1); pthread_mutex_init(&ret->mutex, NULL); pthread_cond_init(&ret->condition, NULL); @@ -124,8 +128,8 @@ static void osx_closeDevice(void *data) od->started = 0; } - CloseComponent(od->au); AudioUnitUninitialize(od->au); + CloseComponent(od->au); } static OSStatus @@ -139,6 +143,7 @@ osx_render(void *vdata, AudioBuffer *buffer = &bufferList->mBuffers[0]; size_t bufferSize = buffer->mDataByteSize; size_t bytesToCopy; + size_t bytes; int curpos = 0; /*DEBUG("osx_render: enter : %i\n", (int)bufferList->mNumberBuffers); @@ -177,21 +182,20 @@ osx_render(void *vdata, } */ - bytesToCopy = od->len < bufferSize ? od->len : bufferSize; + bytesToCopy = MIN(od->len, bufferSize); bufferSize = bytesToCopy; od->len -= bytesToCopy; - if (od->pos + bytesToCopy > od->bufferSize) { - size_t bytes = od->bufferSize - od->pos; - memcpy(buffer->mData + curpos, od->buffer + od->pos, bytes); + bytes = od->bufferSize - od->pos; + if (bytesToCopy > bytes) { + memcpy((unsigned char*)buffer->mData + curpos, od->buffer + od->pos, bytes); od->pos = 0; curpos += bytes; bytesToCopy -= bytes; } - memcpy(buffer->mData + curpos, od->buffer + od->pos, bytesToCopy); + memcpy((unsigned char*)buffer->mData + curpos, od->buffer + od->pos, bytesToCopy); od->pos += bytesToCopy; - curpos += bytesToCopy; if (od->pos >= od->bufferSize) od->pos = 0; @@ -219,6 +223,9 @@ osx_openDevice(void *data, struct audio_format *audioFormat) AURenderCallbackStruct callback; AudioStreamBasicDescription streamDesc; + if (audioFormat->bits > 16) + audioFormat->bits = 16; + desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; @@ -227,18 +234,18 @@ osx_openDevice(void *data, struct audio_format *audioFormat) comp = FindNextComponent(NULL, &desc); if (comp == 0) { - ERROR("Error finding OS X component\n"); + g_warning("Error finding OS X component\n"); return false; } if (OpenAComponent(comp, &od->au) != noErr) { - ERROR("Unable to open OS X component\n"); + g_warning("Unable to open OS X component\n"); return false; } if (AudioUnitInitialize(od->au) != 0) { CloseComponent(od->au); - ERROR("Unable to initialize OS X audio unit\n"); + g_warning("Unable to initialize OS X audio unit\n"); return false; } @@ -250,7 +257,7 @@ osx_openDevice(void *data, struct audio_format *audioFormat) &callback, sizeof(callback)) != 0) { AudioUnitUninitialize(od->au); CloseComponent(od->au); - ERROR("unable to set callback for OS X audio unit\n"); + g_warning("unable to set callback for OS X audio unit\n"); return false; } @@ -272,14 +279,14 @@ osx_openDevice(void *data, struct audio_format *audioFormat) &streamDesc, sizeof(streamDesc)) != 0) { AudioUnitUninitialize(od->au); CloseComponent(od->au); - ERROR("Unable to set format on OS X device\n"); + g_warning("Unable to set format on OS X device\n"); return false; } /* create a buffer of 1s */ od->bufferSize = (audioFormat->sample_rate) * audio_format_frame_size(audioFormat); - od->buffer = xrealloc(od->buffer, od->bufferSize); + od->buffer = g_realloc(od->buffer, od->bufferSize); od->pos = 0; od->len = 0; @@ -292,6 +299,7 @@ osx_play(void *data, const char *playChunk, size_t size) { OsxData *od = data; size_t bytesToCopy; + size_t bytes; size_t curpos; /* DEBUG("osx_play: enter\n"); */ @@ -301,7 +309,7 @@ osx_play(void *data, const char *playChunk, size_t size) od->started = 1; err = AudioOutputUnitStart(od->au); if (err) { - ERROR("unable to start audio output: %i\n", err); + g_warning("unable to start audio output: %i\n", err); return false; } } @@ -314,20 +322,18 @@ osx_play(void *data, const char *playChunk, size_t size) if (curpos >= od->bufferSize) curpos -= od->bufferSize; - bytesToCopy = od->bufferSize < size ? od->bufferSize : size; + bytesToCopy = MIN(od->bufferSize, size); while (od->len > od->bufferSize - bytesToCopy) { /* DEBUG("osx_play: wait\n"); */ pthread_cond_wait(&od->condition, &od->mutex); } - bytesToCopy = od->bufferSize - od->len; - bytesToCopy = bytesToCopy < size ? bytesToCopy : size; size -= bytesToCopy; od->len += bytesToCopy; - if (curpos + bytesToCopy > od->bufferSize) { - size_t bytes = od->bufferSize - curpos; + bytes = od->bufferSize - curpos; + if (bytesToCopy > bytes) { memcpy(od->buffer + curpos, playChunk, bytes); curpos = 0; playChunk += bytes; @@ -335,7 +341,6 @@ osx_play(void *data, const char *playChunk, size_t size) } memcpy(od->buffer + curpos, playChunk, bytesToCopy); - curpos += bytesToCopy; playChunk += bytesToCopy; } diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c index 7fdf4c1e0..9edaf63af 100644 --- a/src/output/shout_plugin.c +++ b/src/output/shout_plugin.c @@ -203,9 +203,9 @@ static void *my_shout_init_driver(struct audio_output *audio_output, } sd->encoder = shout_encoder_plugin_get(encoding); - if (sd->encoder == NULL) { - g_error("couldn't find shout encoder plugin for \"%s\"\n", encoding); - } + if (sd->encoder == NULL) + g_error("couldn't find shout encoder plugin \"%s\"\n", + encoding); block_param = getBlockParam(param, "protocol"); if (block_param) { diff --git a/src/output_thread.c b/src/output_thread.c index b65a601a3..c887828bb 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -69,9 +69,17 @@ static void ao_play(struct audio_output *ao) assert(size > 0); - if (!audio_format_equals(&ao->inAudioFormat, &ao->outAudioFormat)) + if (!audio_format_equals(&ao->inAudioFormat, &ao->outAudioFormat)) { convertAudioFormat(ao, &data, &size); + /* under certain circumstances, pcm_convert() may + return an empty buffer - this condition should be + investigated further, but for now, do this check as + a workaround: */ + if (size == 0) + return; + } + ret = ao->plugin->play(ao->data, data, size); if (!ret) { ao->plugin->cancel(ao->data); diff --git a/src/pcm_utils.c b/src/pcm_utils.c index 4759c20ac..f73df8aef 100644 --- a/src/pcm_utils.c +++ b/src/pcm_utils.c @@ -379,8 +379,6 @@ pcm_convert_16(const struct audio_format *src_format, dest_format->sample_rate, dest_buffer, dest_size, &state->resample); - if (len == 0) - exit(EXIT_FAILURE); } return len; @@ -421,8 +419,6 @@ pcm_convert_24(const struct audio_format *src_format, dest_format->sample_rate, (int32_t*)dest_buffer, dest_size, &state->resample); - if (len == 0) - exit(EXIT_FAILURE); } return len; @@ -461,7 +457,7 @@ size_t pcm_convert_size(const struct audio_format *inFormat, size_t src_size, assert((src_size % audio_format_frame_size(inFormat)) == 0); dest_size /= audio_format_frame_size(inFormat); - dest_size = floor(0.5 + (double)dest_size * ratio); + dest_size = ceil((double)dest_size * ratio); dest_size *= audio_format_frame_size(outFormat); return dest_size; diff --git a/src/player_control.c b/src/player_control.c index 1d5c76aa0..b8e9499f6 100644 --- a/src/player_control.c +++ b/src/player_control.c @@ -44,6 +44,13 @@ void pc_deinit(void) notify_deinit(&pc.notify); } +void +pc_song_deleted(const struct song *song) +{ + if (pc.errored_song == song) + pc.errored_song = NULL; +} + static void player_command(enum player_command cmd) { pc.command = cmd; @@ -141,12 +148,22 @@ enum player_error getPlayerError(void) return pc.error; } +static const char * +pc_errored_song_uri(void) +{ + char path_max_tmp[MPD_PATH_MAX]; + + if (pc.errored_song == NULL) + return "?"; + + return song_get_url(pc.errored_song, path_max_tmp); +} + char *getPlayerErrorStr(void) { /* static OK here, only one user in main task */ static char error[MPD_PATH_MAX + 64]; /* still too much */ static const size_t errorlen = sizeof(error); - char path_max_tmp[MPD_PATH_MAX]; *error = '\0'; /* likely */ switch (pc.error) { @@ -156,11 +173,11 @@ char *getPlayerErrorStr(void) case PLAYER_ERROR_FILENOTFOUND: snprintf(error, errorlen, "file \"%s\" does not exist or is inaccessible", - song_get_url(pc.errored_song, path_max_tmp)); + pc_errored_song_uri()); break; case PLAYER_ERROR_FILE: snprintf(error, errorlen, "problems decoding \"%s\"", - song_get_url(pc.errored_song, path_max_tmp)); + pc_errored_song_uri()); break; case PLAYER_ERROR_AUDIO: strcpy(error, "problems opening audio device"); @@ -170,7 +187,7 @@ char *getPlayerErrorStr(void) break; case PLAYER_ERROR_UNKTYPE: snprintf(error, errorlen, "file type of \"%s\" is unknown", - song_get_url(pc.errored_song, path_max_tmp)); + pc_errored_song_uri()); } return *error ? error : NULL; } diff --git a/src/player_control.h b/src/player_control.h index 2ae1fb618..fa228d8b3 100644 --- a/src/player_control.h +++ b/src/player_control.h @@ -84,6 +84,14 @@ void pc_init(unsigned int buffered_before_play); void pc_deinit(void); +/** + * Call this function when the specified song pointer is about to be + * invalidated. This makes sure that player_control.errored_song does + * not point to an invalid pointer. + */ +void +pc_song_deleted(const struct song *song); + void playerPlay(struct song *song); diff --git a/src/playlist.c b/src/playlist.c index 8581755ca..ba69844de 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -200,8 +200,10 @@ void clearPlaylist(void) stopPlaylist(); for (unsigned i = 0; i < playlist.length; i++) { - if (!song_in_database(playlist.songs[i])) + if (!song_in_database(playlist.songs[i])) { + pc_song_deleted(playlist.songs[i]); song_free(playlist.songs[i]); + } playlist.idToPosition[playlist.positionToId[i]] = -1; playlist.songs[i] = NULL; @@ -537,7 +539,7 @@ song_by_url(const char *url) if (song != NULL) return song; - if (isValidRemoteUtf8Url(url)) + if (isRemoteUrl(url)) return song_remote_new(url); return NULL; @@ -670,8 +672,10 @@ enum playlist_result deleteFromPlaylist(unsigned song) || playlist.order[playlist.current] == song)) clearPlayerQueue(); - if (!song_in_database(playlist.songs[song])) + if (!song_in_database(playlist.songs[song])) { + pc_song_deleted(playlist.songs[song]); song_free(playlist.songs[song]); + } playlist.idToPosition[playlist.positionToId[song]] = -1; @@ -738,6 +742,8 @@ deleteASongFromPlaylist(const struct song *song) for (unsigned i = 0; i < playlist.length; i++) if (song == playlist.songs[i]) deleteFromPlaylist(i); + + pc_song_deleted(song); } void stopPlaylist(void) diff --git a/src/playlist_save.c b/src/playlist_save.c index 4ae965154..b07137d9e 100644 --- a/src/playlist_save.c +++ b/src/playlist_save.c @@ -46,9 +46,9 @@ playlist_print_uri(FILE *file, const char *uri) char tmp[MPD_PATH_MAX]; const char *s; - if (playlist_saveAbsolutePaths && !isValidRemoteUtf8Url(uri) && + if (playlist_saveAbsolutePaths && !isRemoteUrl(uri) && uri[0] != '/') - s = map_directory_child_fs(db_get_root(), uri, tmp); + s = map_uri_fs(uri, tmp); else s = utf8_to_fs_charset(tmp, uri); diff --git a/src/stored_playlist.c b/src/stored_playlist.c index cadd2ccdf..78977bf69 100644 --- a/src/stored_playlist.c +++ b/src/stored_playlist.c @@ -156,7 +156,7 @@ spl_load(const char *utf8path) if (*s == PLAYLIST_COMMENT) continue; - if (!isValidRemoteUtf8Url(s)) { + if (!isRemoteUrl(s)) { struct song *song; path_utf8 = map_fs_to_utf8(s, path_max_tmp); @@ -338,7 +338,7 @@ spl_append_song(const char *utf8path, struct song *song) return PLAYLIST_RESULT_ERRNO; } - if (st.st_size >= ((MPD_PATH_MAX+1) * (off_t)playlist_max_length)) { + if (st.st_size / (MPD_PATH_MAX + 1) >= (off_t)playlist_max_length) { while (fclose(file) != 0 && errno == EINTR); return PLAYLIST_RESULT_TOO_LARGE; } @@ -360,7 +360,7 @@ spl_append_uri(const char *url, const char *utf8file) if (song) return spl_append_song(utf8file, song); - if (!isValidRemoteUtf8Url(url)) + if (!isRemoteUrl(url)) return PLAYLIST_RESULT_NO_SUCH_SONG; song = song_remote_new(url); diff --git a/src/stored_playlist.h b/src/stored_playlist.h index 1ac5c33af..26dd163a1 100644 --- a/src/stored_playlist.h +++ b/src/stored_playlist.h @@ -22,6 +22,7 @@ #include "playlist.h" #include <glib.h> +#include <time.h> struct song; diff --git a/src/update.c b/src/update.c index 5d85ffff4..c7ad71c7b 100644 --- a/src/update.c +++ b/src/update.c @@ -59,7 +59,7 @@ static struct condition delete_cond; enum { DEFAULT_FOLLOW_INSIDE_SYMLINKS = true, - DEFAULT_FOLLOW_OUTSIDE_SYMLINKS = false, + DEFAULT_FOLLOW_OUTSIDE_SYMLINKS = true, }; static bool follow_inside_symlinks; |