diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/directory.c | 10 | ||||
-rw-r--r-- | src/encoder/flac_encoder.c | 1 | ||||
-rw-r--r-- | src/encoder/twolame_encoder.c | 1 | ||||
-rw-r--r-- | src/encoder/vorbis_encoder.c | 3 | ||||
-rw-r--r-- | src/encoder_plugin.h | 98 | ||||
-rw-r--r-- | src/output/jack_output_plugin.c | 16 | ||||
-rw-r--r-- | src/output/osx_output_plugin.c | 94 | ||||
-rw-r--r-- | src/output/recorder_output_plugin.c | 2 | ||||
-rw-r--r-- | src/output/shout_output_plugin.c | 2 | ||||
-rw-r--r-- | src/update_remove.c | 2 | ||||
-rw-r--r-- | src/update_walk.c | 6 | ||||
-rw-r--r-- | src/uri.c | 4 |
12 files changed, 171 insertions, 68 deletions
diff --git a/src/directory.c b/src/directory.c index 662b8907f..930881129 100644 --- a/src/directory.c +++ b/src/directory.c @@ -86,7 +86,15 @@ directory_delete(struct directory *directory) const char * directory_get_name(const struct directory *directory) { - return g_basename(directory->path); + assert(!directory_is_root(directory)); + assert(directory->path != NULL); + + const char *slash = strrchr(directory->path, '/'); + assert((slash == NULL) == directory_is_root(directory->parent)); + + return slash != NULL + ? slash + 1 + : directory->path; } struct directory * diff --git a/src/encoder/flac_encoder.c b/src/encoder/flac_encoder.c index 9f60bdae5..e32588e29 100644 --- a/src/encoder/flac_encoder.c +++ b/src/encoder/flac_encoder.c @@ -354,6 +354,7 @@ const struct encoder_plugin flac_encoder_plugin = { .finish = flac_encoder_finish, .open = flac_encoder_open, .close = flac_encoder_close, + .end = flac_encoder_flush, .flush = flac_encoder_flush, .write = flac_encoder_write, .read = flac_encoder_read, diff --git a/src/encoder/twolame_encoder.c b/src/encoder/twolame_encoder.c index 00ebcc0d7..934b2ab24 100644 --- a/src/encoder/twolame_encoder.c +++ b/src/encoder/twolame_encoder.c @@ -300,6 +300,7 @@ const struct encoder_plugin twolame_encoder_plugin = { .finish = twolame_encoder_finish, .open = twolame_encoder_open, .close = twolame_encoder_close, + .end = twolame_encoder_flush, .flush = twolame_encoder_flush, .write = twolame_encoder_write, .read = twolame_encoder_read, diff --git a/src/encoder/vorbis_encoder.c b/src/encoder/vorbis_encoder.c index 3e9d486b6..fcf2b5135 100644 --- a/src/encoder/vorbis_encoder.c +++ b/src/encoder/vorbis_encoder.c @@ -285,8 +285,6 @@ vorbis_encoder_pre_tag(struct encoder *_encoder, G_GNUC_UNUSED GError **error) vorbis_analysis_init(&encoder->vd, &encoder->vi); vorbis_block_init(&encoder->vd, &encoder->vb); - ogg_stream_reset(&encoder->os); - encoder->flush = true; return true; } @@ -407,6 +405,7 @@ const struct encoder_plugin vorbis_encoder_plugin = { .finish = vorbis_encoder_finish, .open = vorbis_encoder_open, .close = vorbis_encoder_close, + .end = vorbis_encoder_pre_tag, .flush = vorbis_encoder_flush, .pre_tag = vorbis_encoder_pre_tag, .tag = vorbis_encoder_tag, diff --git a/src/encoder_plugin.h b/src/encoder_plugin.h index 95b3da016..33a379115 100644 --- a/src/encoder_plugin.h +++ b/src/encoder_plugin.h @@ -22,6 +22,7 @@ #include <glib.h> +#include <assert.h> #include <stdbool.h> #include <stddef.h> @@ -32,6 +33,10 @@ struct tag; struct encoder { const struct encoder_plugin *plugin; + +#ifndef NDEBUG + bool open, pre_tag, tag, end; +#endif }; struct encoder_plugin { @@ -48,6 +53,8 @@ struct encoder_plugin { void (*close)(struct encoder *encoder); + bool (*end)(struct encoder *encoder, GError **error); + bool (*flush)(struct encoder *encoder, GError **error); bool (*pre_tag)(struct encoder *encoder, GError **error); @@ -73,6 +80,10 @@ encoder_struct_init(struct encoder *encoder, const struct encoder_plugin *plugin) { encoder->plugin = plugin; + +#ifndef NDEBUG + encoder->open = false; +#endif } /** @@ -98,6 +109,8 @@ encoder_init(const struct encoder_plugin *plugin, static inline void encoder_finish(struct encoder *encoder) { + assert(!encoder->open); + encoder->plugin->finish(encoder); } @@ -116,7 +129,14 @@ static inline bool encoder_open(struct encoder *encoder, struct audio_format *audio_format, GError **error) { - return encoder->plugin->open(encoder, audio_format, error); + assert(!encoder->open); + + bool success = encoder->plugin->open(encoder, audio_format, error); +#ifndef NDEBUG + encoder->open = success; + encoder->pre_tag = encoder->tag = encoder->end = false; +#endif + return success; } /** @@ -128,8 +148,43 @@ encoder_open(struct encoder *encoder, struct audio_format *audio_format, static inline void encoder_close(struct encoder *encoder) { + assert(encoder->open); + if (encoder->plugin->close != NULL) encoder->plugin->close(encoder); + +#ifndef NDEBUG + encoder->open = false; +#endif +} + +/** + * Ends the stream: flushes the encoder object, generate an + * end-of-stream marker (if applicable), make everything which might + * currently be buffered available by encoder_read(). + * + * After this function has been called, the encoder may not be usable + * for more data, and only encoder_read() and encoder_close() can be + * called. + * + * @param encoder the encoder + * @param error location to store the error occuring, or NULL to ignore errors. + * @return true on success + */ +static inline bool +encoder_end(struct encoder *encoder, GError **error) +{ + assert(encoder->open); + assert(!encoder->end); + +#ifndef NDEBUG + encoder->end = true; +#endif + + /* this method is optional */ + return encoder->plugin->end != NULL + ? encoder->plugin->end(encoder, error) + : true; } /** @@ -143,6 +198,11 @@ encoder_close(struct encoder *encoder) static inline bool encoder_flush(struct encoder *encoder, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(!encoder->tag); + assert(!encoder->end); + /* this method is optional */ return encoder->plugin->flush != NULL ? encoder->plugin->flush(encoder, error) @@ -162,10 +222,20 @@ encoder_flush(struct encoder *encoder, GError **error) static inline bool encoder_pre_tag(struct encoder *encoder, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(!encoder->tag); + assert(!encoder->end); + /* this method is optional */ - return encoder->plugin->pre_tag != NULL + bool success = encoder->plugin->pre_tag != NULL ? encoder->plugin->pre_tag(encoder, error) : true; + +#ifndef NDEBUG + encoder->pre_tag = success; +#endif + return success; } /** @@ -182,6 +252,15 @@ encoder_pre_tag(struct encoder *encoder, GError **error) static inline bool encoder_tag(struct encoder *encoder, const struct tag *tag, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(encoder->tag); + assert(!encoder->end); + +#ifndef NDEBUG + encoder->tag = false; +#endif + /* this method is optional */ return encoder->plugin->tag != NULL ? encoder->plugin->tag(encoder, tag, error) @@ -201,6 +280,11 @@ static inline bool encoder_write(struct encoder *encoder, const void *data, size_t length, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(!encoder->tag); + assert(!encoder->end); + return encoder->plugin->write(encoder, data, length, error); } @@ -215,6 +299,16 @@ encoder_write(struct encoder *encoder, const void *data, size_t length, static inline size_t encoder_read(struct encoder *encoder, void *dest, size_t length) { + assert(encoder->open); + assert(!encoder->pre_tag || !encoder->tag); + +#ifndef NDEBUG + if (encoder->pre_tag) { + encoder->pre_tag = false; + encoder->tag = true; + } +#endif + return encoder->plugin->read(encoder, dest, length); } diff --git a/src/output/jack_output_plugin.c b/src/output/jack_output_plugin.c index cd769088b..a24cb8557 100644 --- a/src/output/jack_output_plugin.c +++ b/src/output/jack_output_plugin.c @@ -146,6 +146,13 @@ mpd_jack_process(jack_nframes_t nframes, void *arg) for (unsigned i = 0; i < jd->audio_format.channels; ++i) { out = jack_port_get_buffer(jd->ports[i], nframes); + if (out == NULL) + /* workaround for libjack1 bug: if the server + connection fails, the process callback is + invoked anyway, but unable to get a + buffer */ + continue; + jack_ringbuffer_read(jd->ringbuffer[i], (char *)out, available * jack_sample_size); @@ -159,6 +166,12 @@ mpd_jack_process(jack_nframes_t nframes, void *arg) for (unsigned i = jd->audio_format.channels; i < jd->num_source_ports; ++i) { out = jack_port_get_buffer(jd->ports[i], nframes); + if (out == NULL) + /* workaround for libjack1 bug: if the server + connection fails, the process callback is + invoked anyway, but unable to get a + buffer */ + continue; for (jack_nframes_t f = 0; f < nframes; ++f) out[f] = 0.0; @@ -572,6 +585,9 @@ mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format, jd->pause = false; + if (jd->client != NULL && jd->shutdown) + mpd_jack_disconnect(jd); + if (jd->client == NULL && !mpd_jack_connect(jd, error_r)) return false; diff --git a/src/output/osx_output_plugin.c b/src/output/osx_output_plugin.c index 3f1af821b..fbba81749 100644 --- a/src/output/osx_output_plugin.c +++ b/src/output/osx_output_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * Copyright (C) 2003-2012 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "config.h" #include "osx_output_plugin.h" #include "output_api.h" +#include "fifo_buffer.h" #include <glib.h> #include <CoreAudio/AudioHardware.h> @@ -40,10 +41,8 @@ struct osx_output { AudioUnit au; GMutex *mutex; GCond *condition; - char *buffer; - size_t buffer_size; - size_t pos; - size_t len; + + struct fifo_buffer *buffer; }; /** @@ -96,11 +95,6 @@ osx_output_init(const struct config_param *param, GError **error_r) oo->mutex = g_mutex_new(); oo->condition = g_cond_new(); - oo->pos = 0; - oo->len = 0; - oo->buffer = NULL; - oo->buffer_size = 0; - return &oo->base; } @@ -109,7 +103,6 @@ osx_output_finish(struct audio_output *ao) { struct osx_output *od = (struct osx_output *)ao; - g_free(od->buffer); g_mutex_free(od->mutex); g_cond_free(od->condition); g_free(od); @@ -215,37 +208,29 @@ osx_render(void *vdata, struct osx_output *od = (struct osx_output *) vdata; AudioBuffer *buffer = &buffer_list->mBuffers[0]; size_t buffer_size = buffer->mDataByteSize; - size_t bytes_to_copy; - size_t trailer_length; - size_t dest_pos = 0; - g_mutex_lock(od->mutex); + assert(od->buffer != NULL); - bytes_to_copy = MIN(od->len, buffer_size); - od->len -= bytes_to_copy; + g_mutex_lock(od->mutex); - trailer_length = od->buffer_size - od->pos; - if (bytes_to_copy > trailer_length) { - memcpy((unsigned char*)buffer->mData + dest_pos, - od->buffer + od->pos, trailer_length); - od->pos = 0; - dest_pos += trailer_length; - bytes_to_copy -= trailer_length; - } + size_t nbytes; + const void *src = fifo_buffer_read(od->buffer, &nbytes); - memcpy((unsigned char*)buffer->mData + dest_pos, - od->buffer + od->pos, bytes_to_copy); - od->pos += bytes_to_copy; + if (src != NULL) { + if (nbytes > buffer_size) + nbytes = buffer_size; - if (od->pos >= od->buffer_size) - od->pos = 0; + memcpy(buffer->mData, src, nbytes); + fifo_buffer_consume(od->buffer, nbytes); + } else + nbytes = 0; g_cond_signal(od->condition); g_mutex_unlock(od->mutex); - if (bytes_to_copy < buffer_size) - memset((unsigned char*)buffer->mData + bytes_to_copy, 0, - buffer_size - bytes_to_copy); + if (nbytes < buffer_size) + memset((unsigned char*)buffer->mData + nbytes, 0, + buffer_size - nbytes); return 0; } @@ -315,7 +300,7 @@ osx_output_cancel(struct audio_output *ao) struct osx_output *od = (struct osx_output *)ao; g_mutex_lock(od->mutex); - od->len = 0; + fifo_buffer_clear(od->buffer); g_mutex_unlock(od->mutex); } @@ -326,6 +311,8 @@ osx_output_close(struct audio_output *ao) AudioOutputUnitStop(od->au); AudioUnitUninitialize(od->au); + + fifo_buffer_free(od->buffer); } static bool @@ -387,12 +374,8 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr } /* create a buffer of 1s */ - od->buffer_size = (audio_format->sample_rate) * - audio_format_frame_size(audio_format); - od->buffer = g_realloc(od->buffer, od->buffer_size); - - od->pos = 0; - od->len = 0; + od->buffer = fifo_buffer_new(audio_format->sample_rate * + audio_format_frame_size(audio_format)); status = AudioOutputUnitStart(od->au); if (status != 0) { @@ -411,33 +394,30 @@ osx_output_play(struct audio_output *ao, const void *chunk, size_t size, G_GNUC_UNUSED GError **error) { struct osx_output *od = (struct osx_output *)ao; - size_t start, nbytes; g_mutex_lock(od->mutex); - while (od->len >= od->buffer_size) - /* wait for some free space in the buffer */ - g_cond_wait(od->condition, od->mutex); + void *dest; + size_t max_length; - start = od->pos + od->len; - if (start >= od->buffer_size) - start -= od->buffer_size; - - nbytes = start < od->pos - ? od->pos - start - : od->buffer_size - start; + while (true) { + dest = fifo_buffer_write(od->buffer, &max_length); + if (dest != NULL) + break; - assert(nbytes > 0); + /* wait for some free space in the buffer */ + g_cond_wait(od->condition, od->mutex); + } - if (nbytes > size) - nbytes = size; + if (size > max_length) + size = max_length; - memcpy(od->buffer + start, chunk, nbytes); - od->len += nbytes; + memcpy(dest, chunk, size); + fifo_buffer_append(od->buffer, size); g_mutex_unlock(od->mutex); - return nbytes; + return size; } const struct audio_output_plugin osx_output_plugin = { diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c index 00adc5d19..ea299468b 100644 --- a/src/output/recorder_output_plugin.c +++ b/src/output/recorder_output_plugin.c @@ -202,7 +202,7 @@ recorder_output_close(struct audio_output *ao) /* flush the encoder and write the rest to the file */ - if (encoder_flush(recorder->encoder, NULL)) + if (encoder_end(recorder->encoder, NULL)) recorder_output_encoder_to_file(recorder, NULL); /* now really close everything */ diff --git a/src/output/shout_output_plugin.c b/src/output/shout_output_plugin.c index 35356d659..7867ae63c 100644 --- a/src/output/shout_output_plugin.c +++ b/src/output/shout_output_plugin.c @@ -376,7 +376,7 @@ static void close_shout_conn(struct shout_data * sd) sd->buf.len = 0; if (sd->encoder != NULL) { - if (encoder_flush(sd->encoder, NULL)) + if (encoder_end(sd->encoder, NULL)) write_page(sd, NULL); encoder_close(sd->encoder); diff --git a/src/update_remove.c b/src/update_remove.c index ef697e44e..f443f5eb2 100644 --- a/src/update_remove.c +++ b/src/update_remove.c @@ -50,7 +50,7 @@ song_remove_event(void) assert(removed_song != NULL); uri = song_get_uri(removed_song); - g_debug("removing: %s", uri); + g_message("removing %s", uri); g_free(uri); #ifdef ENABLE_SQLITE diff --git a/src/update_walk.c b/src/update_walk.c index 003807da6..9ca9115bd 100644 --- a/src/update_walk.c +++ b/src/update_walk.c @@ -676,6 +676,9 @@ directory_make_child_checked(struct directory *parent, const char *name_utf8) inodeFoundInParent(parent, st.st_ino, st.st_dev)) return NULL; + if (skip_symlink(parent, name_utf8)) + return NULL; + /* if we're adding directory paths, make sure to delete filenames with potentially the same name */ db_lock(); @@ -728,7 +731,8 @@ updatePath(const char *path) name = g_path_get_basename(path); - if (stat_directory_child(parent, name, &st) == 0) + if (!skip_symlink(parent, name) && + stat_directory_child(parent, name, &st) == 0) updateInDirectory(parent, name, &st); else modified |= delete_name_in(parent, name); @@ -34,13 +34,13 @@ bool uri_has_scheme(const char *uri) const char * uri_get_suffix(const char *uri) { - const char *suffix = strrchr(g_basename(uri), '.'); + const char *suffix = strrchr(uri, '.'); if (suffix == NULL) return NULL; ++suffix; - if (strchr(suffix, '/') != NULL) + if (strpbrk(suffix, "/\\") != NULL) return NULL; return suffix; |