diff options
Diffstat (limited to '')
-rw-r--r-- | src/decoder/ffmpeg_decoder_plugin.c | 4 | ||||
-rw-r--r-- | src/decoder/mp4ff_decoder_plugin.c | 8 | ||||
-rw-r--r-- | src/decoder_control.c | 2 | ||||
-rw-r--r-- | src/input/rewind_input_plugin.c | 6 | ||||
-rw-r--r-- | src/output_all.c | 4 | ||||
-rw-r--r-- | src/output_control.c | 37 | ||||
-rw-r--r-- | src/output_internal.h | 3 | ||||
-rw-r--r-- | src/output_thread.c | 15 | ||||
-rw-r--r-- | src/pipe.h | 6 | ||||
-rw-r--r-- | src/player_thread.c | 60 |
10 files changed, 100 insertions, 45 deletions
diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c index ea5b97d08..f9d4eb8a9 100644 --- a/src/decoder/ffmpeg_decoder_plugin.c +++ b/src/decoder/ffmpeg_decoder_plugin.c @@ -524,7 +524,9 @@ static const char *const ffmpeg_suffixes[] = { "atrac", "au", "aud", "avi", "avm2", "avs", "bap", "bfi", "c93", "cak", "cin", "cmv", "cpk", "daud", "dct", "divx", "dts", "dv", "dvd", "dxa", "eac3", "film", "flac", "flc", "fli", "fll", "flx", "flv", "g726", - "gsm", "gxf", "iss", "m1v", "m2v", "m2t", "m2ts", "m4a", "m4v", "mad", + "gsm", "gxf", "iss", "m1v", "m2v", "m2t", "m2ts", + "m4a", "m4b", "m4v", + "mad", "mj2", "mjpeg", "mjpg", "mka", "mkv", "mlp", "mm", "mmf", "mov", "mp+", "mp1", "mp2", "mp3", "mp4", "mpc", "mpeg", "mpg", "mpga", "mpp", "mpu", "mve", "mvi", "mxf", "nc", "nsv", "nut", "nuv", "oga", "ogm", "ogv", diff --git a/src/decoder/mp4ff_decoder_plugin.c b/src/decoder/mp4ff_decoder_plugin.c index ce4848409..861b08194 100644 --- a/src/decoder/mp4ff_decoder_plugin.c +++ b/src/decoder/mp4ff_decoder_plugin.c @@ -417,7 +417,13 @@ mp4_stream_tag(struct input_stream *is) return tag; } -static const char *const mp4_suffixes[] = { "m4a", "mp4", NULL }; +static const char *const mp4_suffixes[] = { + "m4a", + "m4b", + "mp4", + NULL +}; + static const char *const mp4_mime_types[] = { "audio/mp4", "audio/m4a", NULL }; const struct decoder_plugin mp4ff_decoder_plugin = { diff --git a/src/decoder_control.c b/src/decoder_control.c index 224abbf31..a5e6e4ad3 100644 --- a/src/decoder_control.c +++ b/src/decoder_control.c @@ -20,6 +20,7 @@ #include "config.h" #include "decoder_control.h" #include "player_control.h" +#include "pipe.h" #include <assert.h> @@ -106,6 +107,7 @@ dc_start(struct decoder_control *dc, struct song *song, assert(song != NULL); assert(buffer != NULL); assert(pipe != NULL); + assert(music_pipe_empty(pipe)); dc->song = song; dc->buffer = buffer; diff --git a/src/input/rewind_input_plugin.c b/src/input/rewind_input_plugin.c index 714927c60..cee0d3cd4 100644 --- a/src/input/rewind_input_plugin.c +++ b/src/input/rewind_input_plugin.c @@ -80,14 +80,16 @@ copy_attributes(struct input_rewind *r) struct input_stream *dest = &r->base; const struct input_stream *src = r->input; + assert(dest != src); + assert(dest->mime != src->mime); + dest->ready = src->ready; dest->seekable = src->seekable; dest->size = src->size; dest->offset = src->offset; if (src->mime != NULL) { - if (dest->mime != NULL) - g_free(dest->mime); + g_free(dest->mime); dest->mime = g_strdup(src->mime); } } diff --git a/src/output_all.c b/src/output_all.c index 5b066ba26..19c0f0166 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -323,7 +323,7 @@ audio_output_all_open(const struct audio_format *audio_format, else /* if the pipe hasn't been cleared, the the audio format must not have changed */ - assert(music_pipe_size(g_mp) == 0 || + assert(music_pipe_empty(g_mp) || audio_format_equals(audio_format, &input_audio_format)); @@ -436,7 +436,7 @@ audio_output_all_check(void) assert(g_mp != NULL); while ((chunk = music_pipe_peek(g_mp)) != NULL) { - assert(music_pipe_size(g_mp) > 0); + assert(!music_pipe_empty(g_mp)); if (!chunk_is_consumed(chunk)) /* at least one output is not finished playing diff --git a/src/output_control.c b/src/output_control.c index 5b9b2b902..161404f78 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -102,6 +102,12 @@ audio_output_disable(struct audio_output *ao) g_mutex_unlock(ao->mutex); } +static void +audio_output_close_locked(struct audio_output *ao); + +/** + * Object must be locked (and unlocked) by the caller. + */ static bool audio_output_open(struct audio_output *ao, const struct audio_format *audio_format, @@ -173,6 +179,8 @@ audio_output_open(struct audio_output *ao, static void audio_output_close_locked(struct audio_output *ao) { + assert(ao != NULL); + if (ao->mixer != NULL) mixer_auto_close(ao->mixer); @@ -251,25 +259,6 @@ void audio_output_cancel(struct audio_output *ao) g_mutex_unlock(ao->mutex); } -void audio_output_close(struct audio_output *ao) -{ - if (ao->mixer != NULL) - mixer_auto_close(ao->mixer); - - g_mutex_lock(ao->mutex); - - assert(!ao->open || ao->fail_timer == NULL); - - if (ao->open) - ao_command(ao, AO_COMMAND_CLOSE); - else if (ao->fail_timer != NULL) { - g_timer_destroy(ao->fail_timer); - ao->fail_timer = NULL; - } - - g_mutex_unlock(ao->mutex); -} - void audio_output_release(struct audio_output *ao) { @@ -279,6 +268,16 @@ audio_output_release(struct audio_output *ao) audio_output_close(ao); } +void audio_output_close(struct audio_output *ao) +{ + assert(ao != NULL); + assert(!ao->open || ao->fail_timer == NULL); + + g_mutex_lock(ao->mutex); + audio_output_close_locked(ao); + g_mutex_unlock(ao->mutex); +} + void audio_output_finish(struct audio_output *ao) { audio_output_close(ao); diff --git a/src/output_internal.h b/src/output_internal.h index 9e4d1f25d..18d431352 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -196,7 +196,8 @@ struct audio_output { const struct music_pipe *pipe; /** - * This mutex protects #open, #chunk and #chunk_finished. + * This mutex protects #open, #fail_timer, #chunk and + * #chunk_finished. */ GMutex *mutex; diff --git a/src/output_thread.c b/src/output_thread.c index 8b120325c..380956fac 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -134,10 +134,18 @@ ao_open(struct audio_output *ao) struct audio_format_string af_string; assert(!ao->open); - assert(ao->fail_timer == NULL); assert(ao->pipe != NULL); assert(ao->chunk == NULL); + if (ao->fail_timer != NULL) { + /* this can only happen when this + output thread fails while + audio_output_open() is run in the + player thread */ + g_timer_destroy(ao->fail_timer); + ao->fail_timer = NULL; + } + /* enable the device (just in case the last enable has failed) */ if (!ao_enable(ao)) @@ -455,7 +463,12 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk) /* don't automatically reopen this device for 10 seconds */ + g_mutex_lock(ao->mutex); + + assert(ao->fail_timer == NULL); ao->fail_timer = g_timer_new(); + + g_mutex_unlock(ao->mutex); return false; } diff --git a/src/pipe.h b/src/pipe.h index 676412bb5..7eabb6e54 100644 --- a/src/pipe.h +++ b/src/pipe.h @@ -99,4 +99,10 @@ music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk); unsigned music_pipe_size(const struct music_pipe *mp); +static inline bool +music_pipe_empty(const struct music_pipe *mp) +{ + return music_pipe_size(mp) == 0; +} + #endif diff --git a/src/player_thread.c b/src/player_thread.c index 13d1c2ebb..2d8822eb0 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -149,6 +149,32 @@ player_dc_start(struct player *player, struct music_pipe *pipe) } /** + * Is the decoder still busy on the same song as the player? + * + * Note: this function does not check if the decoder is already + * finished. + */ +static bool +player_dc_at_current_song(const struct player *player) +{ + assert(player != NULL); + assert(player->pipe != NULL); + + return player->dc->pipe == player->pipe; +} + +/** + * Returns true if the decoder is decoding the next song (or has begun + * decoding it, or has finished doing it), and the player hasn't + * switched to that song yet. + */ +static bool +player_dc_at_next_song(const struct player *player) +{ + return player->dc->pipe != NULL && !player_dc_at_current_song(player); +} + +/** * Stop the decoder and clears (and frees) its music pipe. * * Player lock is not held. @@ -173,17 +199,6 @@ player_dc_stop(struct player *player) } /** - * Returns true if the decoder is decoding the next song (or has begun - * decoding it, or has finished doing it), and the player hasn't - * switched to that song yet. - */ -static bool -decoding_next_song(const struct player *player) -{ - return player->dc->pipe != NULL && player->dc->pipe != player->pipe; -} - -/** * After the decoder has been started asynchronously, wait for the * "START" command to finish. The decoder may not be initialized yet, * i.e. there is no audio_format information yet. @@ -405,6 +420,14 @@ static bool player_seek_decoder(struct player *player) return false; } } else { + if (!player_dc_at_current_song(player)) { + /* the decoder is already decoding the "next" song, + but it is the same song file; exchange the pipe */ + music_pipe_clear(player->pipe, player_buffer); + music_pipe_free(player->pipe); + player->pipe = dc->pipe; + } + pc.next_song = NULL; player->queued = false; } @@ -473,7 +496,7 @@ static void player_process_command(struct player *player) case PLAYER_COMMAND_QUEUE: assert(pc.next_song != NULL); assert(!player->queued); - assert(dc->pipe == NULL || dc->pipe == player->pipe); + assert(!player_dc_at_next_song(player)); player->queued = true; player_command_finished_locked(); @@ -527,7 +550,7 @@ static void player_process_command(struct player *player) return; } - if (decoding_next_song(player)) { + if (player_dc_at_next_song(player)) { /* the decoder is already decoding the song - stop it and reset the position */ player_unlock(); @@ -635,7 +658,7 @@ play_next_chunk(struct player *player) return true; if (player->xfade == XFADE_ENABLED && - decoding_next_song(player) && + player_dc_at_next_song(player) && (cross_fade_position = music_pipe_size(player->pipe)) <= player->cross_fade_chunks) { /* perform cross fade */ @@ -881,12 +904,13 @@ static void do_play(struct decoder_control *dc) dc->pipe == player.pipe) { /* the decoder has finished the current song; make it decode the next song */ + assert(dc->pipe == NULL || dc->pipe == player.pipe); player_dc_start(&player, music_pipe_new()); } - if (decoding_next_song(&player) && + if (player_dc_at_next_song(&player) && player.xfade == XFADE_UNKNOWN && !decoder_lock_is_starting(dc)) { /* enable cross fading in this song? if yes, @@ -919,7 +943,7 @@ static void do_play(struct decoder_control *dc) if (pc.command == PLAYER_COMMAND_NONE) player_wait(); continue; - } else if (music_pipe_size(player.pipe) > 0) { + } else if (!music_pipe_empty(player.pipe)) { /* at least one music chunk is ready - send it to the audio output */ @@ -931,7 +955,7 @@ static void do_play(struct decoder_control *dc) /* XXX synchronize in a better way */ g_usleep(10000); - } else if (decoding_next_song(&player)) { + } else if (player_dc_at_next_song(&player)) { /* at the beginning of a new song */ if (!player_song_border(&player)) @@ -940,7 +964,7 @@ static void do_play(struct decoder_control *dc) /* check the size of the pipe again, because the decoder thread may have added something since we last checked */ - if (music_pipe_size(player.pipe) == 0) { + if (music_pipe_empty(player.pipe)) { /* wait for the hardware to finish playback */ audio_output_all_drain(); |