diff options
Diffstat (limited to 'src/decoder_api.c')
-rw-r--r-- | src/decoder_api.c | 108 |
1 files changed, 65 insertions, 43 deletions
diff --git a/src/decoder_api.c b/src/decoder_api.c index 19de47855..8f12d017a 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -21,8 +21,7 @@ #include "decoder_api.h" #include "decoder_internal.h" #include "decoder_control.h" -#include "player_control.h" -#include "audio.h" +#include "audio_config.h" #include "song.h" #include "buffer.h" #include "pipe.h" @@ -57,16 +56,18 @@ decoder_initialized(struct decoder *decoder, dc->in_audio_format = *audio_format; getOutputAudioFormat(audio_format, &dc->out_audio_format); + /* force host byte order, even if the decoder supplies reverse + endian */ + dc->out_audio_format.reverse_endian = false; dc->seekable = seekable; dc->total_time = total_time; decoder_lock(dc); dc->state = DECODE_STATE_DECODE; + g_cond_signal(dc->client_cond); decoder_unlock(dc); - player_lock_signal(); - g_debug("audio_format=%s, seekable=%s", audio_format_to_string(&dc->in_audio_format, &af_string), seekable ? "true" : "false"); @@ -189,9 +190,8 @@ decoder_command_finished(struct decoder *decoder) } dc->command = DECODE_COMMAND_NONE; + g_cond_signal(dc->client_cond); decoder_unlock(dc); - - player_lock_signal(); } double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder) @@ -231,50 +231,73 @@ void decoder_seek_error(struct decoder * decoder) decoder_command_finished(decoder); } +/** + * Should be read operation be cancelled? That is the case when the + * player thread has sent a command such as "STOP". + */ +G_GNUC_PURE +static inline bool +decoder_check_cancel_read(const struct decoder *decoder) +{ + if (decoder == NULL) + return false; + + const struct decoder_control *dc = decoder->dc; + if (dc->command == DECODE_COMMAND_NONE) + return false; + + /* ignore the SEEK command during initialization, the plugin + should handle that after it has initialized successfully */ + if (dc->command == DECODE_COMMAND_SEEK && + (dc->state == DECODE_STATE_START || decoder->seeking)) + return false; + + return true; +} + size_t decoder_read(struct decoder *decoder, struct input_stream *is, void *buffer, size_t length) { - const struct decoder_control *dc = - decoder != NULL ? decoder->dc : NULL; + /* XXX don't allow decoder==NULL */ GError *error = NULL; size_t nbytes; assert(decoder == NULL || - dc->state == DECODE_STATE_START || - dc->state == DECODE_STATE_DECODE); + decoder->dc->state == DECODE_STATE_START || + decoder->dc->state == DECODE_STATE_DECODE); assert(is != NULL); assert(buffer != NULL); if (length == 0) return 0; + input_stream_lock(is); + while (true) { - /* XXX don't allow decoder==NULL */ - if (decoder != NULL && - /* ignore the SEEK command during initialization, - the plugin should handle that after it has - initialized successfully */ - (dc->command != DECODE_COMMAND_SEEK || - (dc->state != DECODE_STATE_START && !decoder->seeking)) && - dc->command != DECODE_COMMAND_NONE) + if (decoder_check_cancel_read(decoder)) { + input_stream_unlock(is); return 0; + } - nbytes = input_stream_read(is, buffer, length, &error); + if (input_stream_available(is)) + break; - if (G_UNLIKELY(nbytes == 0 && error != NULL)) { - g_warning("%s", error->message); - g_error_free(error); - return 0; - } + g_cond_wait(is->cond, is->mutex); + } - if (nbytes > 0 || input_stream_eof(is)) - return nbytes; + nbytes = input_stream_read(is, buffer, length, &error); + assert(nbytes == 0 || error == NULL); + assert(nbytes > 0 || error != NULL || input_stream_eof(is)); - /* sleep for a fraction of a second! */ - /* XXX don't sleep, wait for an event instead */ - g_usleep(10000); + if (G_UNLIKELY(nbytes == 0 && error != NULL)) { + g_warning("%s", error->message); + g_error_free(error); } + + input_stream_unlock(is); + + return nbytes; } void @@ -291,8 +314,7 @@ decoder_timestamp(struct decoder *decoder, double t) * (decoder.chunk) if there is one. */ static enum decoder_command -do_send_tag(struct decoder *decoder, struct input_stream *is, - const struct tag *tag) +do_send_tag(struct decoder *decoder, const struct tag *tag) { struct music_chunk *chunk; @@ -300,12 +322,12 @@ do_send_tag(struct decoder *decoder, struct input_stream *is, /* there is a partial chunk - flush it, we want the tag in a new chunk */ decoder_flush_chunk(decoder); - player_lock_signal(); + g_cond_signal(decoder->dc->client_cond); } assert(decoder->chunk == NULL); - chunk = decoder_get_chunk(decoder, is); + chunk = decoder_get_chunk(decoder); if (chunk == NULL) { assert(decoder->dc->command != DECODE_COMMAND_NONE); return decoder->dc->command; @@ -321,7 +343,7 @@ update_stream_tag(struct decoder *decoder, struct input_stream *is) struct tag *tag; tag = is != NULL - ? input_stream_tag(is) + ? input_stream_lock_tag(is) : NULL; if (tag == NULL) { tag = decoder->song_tag; @@ -372,11 +394,11 @@ decoder_data(struct decoder *decoder, tag = tag_merge(decoder->decoder_tag, decoder->stream_tag); - cmd = do_send_tag(decoder, is, tag); + cmd = do_send_tag(decoder, tag); tag_free(tag); } else /* send only the stream tag */ - cmd = do_send_tag(decoder, is, decoder->stream_tag); + cmd = do_send_tag(decoder, decoder->stream_tag); if (cmd != DECODE_COMMAND_NONE) return cmd; @@ -402,7 +424,7 @@ decoder_data(struct decoder *decoder, size_t nbytes; bool full; - chunk = decoder_get_chunk(decoder, is); + chunk = decoder_get_chunk(decoder); if (chunk == NULL) { assert(dc->command != DECODE_COMMAND_NONE); return dc->command; @@ -415,7 +437,7 @@ decoder_data(struct decoder *decoder, if (dest == NULL) { /* the chunk is full, flush it */ decoder_flush_chunk(decoder); - player_lock_signal(); + g_cond_signal(dc->client_cond); continue; } @@ -434,7 +456,7 @@ decoder_data(struct decoder *decoder, if (full) { /* the chunk is full, flush it */ decoder_flush_chunk(decoder); - player_lock_signal(); + g_cond_signal(dc->client_cond); } data += nbytes; @@ -489,11 +511,11 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, struct tag *merged; merged = tag_merge(decoder->stream_tag, decoder->decoder_tag); - cmd = do_send_tag(decoder, is, merged); + cmd = do_send_tag(decoder, merged); tag_free(merged); } else /* send only the decoder tag */ - cmd = do_send_tag(decoder, is, tag); + cmd = do_send_tag(decoder, tag); return cmd; } @@ -526,7 +548,7 @@ decoder_replay_gain(struct decoder *decoder, replay gain values affect the following samples */ decoder_flush_chunk(decoder); - player_lock_signal(); + g_cond_signal(decoder->dc->client_cond); } } else decoder->replay_gain_serial = 0; |