aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/client.c13
-rw-r--r--src/command.c15
-rw-r--r--src/conf.c2
-rw-r--r--src/conf.h2
-rw-r--r--src/decoder/ffmpeg_plugin.c59
-rw-r--r--src/decoder/mp3_plugin.c8
-rw-r--r--src/decoder_api.c7
-rw-r--r--src/listen.c3
-rw-r--r--src/locate.c2
-rw-r--r--src/log.c6
-rw-r--r--src/ls.c61
-rw-r--r--src/ls.h12
-rw-r--r--src/mapper.c12
-rw-r--r--src/mapper.h8
-rw-r--r--src/output/ao_plugin.c6
-rw-r--r--src/output/osx_plugin.c49
-rw-r--r--src/output/shout_plugin.c6
-rw-r--r--src/output_thread.c10
-rw-r--r--src/pcm_utils.c6
-rw-r--r--src/player_control.c25
-rw-r--r--src/player_control.h8
-rw-r--r--src/playlist.c12
-rw-r--r--src/playlist_save.c4
-rw-r--r--src/stored_playlist.c6
-rw-r--r--src/stored_playlist.h1
-rw-r--r--src/update.c2
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)
diff --git a/src/log.c b/src/log.c
index e09aaf32a..1510b29e9 100644
--- a/src/log.c
+++ b/src/log.c
@@ -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")) {
diff --git a/src/ls.c b/src/ls.c
index b5cb5cfeb..f0f403f44 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -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 *
diff --git a/src/ls.h b/src/ls.h
index 92839e018..713b6ac20 100644
--- a/src/ls.h
+++ b/src/ls.h
@@ -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;