aboutsummaryrefslogtreecommitdiffstats
path: root/src/decoder_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/decoder_api.c')
-rw-r--r--src/decoder_api.c108
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;