Commit 6ef428af authored by Max Kellermann's avatar Max Kellermann

decoder_control: removed the global variable "dc"

Allocate a decoder_control object where needed, and pass it around. This will allow more than one decoder thread one day.
parent 806496df
...@@ -37,12 +37,15 @@ ...@@ -37,12 +37,15 @@
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "decoder" #define G_LOG_DOMAIN "decoder"
void decoder_initialized(G_GNUC_UNUSED struct decoder * decoder, void
const struct audio_format *audio_format, decoder_initialized(struct decoder *decoder,
bool seekable, float total_time) const struct audio_format *audio_format,
bool seekable, float total_time)
{ {
assert(dc.state == DECODE_STATE_START); struct decoder_control *dc = decoder->dc;
assert(dc.pipe != NULL);
assert(dc->state == DECODE_STATE_START);
assert(dc->pipe != NULL);
assert(decoder != NULL); assert(decoder != NULL);
assert(decoder->stream_tag == NULL); assert(decoder->stream_tag == NULL);
assert(decoder->decoder_tag == NULL); assert(decoder->decoder_tag == NULL);
...@@ -51,86 +54,98 @@ void decoder_initialized(G_GNUC_UNUSED struct decoder * decoder, ...@@ -51,86 +54,98 @@ void decoder_initialized(G_GNUC_UNUSED struct decoder * decoder,
assert(audio_format_defined(audio_format)); assert(audio_format_defined(audio_format));
assert(audio_format_valid(audio_format)); assert(audio_format_valid(audio_format));
dc.in_audio_format = *audio_format; dc->in_audio_format = *audio_format;
getOutputAudioFormat(audio_format, &dc.out_audio_format); getOutputAudioFormat(audio_format, &dc->out_audio_format);
dc.seekable = seekable; dc->seekable = seekable;
dc.total_time = total_time; dc->total_time = total_time;
decoder_lock(); decoder_lock(dc);
dc.state = DECODE_STATE_DECODE; dc->state = DECODE_STATE_DECODE;
decoder_unlock(); decoder_unlock(dc);
player_lock_signal(); player_lock_signal();
g_debug("audio_format=%u:%u:%u, seekable=%s", g_debug("audio_format=%u:%u:%u, seekable=%s",
dc.in_audio_format.sample_rate, dc.in_audio_format.bits, dc->in_audio_format.sample_rate,
dc.in_audio_format.channels, dc->in_audio_format.bits,
dc->in_audio_format.channels,
seekable ? "true" : "false"); seekable ? "true" : "false");
if (!audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) if (!audio_format_equals(&dc->in_audio_format,
&dc->out_audio_format))
g_debug("converting to %u:%u:%u", g_debug("converting to %u:%u:%u",
dc.out_audio_format.sample_rate, dc->out_audio_format.sample_rate,
dc.out_audio_format.bits, dc->out_audio_format.bits,
dc.out_audio_format.channels); dc->out_audio_format.channels);
} }
char *decoder_get_uri(G_GNUC_UNUSED struct decoder *decoder) char *decoder_get_uri(G_GNUC_UNUSED struct decoder *decoder)
{ {
assert(dc.pipe != NULL); const struct decoder_control *dc = decoder->dc;
assert(dc->pipe != NULL);
return song_get_uri(dc.current_song); return song_get_uri(dc->current_song);
} }
enum decoder_command decoder_get_command(G_GNUC_UNUSED struct decoder * decoder) enum decoder_command decoder_get_command(G_GNUC_UNUSED struct decoder * decoder)
{ {
assert(dc.pipe != NULL); const struct decoder_control *dc = decoder->dc;
assert(dc->pipe != NULL);
return dc.command; return dc->command;
} }
void decoder_command_finished(G_GNUC_UNUSED struct decoder * decoder) void decoder_command_finished(G_GNUC_UNUSED struct decoder * decoder)
{ {
decoder_lock(); struct decoder_control *dc = decoder->dc;
assert(dc.command != DECODE_COMMAND_NONE); decoder_lock(dc);
assert(dc.command != DECODE_COMMAND_SEEK ||
dc.seek_error || decoder->seeking);
assert(dc.pipe != NULL);
if (dc.command == DECODE_COMMAND_SEEK) { assert(dc->command != DECODE_COMMAND_NONE);
assert(dc->command != DECODE_COMMAND_SEEK ||
dc->seek_error || decoder->seeking);
assert(dc->pipe != NULL);
if (dc->command == DECODE_COMMAND_SEEK) {
/* delete frames from the old song position */ /* delete frames from the old song position */
if (decoder->chunk != NULL) { if (decoder->chunk != NULL) {
music_buffer_return(dc.buffer, decoder->chunk); music_buffer_return(dc->buffer, decoder->chunk);
decoder->chunk = NULL; decoder->chunk = NULL;
} }
music_pipe_clear(dc.pipe, dc.buffer); music_pipe_clear(dc->pipe, dc->buffer);
} }
dc.command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
decoder_unlock(); decoder_unlock(dc);
player_lock_signal(); player_lock_signal();
} }
double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder) double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
{ {
assert(dc.command == DECODE_COMMAND_SEEK); const struct decoder_control *dc = decoder->dc;
assert(dc.pipe != NULL);
assert(dc->command == DECODE_COMMAND_SEEK);
assert(dc->pipe != NULL);
decoder->seeking = true; decoder->seeking = true;
return dc.seek_where; return dc->seek_where;
} }
void decoder_seek_error(struct decoder * decoder) void decoder_seek_error(struct decoder * decoder)
{ {
assert(dc.command == DECODE_COMMAND_SEEK); struct decoder_control *dc = decoder->dc;
assert(dc.pipe != NULL);
assert(dc->command == DECODE_COMMAND_SEEK);
assert(dc->pipe != NULL);
dc.seek_error = true; dc->seek_error = true;
decoder_command_finished(decoder); decoder_command_finished(decoder);
} }
...@@ -138,11 +153,12 @@ size_t decoder_read(struct decoder *decoder, ...@@ -138,11 +153,12 @@ size_t decoder_read(struct decoder *decoder,
struct input_stream *is, struct input_stream *is,
void *buffer, size_t length) void *buffer, size_t length)
{ {
const struct decoder_control *dc = decoder->dc;
size_t nbytes; size_t nbytes;
assert(decoder == NULL || assert(decoder == NULL ||
dc.state == DECODE_STATE_START || dc->state == DECODE_STATE_START ||
dc.state == DECODE_STATE_DECODE); dc->state == DECODE_STATE_DECODE);
assert(is != NULL); assert(is != NULL);
assert(buffer != NULL); assert(buffer != NULL);
...@@ -155,9 +171,9 @@ size_t decoder_read(struct decoder *decoder, ...@@ -155,9 +171,9 @@ size_t decoder_read(struct decoder *decoder,
/* ignore the SEEK command during initialization, /* ignore the SEEK command during initialization,
the plugin should handle that after it has the plugin should handle that after it has
initialized successfully */ initialized successfully */
(dc.command != DECODE_COMMAND_SEEK || (dc->command != DECODE_COMMAND_SEEK ||
(dc.state != DECODE_STATE_START && !decoder->seeking)) && (dc->state != DECODE_STATE_START && !decoder->seeking)) &&
dc.command != DECODE_COMMAND_NONE) dc->command != DECODE_COMMAND_NONE)
return 0; return 0;
nbytes = input_stream_read(is, buffer, length); nbytes = input_stream_read(is, buffer, length);
...@@ -191,8 +207,8 @@ do_send_tag(struct decoder *decoder, struct input_stream *is, ...@@ -191,8 +207,8 @@ do_send_tag(struct decoder *decoder, struct input_stream *is,
chunk = decoder_get_chunk(decoder, is); chunk = decoder_get_chunk(decoder, is);
if (chunk == NULL) { if (chunk == NULL) {
assert(dc.command != DECODE_COMMAND_NONE); assert(decoder->dc->command != DECODE_COMMAND_NONE);
return dc.command; return decoder->dc->command;
} }
chunk->tag = tag_dup(tag); chunk->tag = tag_dup(tag);
...@@ -231,17 +247,18 @@ decoder_data(struct decoder *decoder, ...@@ -231,17 +247,18 @@ decoder_data(struct decoder *decoder,
float data_time, uint16_t bitRate, float data_time, uint16_t bitRate,
struct replay_gain_info *replay_gain_info) struct replay_gain_info *replay_gain_info)
{ {
struct decoder_control *dc = decoder->dc;
const char *data = _data; const char *data = _data;
GError *error = NULL; GError *error = NULL;
enum decoder_command cmd; enum decoder_command cmd;
assert(dc.state == DECODE_STATE_DECODE); assert(dc->state == DECODE_STATE_DECODE);
assert(dc.pipe != NULL); assert(dc->pipe != NULL);
assert(length % audio_format_frame_size(&dc.in_audio_format) == 0); assert(length % audio_format_frame_size(&dc->in_audio_format) == 0);
decoder_lock(); decoder_lock(dc);
cmd = dc.command; cmd = dc->command;
decoder_unlock(); decoder_unlock(dc);
if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK || if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK ||
length == 0) length == 0)
...@@ -266,10 +283,10 @@ decoder_data(struct decoder *decoder, ...@@ -266,10 +283,10 @@ decoder_data(struct decoder *decoder,
return cmd; return cmd;
} }
if (!audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) { if (!audio_format_equals(&dc->in_audio_format, &dc->out_audio_format)) {
data = pcm_convert(&decoder->conv_state, data = pcm_convert(&decoder->conv_state,
&dc.in_audio_format, data, length, &dc->in_audio_format, data, length,
&dc.out_audio_format, &length, &dc->out_audio_format, &length,
&error); &error);
if (data == NULL) { if (data == NULL) {
/* the PCM conversion has failed - stop /* the PCM conversion has failed - stop
...@@ -288,11 +305,11 @@ decoder_data(struct decoder *decoder, ...@@ -288,11 +305,11 @@ decoder_data(struct decoder *decoder,
chunk = decoder_get_chunk(decoder, is); chunk = decoder_get_chunk(decoder, is);
if (chunk == NULL) { if (chunk == NULL) {
assert(dc.command != DECODE_COMMAND_NONE); assert(dc->command != DECODE_COMMAND_NONE);
return dc.command; return dc->command;
} }
dest = music_chunk_write(chunk, &dc.out_audio_format, dest = music_chunk_write(chunk, &dc->out_audio_format,
data_time, bitRate, &nbytes); data_time, bitRate, &nbytes);
if (dest == NULL) { if (dest == NULL) {
/* the chunk is full, flush it */ /* the chunk is full, flush it */
...@@ -314,13 +331,13 @@ decoder_data(struct decoder *decoder, ...@@ -314,13 +331,13 @@ decoder_data(struct decoder *decoder,
if (replay_gain_mode != REPLAY_GAIN_OFF) if (replay_gain_mode != REPLAY_GAIN_OFF)
replay_gain_apply(replay_gain_info, dest, nbytes, replay_gain_apply(replay_gain_info, dest, nbytes,
&dc.out_audio_format); &dc->out_audio_format);
else if (normalizationEnabled) else if (normalizationEnabled)
normalizeData(dest, nbytes, &dc.out_audio_format); normalizeData(dest, nbytes, &dc->out_audio_format);
/* expand the music pipe chunk */ /* expand the music pipe chunk */
full = music_chunk_expand(chunk, &dc.out_audio_format, nbytes); full = music_chunk_expand(chunk, &dc->out_audio_format, nbytes);
if (full) { if (full) {
/* the chunk is full, flush it */ /* the chunk is full, flush it */
decoder_flush_chunk(decoder); decoder_flush_chunk(decoder);
...@@ -338,10 +355,11 @@ enum decoder_command ...@@ -338,10 +355,11 @@ enum decoder_command
decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is,
const struct tag *tag) const struct tag *tag)
{ {
const struct decoder_control *dc = decoder->dc;
enum decoder_command cmd; enum decoder_command cmd;
assert(dc.state == DECODE_STATE_DECODE); assert(dc->state == DECODE_STATE_DECODE);
assert(dc.pipe != NULL); assert(dc->pipe != NULL);
assert(tag != NULL); assert(tag != NULL);
/* save the tag */ /* save the tag */
......
...@@ -22,131 +22,134 @@ ...@@ -22,131 +22,134 @@
#include <assert.h> #include <assert.h>
struct decoder_control dc; void
dc_init(struct decoder_control *dc)
void dc_init(void)
{ {
dc.mutex = g_mutex_new(); dc->thread = NULL;
dc.cond = g_cond_new();
dc->mutex = g_mutex_new();
dc->cond = g_cond_new();
dc.state = DECODE_STATE_STOP; dc->state = DECODE_STATE_STOP;
dc.command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
} }
void dc_deinit(void) void
dc_deinit(struct decoder_control *dc)
{ {
g_cond_free(dc.cond); g_cond_free(dc->cond);
g_mutex_free(dc.mutex); g_mutex_free(dc->mutex);
} }
static void static void
dc_command_wait_locked(void) dc_command_wait_locked(struct decoder_control *dc)
{ {
while (dc.command != DECODE_COMMAND_NONE) { while (dc->command != DECODE_COMMAND_NONE) {
decoder_signal(); decoder_signal(dc);
player_wait_decoder(); player_wait_decoder(dc);
} }
} }
void void
dc_command_wait(void) dc_command_wait(struct decoder_control *dc)
{ {
decoder_lock(); decoder_lock(dc);
dc_command_wait_locked(); dc_command_wait_locked(dc);
decoder_unlock(); decoder_unlock(dc);
} }
static void static void
dc_command_locked(enum decoder_command cmd) dc_command_locked(struct decoder_control *dc, enum decoder_command cmd)
{ {
dc.command = cmd; dc->command = cmd;
dc_command_wait_locked(); dc_command_wait_locked(dc);
} }
static void static void
dc_command(enum decoder_command cmd) dc_command(struct decoder_control *dc, enum decoder_command cmd)
{ {
decoder_lock(); decoder_lock(dc);
dc_command_locked(cmd); dc_command_locked(dc, cmd);
decoder_unlock(); decoder_unlock(dc);
} }
static void dc_command_async(enum decoder_command cmd) static void
dc_command_async(struct decoder_control *dc, enum decoder_command cmd)
{ {
decoder_lock(); decoder_lock(dc);
dc.command = cmd; dc->command = cmd;
decoder_signal(); decoder_signal(dc);
decoder_unlock(); decoder_unlock(dc);
} }
void void
dc_start(struct song *song) dc_start(struct decoder_control *dc, struct song *song)
{ {
assert(dc.pipe != NULL); assert(dc->pipe != NULL);
assert(song != NULL); assert(song != NULL);
dc.next_song = song; dc->next_song = song;
dc_command(DECODE_COMMAND_START); dc_command(dc, DECODE_COMMAND_START);
} }
void void
dc_start_async(struct song *song) dc_start_async(struct decoder_control *dc, struct song *song)
{ {
assert(dc.pipe != NULL); assert(dc->pipe != NULL);
assert(song != NULL); assert(song != NULL);
dc.next_song = song; dc->next_song = song;
dc_command_async(DECODE_COMMAND_START); dc_command_async(dc, DECODE_COMMAND_START);
} }
void void
dc_stop(void) dc_stop(struct decoder_control *dc)
{ {
decoder_lock(); decoder_lock(dc);
if (dc.command != DECODE_COMMAND_NONE) if (dc->command != DECODE_COMMAND_NONE)
/* Attempt to cancel the current command. If it's too /* Attempt to cancel the current command. If it's too
late and the decoder thread is already executing late and the decoder thread is already executing
the old command, we'll call STOP again in this the old command, we'll call STOP again in this
function (see below). */ function (see below). */
dc_command_locked(DECODE_COMMAND_STOP); dc_command_locked(dc, DECODE_COMMAND_STOP);
if (dc.state != DECODE_STATE_STOP && dc.state != DECODE_STATE_ERROR) if (dc->state != DECODE_STATE_STOP && dc->state != DECODE_STATE_ERROR)
dc_command_locked(DECODE_COMMAND_STOP); dc_command_locked(dc, DECODE_COMMAND_STOP);
decoder_unlock(); decoder_unlock(dc);
} }
bool bool
dc_seek(double where) dc_seek(struct decoder_control *dc, double where)
{ {
assert(dc.state != DECODE_STATE_START); assert(dc->state != DECODE_STATE_START);
assert(where >= 0.0); assert(where >= 0.0);
if (dc.state == DECODE_STATE_STOP || if (dc->state == DECODE_STATE_STOP ||
dc.state == DECODE_STATE_ERROR || !dc.seekable) dc->state == DECODE_STATE_ERROR || !dc->seekable)
return false; return false;
dc.seek_where = where; dc->seek_where = where;
dc.seek_error = false; dc->seek_error = false;
dc_command(DECODE_COMMAND_SEEK); dc_command(dc, DECODE_COMMAND_SEEK);
if (dc.seek_error) if (dc->seek_error)
return false; return false;
return true; return true;
} }
void void
dc_quit(void) dc_quit(struct decoder_control *dc)
{ {
assert(dc.thread != NULL); assert(dc->thread != NULL);
dc.quit = true; dc->quit = true;
dc_command_async(DECODE_COMMAND_STOP); dc_command_async(dc, DECODE_COMMAND_STOP);
g_thread_join(dc.thread); g_thread_join(dc->thread);
dc.thread = NULL; dc->thread = NULL;
} }
...@@ -83,28 +83,28 @@ struct decoder_control { ...@@ -83,28 +83,28 @@ struct decoder_control {
struct music_pipe *pipe; struct music_pipe *pipe;
}; };
extern struct decoder_control dc; void
dc_init(struct decoder_control *dc);
void dc_init(void);
void dc_deinit(void); void
dc_deinit(struct decoder_control *dc);
/** /**
* Locks the #decoder_control object. * Locks the #decoder_control object.
*/ */
static inline void static inline void
decoder_lock(void) decoder_lock(struct decoder_control *dc)
{ {
g_mutex_lock(dc.mutex); g_mutex_lock(dc->mutex);
} }
/** /**
* Unlocks the #decoder_control object. * Unlocks the #decoder_control object.
*/ */
static inline void static inline void
decoder_unlock(void) decoder_unlock(struct decoder_control *dc)
{ {
g_mutex_unlock(dc.mutex); g_mutex_unlock(dc->mutex);
} }
/** /**
...@@ -113,9 +113,9 @@ decoder_unlock(void) ...@@ -113,9 +113,9 @@ decoder_unlock(void)
* prior to calling this function. * prior to calling this function.
*/ */
static inline void static inline void
decoder_wait(void) decoder_wait(struct decoder_control *dc)
{ {
g_cond_wait(dc.cond, dc.mutex); g_cond_wait(dc->cond, dc->mutex);
} }
/** /**
...@@ -124,75 +124,81 @@ decoder_wait(void) ...@@ -124,75 +124,81 @@ decoder_wait(void)
* this function. * this function.
*/ */
static inline void static inline void
decoder_signal(void) decoder_signal(struct decoder_control *dc)
{ {
g_cond_signal(dc.cond); g_cond_signal(dc->cond);
} }
static inline bool decoder_is_idle(void) static inline bool
decoder_is_idle(const struct decoder_control *dc)
{ {
return (dc.state == DECODE_STATE_STOP || return (dc->state == DECODE_STATE_STOP ||
dc.state == DECODE_STATE_ERROR) && dc->state == DECODE_STATE_ERROR) &&
dc.command != DECODE_COMMAND_START; dc->command != DECODE_COMMAND_START;
} }
static inline bool decoder_is_starting(void) static inline bool
decoder_is_starting(const struct decoder_control *dc)
{ {
return dc.command == DECODE_COMMAND_START || return dc->command == DECODE_COMMAND_START ||
dc.state == DECODE_STATE_START; dc->state == DECODE_STATE_START;
} }
static inline bool decoder_has_failed(void) static inline bool
decoder_has_failed(const struct decoder_control *dc)
{ {
assert(dc.command == DECODE_COMMAND_NONE); assert(dc->command == DECODE_COMMAND_NONE);
return dc.state == DECODE_STATE_ERROR; return dc->state == DECODE_STATE_ERROR;
} }
static inline bool decoder_lock_is_idle(void) static inline bool
decoder_lock_is_idle(struct decoder_control *dc)
{ {
bool ret; bool ret;
decoder_lock(); decoder_lock(dc);
ret = decoder_is_idle(); ret = decoder_is_idle(dc);
decoder_unlock(); decoder_unlock(dc);
return ret; return ret;
} }
static inline bool decoder_lock_is_starting(void) static inline bool
decoder_lock_is_starting(struct decoder_control *dc)
{ {
bool ret; bool ret;
decoder_lock(); decoder_lock(dc);
ret = decoder_is_starting(); ret = decoder_is_starting(dc);
decoder_unlock(); decoder_unlock(dc);
return ret; return ret;
} }
static inline bool decoder_lock_has_failed(void) static inline bool
decoder_lock_has_failed(struct decoder_control *dc)
{ {
bool ret; bool ret;
decoder_lock(); decoder_lock(dc);
ret = decoder_has_failed(); ret = decoder_has_failed(dc);
decoder_unlock(); decoder_unlock(dc);
return ret; return ret;
} }
static inline struct song * static inline const struct song *
decoder_current_song(void) decoder_current_song(const struct decoder_control *dc)
{ {
switch (dc.state) { switch (dc->state) {
case DECODE_STATE_STOP: case DECODE_STATE_STOP:
case DECODE_STATE_ERROR: case DECODE_STATE_ERROR:
return NULL; return NULL;
case DECODE_STATE_START: case DECODE_STATE_START:
case DECODE_STATE_DECODE: case DECODE_STATE_DECODE:
return dc.current_song; return dc->current_song;
} }
assert(false); assert(false);
...@@ -200,21 +206,21 @@ decoder_current_song(void) ...@@ -200,21 +206,21 @@ decoder_current_song(void)
} }
void void
dc_command_wait(void); dc_command_wait(struct decoder_control *dc);
void void
dc_start(struct song *song); dc_start(struct decoder_control *dc, struct song *song);
void void
dc_start_async(struct song *song); dc_start_async(struct decoder_control *dc, struct song *song);
void void
dc_stop(void); dc_stop(struct decoder_control *dc);
bool bool
dc_seek(double where); dc_seek(struct decoder_control *dc, double where);
void void
dc_quit(void); dc_quit(struct decoder_control *dc);
#endif #endif
...@@ -34,13 +34,13 @@ ...@@ -34,13 +34,13 @@
* potentially blocking operation. * potentially blocking operation.
*/ */
static int static int
decoder_input_buffer(struct input_stream *is) decoder_input_buffer(struct decoder_control *dc, struct input_stream *is)
{ {
int ret; int ret;
decoder_unlock(); decoder_unlock(dc);
ret = input_stream_buffer(is) > 0; ret = input_stream_buffer(is) > 0;
decoder_lock(); decoder_lock(dc);
return ret; return ret;
} }
...@@ -50,17 +50,17 @@ decoder_input_buffer(struct input_stream *is) ...@@ -50,17 +50,17 @@ decoder_input_buffer(struct input_stream *is)
* one. * one.
*/ */
static enum decoder_command static enum decoder_command
need_chunks(struct input_stream *is, bool do_wait) need_chunks(struct decoder_control *dc, struct input_stream *is, bool do_wait)
{ {
if (dc.command == DECODE_COMMAND_STOP || if (dc->command == DECODE_COMMAND_STOP ||
dc.command == DECODE_COMMAND_SEEK) dc->command == DECODE_COMMAND_SEEK)
return dc.command; return dc->command;
if ((is == NULL || decoder_input_buffer(is) <= 0) && do_wait) { if ((is == NULL || decoder_input_buffer(dc, is) <= 0) && do_wait) {
decoder_wait(); decoder_wait(dc);
player_signal(); player_signal();
return dc.command; return dc->command;
} }
return DECODE_COMMAND_NONE; return DECODE_COMMAND_NONE;
...@@ -69,6 +69,7 @@ need_chunks(struct input_stream *is, bool do_wait) ...@@ -69,6 +69,7 @@ need_chunks(struct input_stream *is, bool do_wait)
struct music_chunk * struct music_chunk *
decoder_get_chunk(struct decoder *decoder, struct input_stream *is) decoder_get_chunk(struct decoder *decoder, struct input_stream *is)
{ {
struct decoder_control *dc = decoder->dc;
enum decoder_command cmd; enum decoder_command cmd;
assert(decoder != NULL); assert(decoder != NULL);
...@@ -77,13 +78,13 @@ decoder_get_chunk(struct decoder *decoder, struct input_stream *is) ...@@ -77,13 +78,13 @@ decoder_get_chunk(struct decoder *decoder, struct input_stream *is)
return decoder->chunk; return decoder->chunk;
do { do {
decoder->chunk = music_buffer_allocate(dc.buffer); decoder->chunk = music_buffer_allocate(dc->buffer);
if (decoder->chunk != NULL) if (decoder->chunk != NULL)
return decoder->chunk; return decoder->chunk;
decoder_lock(); decoder_lock(dc);
cmd = need_chunks(is, true); cmd = need_chunks(dc, is, true);
decoder_unlock(); decoder_unlock(dc);
} while (cmd == DECODE_COMMAND_NONE); } while (cmd == DECODE_COMMAND_NONE);
return NULL; return NULL;
...@@ -92,13 +93,15 @@ decoder_get_chunk(struct decoder *decoder, struct input_stream *is) ...@@ -92,13 +93,15 @@ decoder_get_chunk(struct decoder *decoder, struct input_stream *is)
void void
decoder_flush_chunk(struct decoder *decoder) decoder_flush_chunk(struct decoder *decoder)
{ {
struct decoder_control *dc = decoder->dc;
assert(decoder != NULL); assert(decoder != NULL);
assert(decoder->chunk != NULL); assert(decoder->chunk != NULL);
if (music_chunk_is_empty(decoder->chunk)) if (music_chunk_is_empty(decoder->chunk))
music_buffer_return(dc.buffer, decoder->chunk); music_buffer_return(dc->buffer, decoder->chunk);
else else
music_pipe_push(dc.pipe, decoder->chunk); music_pipe_push(dc->pipe, decoder->chunk);
decoder->chunk = NULL; decoder->chunk = NULL;
} }
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
struct input_stream; struct input_stream;
struct decoder { struct decoder {
struct decoder_control *dc;
struct pcm_convert_state conv_state; struct pcm_convert_state conv_state;
bool seeking; bool seeking;
......
...@@ -47,21 +47,21 @@ decoder_stream_decode(const struct decoder_plugin *plugin, ...@@ -47,21 +47,21 @@ decoder_stream_decode(const struct decoder_plugin *plugin,
assert(decoder->decoder_tag == NULL); assert(decoder->decoder_tag == NULL);
assert(input_stream != NULL); assert(input_stream != NULL);
assert(input_stream->ready); assert(input_stream->ready);
assert(dc.state == DECODE_STATE_START); assert(decoder->dc->state == DECODE_STATE_START);
decoder_unlock(); decoder_unlock(decoder->dc);
/* rewind the stream, so each plugin gets a fresh start */ /* rewind the stream, so each plugin gets a fresh start */
input_stream_seek(input_stream, 0, SEEK_SET); input_stream_seek(input_stream, 0, SEEK_SET);
decoder_plugin_stream_decode(plugin, decoder, input_stream); decoder_plugin_stream_decode(plugin, decoder, input_stream);
decoder_lock(); decoder_lock(decoder->dc);
assert(dc.state == DECODE_STATE_START || assert(decoder->dc->state == DECODE_STATE_START ||
dc.state == DECODE_STATE_DECODE); decoder->dc->state == DECODE_STATE_DECODE);
return dc.state != DECODE_STATE_START; return decoder->dc->state != DECODE_STATE_START;
} }
static bool static bool
...@@ -75,30 +75,34 @@ decoder_file_decode(const struct decoder_plugin *plugin, ...@@ -75,30 +75,34 @@ decoder_file_decode(const struct decoder_plugin *plugin,
assert(decoder->decoder_tag == NULL); assert(decoder->decoder_tag == NULL);
assert(path != NULL); assert(path != NULL);
assert(g_path_is_absolute(path)); assert(g_path_is_absolute(path));
assert(dc.state == DECODE_STATE_START); assert(decoder->dc->state == DECODE_STATE_START);
decoder_unlock(); decoder_unlock(decoder->dc);
decoder_plugin_file_decode(plugin, decoder, path); decoder_plugin_file_decode(plugin, decoder, path);
decoder_lock(); decoder_lock(decoder->dc);
assert(dc.state == DECODE_STATE_START || assert(decoder->dc->state == DECODE_STATE_START ||
dc.state == DECODE_STATE_DECODE); decoder->dc->state == DECODE_STATE_DECODE);
return dc.state != DECODE_STATE_START; return decoder->dc->state != DECODE_STATE_START;
} }
static void decoder_run_song(const struct song *song, const char *uri) static void
decoder_run_song(struct decoder_control *dc,
const struct song *song, const char *uri)
{ {
struct decoder decoder; struct decoder decoder = {
.dc = dc,
};
int ret; int ret;
bool close_instream = true; bool close_instream = true;
struct input_stream input_stream; struct input_stream input_stream;
const struct decoder_plugin *plugin; const struct decoder_plugin *plugin;
if (!input_stream_open(&input_stream, uri)) { if (!input_stream_open(&input_stream, uri)) {
dc.state = DECODE_STATE_ERROR; dc->state = DECODE_STATE_ERROR;
return; return;
} }
...@@ -109,8 +113,8 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -109,8 +113,8 @@ static void decoder_run_song(const struct song *song, const char *uri)
decoder.decoder_tag = NULL; decoder.decoder_tag = NULL;
decoder.chunk = NULL; decoder.chunk = NULL;
dc.state = DECODE_STATE_START; dc->state = DECODE_STATE_START;
dc.command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
player_signal(); player_signal();
...@@ -118,32 +122,32 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -118,32 +122,32 @@ static void decoder_run_song(const struct song *song, const char *uri)
will be available then */ will be available then */
while (!input_stream.ready) { while (!input_stream.ready) {
if (dc.command == DECODE_COMMAND_STOP) { if (dc->command == DECODE_COMMAND_STOP) {
decoder_unlock(); decoder_unlock(dc);
input_stream_close(&input_stream); input_stream_close(&input_stream);
decoder_lock(); decoder_lock(dc);
dc.state = DECODE_STATE_STOP; dc->state = DECODE_STATE_STOP;
return; return;
} }
decoder_unlock(); decoder_unlock(dc);
ret = input_stream_buffer(&input_stream); ret = input_stream_buffer(&input_stream);
if (ret < 0) { if (ret < 0) {
input_stream_close(&input_stream); input_stream_close(&input_stream);
decoder_lock(); decoder_lock(dc);
dc.state = DECODE_STATE_ERROR; dc->state = DECODE_STATE_ERROR;
return; return;
} }
decoder_lock(); decoder_lock(dc);
} }
if (dc.command == DECODE_COMMAND_STOP) { if (dc->command == DECODE_COMMAND_STOP) {
decoder_unlock(); decoder_unlock(dc);
input_stream_close(&input_stream); input_stream_close(&input_stream);
decoder_lock(); decoder_lock(dc);
dc.state = DECODE_STATE_STOP; dc->state = DECODE_STATE_STOP;
return; return;
} }
...@@ -162,7 +166,7 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -162,7 +166,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
if (ret) if (ret)
break; break;
assert(dc.state == DECODE_STATE_START); assert(dc->state == DECODE_STATE_START);
} }
/* if that fails, try suffix matching the URL: */ /* if that fails, try suffix matching the URL: */
...@@ -177,7 +181,7 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -177,7 +181,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
if (ret) if (ret)
break; break;
assert(dc.state == DECODE_STATE_START); assert(dc->state == DECODE_STATE_START);
} }
} }
/* fallback to mp3: */ /* fallback to mp3: */
...@@ -196,9 +200,9 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -196,9 +200,9 @@ static void decoder_run_song(const struct song *song, const char *uri)
const char *s = uri_get_suffix(uri); const char *s = uri_get_suffix(uri);
while ((plugin = decoder_plugin_from_suffix(s, next++))) { while ((plugin = decoder_plugin_from_suffix(s, next++))) {
if (plugin->file_decode != NULL) { if (plugin->file_decode != NULL) {
decoder_unlock(); decoder_unlock(dc);
input_stream_close(&input_stream); input_stream_close(&input_stream);
decoder_lock(); decoder_lock(dc);
close_instream = false; close_instream = false;
ret = decoder_file_decode(plugin, ret = decoder_file_decode(plugin,
...@@ -213,9 +217,9 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -213,9 +217,9 @@ static void decoder_run_song(const struct song *song, const char *uri)
reopen it */ reopen it */
bool success; bool success;
decoder_unlock(); decoder_unlock(dc);
success = input_stream_open(&input_stream, uri); success = input_stream_open(&input_stream, uri);
decoder_lock(); decoder_lock(dc);
if (success) if (success)
close_instream = true; close_instream = true;
...@@ -231,7 +235,7 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -231,7 +235,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
} }
} }
decoder_unlock(); decoder_unlock(dc);
pcm_convert_deinit(&decoder.conv_state); pcm_convert_deinit(&decoder.conv_state);
...@@ -251,14 +255,15 @@ static void decoder_run_song(const struct song *song, const char *uri) ...@@ -251,14 +255,15 @@ static void decoder_run_song(const struct song *song, const char *uri)
if (decoder.decoder_tag != NULL) if (decoder.decoder_tag != NULL)
tag_free(decoder.decoder_tag); tag_free(decoder.decoder_tag);
decoder_lock(); decoder_lock(dc);
dc.state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR; dc->state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR;
} }
static void decoder_run(void) static void
decoder_run(struct decoder_control *dc)
{ {
struct song *song = dc.next_song; struct song *song = dc->next_song;
char *uri; char *uri;
if (song_is_file(song)) if (song_is_file(song))
...@@ -267,58 +272,62 @@ static void decoder_run(void) ...@@ -267,58 +272,62 @@ static void decoder_run(void)
uri = song_get_uri(song); uri = song_get_uri(song);
if (uri == NULL) { if (uri == NULL) {
dc.state = DECODE_STATE_ERROR; dc->state = DECODE_STATE_ERROR;
return; return;
} }
dc.current_song = dc.next_song; /* NEED LOCK */ dc->current_song = dc->next_song; /* NEED LOCK */
decoder_run_song(song, uri); decoder_run_song(dc, song, uri);
g_free(uri); g_free(uri);
} }
static gpointer decoder_task(G_GNUC_UNUSED gpointer arg) static gpointer
decoder_task(gpointer arg)
{ {
decoder_lock(); struct decoder_control *dc = arg;
decoder_lock(dc);
do { do {
assert(dc.state == DECODE_STATE_STOP || assert(dc->state == DECODE_STATE_STOP ||
dc.state == DECODE_STATE_ERROR); dc->state == DECODE_STATE_ERROR);
switch (dc.command) { switch (dc->command) {
case DECODE_COMMAND_START: case DECODE_COMMAND_START:
case DECODE_COMMAND_SEEK: case DECODE_COMMAND_SEEK:
decoder_run(); decoder_run(dc);
dc.command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
player_signal(); player_signal();
break; break;
case DECODE_COMMAND_STOP: case DECODE_COMMAND_STOP:
dc.command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
player_signal(); player_signal();
break; break;
case DECODE_COMMAND_NONE: case DECODE_COMMAND_NONE:
decoder_wait(); decoder_wait(dc);
break; break;
} }
} while (dc.command != DECODE_COMMAND_NONE || !dc.quit); } while (dc->command != DECODE_COMMAND_NONE || !dc->quit);
decoder_unlock(); decoder_unlock(dc);
return NULL; return NULL;
} }
void decoder_thread_start(void) void
decoder_thread_start(struct decoder_control *dc)
{ {
GError *e = NULL; GError *e = NULL;
assert(dc.thread == NULL); assert(dc->thread == NULL);
dc.thread = g_thread_create(decoder_task, NULL, true, &e); dc->thread = g_thread_create(decoder_task, dc, true, &e);
if (dc.thread == NULL) if (dc->thread == NULL)
g_error("Failed to spawn decoder task: %s", e->message); g_error("Failed to spawn decoder task: %s", e->message);
} }
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#ifndef MPD_DECODER_THREAD_H #ifndef MPD_DECODER_THREAD_H
#define MPD_DECODER_THREAD_H #define MPD_DECODER_THREAD_H
void decoder_thread_start(void); struct decoder_control;
void
decoder_thread_start(struct decoder_control *dc);
#endif #endif
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "path.h" #include "path.h"
#include "mapper.h" #include "mapper.h"
#include "chunk.h" #include "chunk.h"
#include "decoder_control.h"
#include "player_control.h" #include "player_control.h"
#include "stats.h" #include "stats.h"
#include "sig_handlers.h" #include "sig_handlers.h"
...@@ -254,7 +253,6 @@ initialize_decoder_and_player(void) ...@@ -254,7 +253,6 @@ initialize_decoder_and_player(void)
buffered_before_play = buffered_chunks; buffered_before_play = buffered_chunks;
pc_init(buffered_chunks, buffered_before_play); pc_init(buffered_chunks, buffered_before_play);
dc_init();
} }
/** /**
...@@ -426,7 +424,6 @@ int main(int argc, char *argv[]) ...@@ -426,7 +424,6 @@ int main(int argc, char *argv[])
mapper_finish(); mapper_finish();
path_global_finish(); path_global_finish();
finishPermissions(); finishPermissions();
dc_deinit();
pc_deinit(); pc_deinit();
command_finish(); command_finish();
update_global_finish(); update_global_finish();
......
...@@ -53,11 +53,11 @@ void pc_deinit(void) ...@@ -53,11 +53,11 @@ void pc_deinit(void)
} }
void void
player_wait_decoder(void) player_wait_decoder(struct decoder_control *dc)
{ {
/* during this function, the decoder lock is held, because /* during this function, the decoder lock is held, because
we're waiting for the decoder thread */ we're waiting for the decoder thread */
g_cond_wait(pc.cond, dc.mutex); g_cond_wait(pc.cond, dc->mutex);
} }
void void
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <stdint.h> #include <stdint.h>
struct decoder_control;
enum player_state { enum player_state {
PLAYER_STATE_STOP = 0, PLAYER_STATE_STOP = 0,
PLAYER_STATE_PAUSE, PLAYER_STATE_PAUSE,
...@@ -155,7 +157,7 @@ player_wait(void) ...@@ -155,7 +157,7 @@ player_wait(void)
* Note the small difference to the player_wait() function! * Note the small difference to the player_wait() function!
*/ */
void void
player_wait_decoder(void); player_wait_decoder(struct decoder_control *dc);
/** /**
* Signals the #player_control object. The object should be locked * Signals the #player_control object. The object should be locked
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment