From 44d9f62f34e0561d83ea32941f0ea1b529b1490d Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 16 Aug 2008 09:28:15 -0700 Subject: core rewrite (decode,player,outputBuffer,playlist) This is a huge refactoring of the core mpd process. The queueing/buffering mechanism is heavily reworked. The player.c code has been merged into outputBuffer (the actual ring buffering logic is handled by ringbuf.c); and decode.c actually handles decoding stuff. The end result is several hundreds of lines shorter, even though we still have a lot of DEBUG statements left in there for tracing and a lot of assertions, too. --- src/decode.c | 666 ++++++++++++++++++----------------------------------------- 1 file changed, 203 insertions(+), 463 deletions(-) (limited to 'src/decode.c') diff --git a/src/decode.c b/src/decode.c index 6b57239e3..12c1b8746 100644 --- a/src/decode.c +++ b/src/decode.c @@ -17,241 +17,210 @@ */ #include "decode.h" - -#include "player.h" +#include "outputBuffer.h" +#include "player_error.h" +#include "playlist.h" #include "playerData.h" #include "pcm_utils.h" #include "path.h" #include "log.h" #include "ls.h" -#include "main_notify.h" +#include "condition.h" -enum xfade_state { - XFADE_DISABLED = -1, - XFADE_UNKNOWN = 0, - XFADE_ENABLED = 1 -}; +static struct condition dc_action_cond = STATIC_COND_INITIALIZER; +static struct condition dc_halt_cond = STATIC_COND_INITIALIZER; -/* called inside decoder_task (inputPlugins) */ -void decoder_wakeup_player(void) -{ - wakeup_player_nb(); -} +struct decoder_control dc; /* ugh, global for now... */ -void decoder_sleep(void) +/* blocking, waits until the signaled thread has replied */ +void dc_trigger_action(enum dc_action action, float seek_where) { - notify_wait(&dc.notify); - wakeup_player_nb(); + assert(!pthread_equal(pthread_self(), dc.thread)); + /* assert(pthread_equal(pthread_self(), main_thread)); */ + assert(action != DC_ACTION_NONE); + + /* DEBUG(__FILE__ ":%s %d\n", __func__,__LINE__); */ + cond_enter(&dc_action_cond); + assert(dc.action == DC_ACTION_NONE); + if (action == DC_ACTION_SEEK) + dc.seek_where = seek_where; /* usually 0 */ + dc.action = action; + do { + /* DEBUG(__FILE__ ":%s %d\n", __func__,__LINE__); */ + cond_signal(&dc_halt_cond); /* blind signal w/o lock */ + /* DEBUG(__FILE__ ":%s %d\n", __func__,__LINE__); */ + cond_timedwait(&dc_action_cond, 10); + /* DEBUG(__FILE__ ":%s %d\n", __func__,__LINE__); */ + } while (dc.action != DC_ACTION_NONE); /* spurious wakeup protection */ + /* DEBUG(__FILE__ ":%s %d\n", __func__,__LINE__); */ + cond_leave(&dc_action_cond); + /* DEBUG(__FILE__ ":%s %d\n", __func__,__LINE__); */ } -static void player_wakeup_decoder_nb(void) +static void take_action(void) { - notify_signal(&dc.notify); + assert(pthread_equal(pthread_self(), dc.thread)); + assert(dc.state == DC_STATE_STOP); + /* DEBUG("%s dc.action(%d): %d\n", __func__,__LINE__, dc.action); */ + cond_enter(&dc_action_cond); + /* DEBUG("%s dc.action(%d): %d\n", __func__,__LINE__, dc.action); */ + + switch (dc.action) { + case DC_ACTION_NONE: goto out; + case DC_ACTION_START: + case DC_ACTION_SEEK: + dc.state = DC_STATE_DECODE; + return; + case DC_ACTION_STOP: dc.state = DC_STATE_STOP; break; + case DC_ACTION_QUIT: dc.state = DC_STATE_QUIT; + } + dc.action = DC_ACTION_NONE; + cond_signal(&dc_action_cond); +out: + assert(dc.action == DC_ACTION_NONE); + cond_leave(&dc_action_cond); } -/* called from player_task */ -static void player_wakeup_decoder(void) +/* + * This will grab an action, but will not signal the calling thread. + * dc_action_end() is required to signal the calling thread + */ +void dc_action_begin(void) { - notify_signal(&dc.notify); - player_sleep(); -} + enum dc_action ret = dc.action; -static void stopDecode(void) -{ - if (dc.start || dc.state != DECODE_STATE_STOP) { - dc.stop = 1; - do { player_wakeup_decoder_nb(); } while (dc.stop); + assert(pthread_equal(pthread_self(), dc.thread)); + + if (ret != DC_ACTION_NONE) { + /* DEBUG(__FILE__ ":%s %d\n", __func__,__LINE__); */ + cond_enter(&dc_action_cond); + /* dc.action can't get set to NONE outside this thread */ + assert(dc.action == ret); + if (ret == DC_ACTION_SEEK) + ob_seek_start(); } } -static void quitDecode(void) +void dc_action_end(void) { - stopDecode(); - pc.state = PLAYER_STATE_STOP; - dc.seek = 0; - pc.play = 0; - pc.stop = 0; - pc.pause = 0; - wakeup_main_task(); + assert(pthread_equal(pthread_self(), dc.thread)); + assert(dc.action != DC_ACTION_NONE); + /* DEBUG("DONE ACTION %d\n", dc.action); */ + if (dc.action == DC_ACTION_SEEK) + ob_seek_finish(); + dc.action = DC_ACTION_NONE; + + cond_signal(&dc_action_cond); + cond_leave(&dc_action_cond); } -static unsigned calculateCrossFadeChunks(AudioFormat * af, float totalTime) +void dc_action_seek_fail(enum seek_err_type err_type) { - unsigned int buffered_chunks, chunks; - - if (pc.crossFade == 0 || pc.crossFade >= totalTime || - !isCurrentAudioFormat(af)) - return 0; - - assert(pc.crossFade > 0); - assert(af->bits > 0); - assert(af->channels > 0); - assert(af->sampleRate > 0); - - chunks = (af->sampleRate * af->bits * af->channels / 8.0 / CHUNK_SIZE); - chunks = (chunks * pc.crossFade + 0.5); - - buffered_chunks = ob.size; - assert(buffered_chunks >= buffered_before_play); - if (chunks > (buffered_chunks - buffered_before_play)) - chunks = buffered_chunks - buffered_before_play; - - return chunks; + assert(pthread_equal(pthread_self(), dc.thread)); + cond_enter(&dc_action_cond); + assert(dc.action == DC_ACTION_SEEK); + dc.action = DC_ACTION_NONE; + dc.seek_where = err_type; + cond_signal(&dc_action_cond); + cond_leave(&dc_action_cond); } -static int waitOnDecode(int *decodeWaitedOn) +/* Returns true if we need to interrupt the decoding inside an inputPlugin */ +int dc_intr(void) { - while (dc.start) - player_wakeup_decoder(); - - if (dc.error != DECODE_ERROR_NOERROR) { - pc.errored_song = pc.current_song; - pc.error = PLAYER_ERROR_FILE; - quitDecode(); - return -1; + if (!pthread_equal(pthread_self(), dc.thread)) + return 0; + switch (dc.action) { + case DC_ACTION_NONE: + case DC_ACTION_SEEK: + return 0; + default: + /* DEBUG(__FILE__": %s %d\n", __func__, __LINE__); */ + /* DEBUG("dc.action: %d\n", (int)dc.action); */ + return 1; } - - pc.totalTime = pc.fileTime; - pc.bitRate = 0; - pc.sampleRate = 0; - pc.bits = 0; - pc.channels = 0; - *decodeWaitedOn = 1; - - return 0; } -static int decodeSeek(int *decodeWaitedOn, int *next) +int dc_seek(void) { - int ret = -1; - - if (dc.state == DECODE_STATE_STOP || - dc.error != DECODE_ERROR_NOERROR || - dc.current_song != pc.current_song) { - stopDecode(); - *next = -1; - ob_clear(); - dc.error = DECODE_ERROR_NOERROR; - dc.start = 1; - waitOnDecode(decodeWaitedOn); - } - if (dc.state != DECODE_STATE_STOP && dc.seekable) { - *next = -1; - dc.seekWhere = pc.seekWhere > pc.totalTime - 0.1 ? - pc.totalTime - 0.1 : pc.seekWhere; - dc.seekWhere = 0 > dc.seekWhere ? 0 : dc.seekWhere; - dc.seekError = 0; - dc.seek = 1; - do { player_wakeup_decoder(); } while (dc.seek); - if (!dc.seekError) { - pc.elapsedTime = dc.seekWhere; - ret = 0; - } - } - pc.seek = 0; - wakeup_main_task(); - - return ret; + if (pthread_equal(pthread_self(), dc.thread)) + return (dc.action == DC_ACTION_SEEK); + return 0; } -static void processDecodeInput(int *pause_r, unsigned int *bbp_r, - enum xfade_state *do_xfade_r, - int *decodeWaitedOn_r, - int *next_r) +static void finalize_per_track_actions(void) { - if(pc.lockQueue) { - pc.queueLockState = PLAYER_QUEUE_LOCKED; - pc.lockQueue = 0; - wakeup_main_task(); - } - if(pc.unlockQueue) { - pc.queueLockState = PLAYER_QUEUE_UNLOCKED; - pc.unlockQueue = 0; - wakeup_main_task(); - } - if(pc.pause) { - *pause_r = !*pause_r; - if (*pause_r) { - pc.state = PLAYER_STATE_PAUSE; - } else { - if (openAudioDevice(NULL) >= 0) { - pc.state = PLAYER_STATE_PLAY; - } else { - char tmp[MPD_PATH_MAX]; - pc.errored_song = pc.current_song; - pc.error = PLAYER_ERROR_AUDIO; - ERROR("problems opening audio device " - "while playing \"%s\"\n", - get_song_url(tmp, pc.current_song)); - *pause_r = -1; - } - } - pc.pause = 0; - wakeup_main_task(); - if (*pause_r == -1) { - *pause_r = 1; - } else if (*pause_r) { - dropBufferedAudio(); - closeAudioDevice(); - } - } - if(pc.seek) { - dropBufferedAudio(); - if (decodeSeek(decodeWaitedOn_r, next_r) == 0) { - *do_xfade_r = XFADE_UNKNOWN; - *bbp_r = 0; - } + enum dc_action action; + /* DEBUG(":%s dc.action(%d): %d\n", __func__,__LINE__, dc.action); */ + assert(pthread_equal(pthread_self(), dc.thread)); + cond_enter(&dc_action_cond); + dc.state = DC_STATE_STOP; + action = dc.action; + dc.action = DC_ACTION_NONE; + + if (action == DC_ACTION_STOP) { + cond_signal(&dc_action_cond); + } else if (action == DC_ACTION_SEEK) { + dc.seek_where = DC_SEEK_MISMATCH; + cond_signal(&dc_action_cond); } + cond_leave(&dc_action_cond); + /* DEBUG(":%s dc.action(%d): %d\n", __func__,__LINE__, dc.action); */ } -static void decodeStart(void) +static void decode_start(void) { - int ret; + int err = -1; int close_instream = 1; - InputStream inStream; + InputStream is; InputPlugin *plugin = NULL; char path_max_fs[MPD_PATH_MAX]; char path_max_utf8[MPD_PATH_MAX]; - - if (!get_song_url(path_max_utf8, pc.current_song)) { - dc.error = DECODE_ERROR_FILE; - goto stop_no_close; + assert(pthread_equal(pthread_self(), dc.thread)); + assert(dc.state == DC_STATE_DECODE); + assert(dc.current_song); + get_song_url(path_max_utf8, dc.current_song); + assert(*path_max_utf8); + + switch (dc.action) { + case DC_ACTION_START: + dc_action_end(); + break; + case DC_ACTION_SEEK: + /* DEBUG("dc.seek_where(%d): %f\n", __LINE__, dc.seek_where); */ + /* make sure dc_action_start() works inside inputPlugins: */ + cond_leave(&dc_action_cond); + /* DEBUG("dc.action(%d) %d\n", __LINE__, dc.action); */ + break; + default: assert("unknown action!" && 0); } - if (!isRemoteUrl(path_max_utf8)) { + + if (isRemoteUrl(path_max_utf8)) { + pathcpy_trunc(path_max_fs, path_max_utf8); + } else { rmp2amp_r(path_max_fs, utf8_to_fs_charset(path_max_fs, path_max_utf8)); - } else - pathcpy_trunc(path_max_fs, path_max_utf8); - - dc.current_song = pc.current_song; /* NEED LOCK */ - if (openInputStream(&inStream, path_max_fs) < 0) { - dc.error = DECODE_ERROR_FILE; - goto stop_no_close; } - dc.state = DECODE_STATE_START; - dc.start = 0; - - /* for http streams, seekable is determined in bufferInputStream */ - dc.seekable = inStream.seekable; - - if (dc.stop) - goto stop; + if (openInputStream(&is, path_max_fs) < 0) { + DEBUG("couldn't open song: %s\n", path_max_fs); + player_seterror(PLAYER_ERROR_FILENOTFOUND, dc.current_song); + return; + } - ret = DECODE_ERROR_UNKTYPE; if (isRemoteUrl(path_max_utf8)) { unsigned int next = 0; /* first we try mime types: */ - while (ret && (plugin = getInputPluginFromMimeType(inStream.mime, next++))) { + while (err && (plugin = getInputPluginFromMimeType(is.mime, next++))) { if (!plugin->streamDecodeFunc) continue; if (!(plugin->streamTypes & INPUT_PLUGIN_STREAM_URL)) continue; if (plugin->tryDecodeFunc - && !plugin->tryDecodeFunc(&inStream)) + && !plugin->tryDecodeFunc(&is)) continue; - ret = plugin->streamDecodeFunc(&inStream); + err = plugin->streamDecodeFunc(&is); break; } @@ -259,16 +228,16 @@ static void decodeStart(void) if (plugin == NULL) { const char *s = getSuffix(path_max_utf8); next = 0; - while (ret && (plugin = getInputPluginFromSuffix(s, next++))) { + while (err && (plugin = getInputPluginFromSuffix(s, next++))) { if (!plugin->streamDecodeFunc) continue; if (!(plugin->streamTypes & INPUT_PLUGIN_STREAM_URL)) continue; if (plugin->tryDecodeFunc && - !plugin->tryDecodeFunc(&inStream)) + !plugin->tryDecodeFunc(&is)) continue; - ret = plugin->streamDecodeFunc(&inStream); + err = plugin->streamDecodeFunc(&is); break; } } @@ -278,330 +247,101 @@ static void decodeStart(void) if (plugin == NULL) { /* we already know our mp3Plugin supports streams, no * need to check for stream{Types,DecodeFunc} */ - if ((plugin = getInputPluginFromName("mp3"))) { - ret = plugin->streamDecodeFunc(&inStream); - } + if ((plugin = getInputPluginFromName("mp3"))) + err = plugin->streamDecodeFunc(&is); } } else { unsigned int next = 0; const char *s = getSuffix(path_max_utf8); - while (ret && (plugin = getInputPluginFromSuffix(s, next++))) { + while (err && (plugin = getInputPluginFromSuffix(s, next++))) { if (!plugin->streamTypes & INPUT_PLUGIN_STREAM_FILE) continue; if (plugin->tryDecodeFunc && - !plugin->tryDecodeFunc(&inStream)) + !plugin->tryDecodeFunc(&is)) continue; if (plugin->fileDecodeFunc) { - closeInputStream(&inStream); + closeInputStream(&is); close_instream = 0; - ret = plugin->fileDecodeFunc(path_max_fs); + err = plugin->fileDecodeFunc(path_max_fs); break; } else if (plugin->streamDecodeFunc) { - ret = plugin->streamDecodeFunc(&inStream); + err = plugin->streamDecodeFunc(&is); break; } } } - if (ret < 0 || ret == DECODE_ERROR_UNKTYPE) { - pc.errored_song = pc.current_song; - if (ret != DECODE_ERROR_UNKTYPE) - dc.error = DECODE_ERROR_FILE; + if (err) { + if (plugin) + player_seterror(PLAYER_ERROR_SYSTEM, dc.current_song); else - dc.error = DECODE_ERROR_UNKTYPE; + player_seterror(PLAYER_ERROR_UNKTYPE, dc.current_song); } - -stop: + if (player_errno) + ERROR("player_error: %s\n", player_strerror()); if (close_instream) - closeInputStream(&inStream); -stop_no_close: - dc.state = DECODE_STATE_STOP; - dc.stop = 0; + closeInputStream(&is); } static void * decoder_task(mpd_unused void *arg) { - notify_enter(&dc.notify); - + assert(pthread_equal(pthread_self(), dc.thread)); + cond_enter(&dc_halt_cond); while (1) { - assert(dc.state == DECODE_STATE_STOP); - - if (dc.start || dc.seek) { - decodeStart(); - } else if (dc.stop) { - dc.stop = 0; - decoder_wakeup_player(); - } else { - decoder_sleep(); + take_action(); + switch (dc.state) { + case DC_STATE_STOP: + /* DEBUG(__FILE__": halted %d\n", __LINE__); */ + cond_wait(&dc_halt_cond); + /* DEBUG(__FILE__": unhalted %d\n", __LINE__); */ + break; + case DC_STATE_DECODE: + /* DEBUG(__FILE__": %s %d\n", __func__, __LINE__); */ + /* DEBUG("dc.action: %d\n", (int)dc.action); */ + if ((dc.current_song = playlist_queued_song())) { + char p[MPD_PATH_MAX]; + ob_advance_sequence(); + get_song_url(p, dc.current_song); + DEBUG("decoding song: %s\n", p); + decode_start(); + DEBUG("DONE decoding song: %s\n", p); + ob_flush(); + dc.current_song = NULL; + } + finalize_per_track_actions(); + playlist_queue_next(); + break; + case DC_STATE_QUIT: + goto out; } } - +out: + cond_leave(&dc_halt_cond); + assert(dc.state == DC_STATE_QUIT); return NULL; } -void decoderInit(void) +void decoder_init(void) { pthread_attr_t attr; - pthread_t decoder_thread; + assert(!dc.thread); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (pthread_create(&decoder_thread, &attr, decoder_task, NULL)) + if (pthread_create(&dc.thread, &attr, decoder_task, NULL)) FATAL("Failed to spawn decoder task: %s\n", strerror(errno)); } -static void crossFade(ob_chunk * a, ob_chunk * b, - AudioFormat * format, - unsigned int fadePosition, unsigned int crossFadeChunks) +int dc_try_unhalt(void) { - assert(fadePosition <= crossFadeChunks); - - pcm_mix(a->data, - b->data, - a->chunkSize, - b->chunkSize, - format, - ((float)fadePosition) / - crossFadeChunks); - if (b->chunkSize > a->chunkSize) - a->chunkSize = b->chunkSize; + assert(!pthread_equal(pthread_self(), dc.thread)); + return cond_signal_trysync(&dc_halt_cond); } -static int playChunk(ob_chunk * chunk, - const AudioFormat * format, double sizeToTime) +void dc_halt(void) { - pc.elapsedTime = chunk->times; - pc.bitRate = chunk->bitRate; - - pcm_volumeChange(chunk->data, chunk->chunkSize, - format, pc.softwareVolume); - - if (playAudio(chunk->data, - chunk->chunkSize) < 0) - return -1; - - pc.totalPlayTime += sizeToTime * chunk->chunkSize; - return 0; -} - -static void decodeParent(void) -{ - int do_pause = 0; - int buffering = 1; - unsigned int bbp = buffered_before_play; - enum xfade_state do_xfade = XFADE_UNKNOWN; - unsigned int crossFadeChunks = 0; - /** the position of the next cross-faded chunk in the next - song */ - int nextChunk = 0; - int decodeWaitedOn = 0; - static const char silence[CHUNK_SIZE]; - double sizeToTime = 0.0; - /** the position of the first chunk in the next song */ - int next = -1; - - ob_set_lazy(0); - - if (waitOnDecode(&decodeWaitedOn) < 0) - return; - - pc.elapsedTime = 0; - pc.state = PLAYER_STATE_PLAY; - pc.play = 0; - wakeup_main_task(); - - while (1) { - processDecodeInput(&do_pause, &bbp, &do_xfade, - &decodeWaitedOn, &next); - if (pc.stop) { - dropBufferedAudio(); - break; - } - - if (buffering) { - if (ob_available() < bbp) { - /* not enough decoded buffer space yet */ - player_sleep(); - continue; - } else { - /* buffering is complete */ - buffering = 0; - ob_set_lazy(1); - } - } - - if (decodeWaitedOn) { - if(dc.state!=DECODE_STATE_START && - dc.error==DECODE_ERROR_NOERROR) { - /* the decoder is ready and ok */ - decodeWaitedOn = 0; - if(openAudioDevice(&(ob.audioFormat))<0) { - char tmp[MPD_PATH_MAX]; - pc.errored_song = pc.current_song; - pc.error = PLAYER_ERROR_AUDIO; - ERROR("problems opening audio device " - "while playing \"%s\"\n", - get_song_url(tmp, pc.current_song)); - break; - } else { - player_wakeup_decoder(); - } - if (do_pause) { - dropBufferedAudio(); - closeAudioDevice(); - } - pc.totalTime = dc.totalTime; - pc.sampleRate = dc.audioFormat.sampleRate; - pc.bits = dc.audioFormat.bits; - pc.channels = dc.audioFormat.channels; - sizeToTime = audioFormatSizeToTime(&ob.audioFormat); - } - else if(dc.state!=DECODE_STATE_START) { - /* the decoder failed */ - pc.errored_song = pc.current_song; - pc.error = PLAYER_ERROR_FILE; - break; - } - else { - /* the decoder is not yet ready; wait - some more */ - player_sleep(); - continue; - } - } - - if (dc.state == DECODE_STATE_STOP && - pc.queueState == PLAYER_QUEUE_FULL && - pc.queueLockState == PLAYER_QUEUE_UNLOCKED) { - /* the decoder has finished the current song; - make it decode the next song */ - next = ob.end; - dc.start = 1; - pc.queueState = PLAYER_QUEUE_DECODE; - wakeup_main_task(); - player_wakeup_decoder_nb(); - } - if (next >= 0 && do_xfade == XFADE_UNKNOWN && !dc.start && - dc.state != DECODE_STATE_START) { - /* enable cross fading in this song? if yes, - calculate how many chunks will be required - for it */ - crossFadeChunks = - calculateCrossFadeChunks(&(ob.audioFormat), - dc.totalTime); - if (crossFadeChunks > 0) { - do_xfade = XFADE_ENABLED; - nextChunk = -1; - } else - /* cross fading is disabled or the - next song is too short */ - do_xfade = XFADE_DISABLED; - } - - if (do_pause) - player_sleep(); - else if (!ob_is_empty() && (int)ob.begin != next) { - ob_chunk *beginChunk = ob_get_chunk(ob.begin); - unsigned int fadePosition; - if (do_xfade == XFADE_ENABLED && next >= 0 && - (fadePosition = ob_relative(next)) - <= crossFadeChunks) { - /* perform cross fade */ - if (nextChunk < 0) { - /* beginning of the cross fade - - adjust crossFadeChunks - which might be bigger than - the remaining number of - chunks in the old song */ - crossFadeChunks = fadePosition; - } - nextChunk = ob_absolute(crossFadeChunks); - if (nextChunk >= 0) { - ob_set_lazy(1); - crossFade(beginChunk, - ob_get_chunk(nextChunk), - &(ob.audioFormat), - fadePosition, - crossFadeChunks); - } else { - /* there are not enough - decoded chunks yet */ - if (dc.state == DECODE_STATE_STOP) { - /* the decoder isn't - running, abort - cross fading */ - do_xfade = XFADE_DISABLED; - } else { - /* wait for the - decoder */ - ob_set_lazy(0); - player_sleep(); - continue; - } - } - } - - /* play the current chunk */ - if (playChunk(beginChunk, &(ob.audioFormat), - sizeToTime) < 0) - break; - ob_shift(); - player_wakeup_decoder_nb(); - } else if (!ob_is_empty() && (int)ob.begin == next) { - /* at the beginning of a new song */ - - if (do_xfade == XFADE_ENABLED && nextChunk >= 0) { - /* the cross-fade is finished; skip - the section which was cross-faded - (and thus already played) */ - ob_skip(crossFadeChunks); - } - - do_xfade = XFADE_UNKNOWN; - - /* wait for the decoder to work on the new song */ - if (pc.queueState == PLAYER_QUEUE_DECODE || - pc.queueLockState == PLAYER_QUEUE_LOCKED) { - player_sleep(); - continue; - } - if (pc.queueState != PLAYER_QUEUE_PLAY) - break; - - next = -1; - if (waitOnDecode(&decodeWaitedOn) < 0) - return; - - pc.queueState = PLAYER_QUEUE_EMPTY; - wakeup_main_task(); - } else if (dc.state == DECODE_STATE_STOP && !dc.start) { - break; - } else { - /*DEBUG("waiting for decoded audio, play silence\n");*/ - if (playAudio(silence, CHUNK_SIZE) < 0) - break; - } - } - - quitDecode(); -} - -/* decode w/ buffering - * this will fork another process - * child process does decoding - * parent process does playing audio - */ -void decode(void) -{ - ob_clear(); - - dc.error = DECODE_ERROR_NOERROR; - dc.seek = 0; - dc.stop = 0; - dc.start = 1; - do { player_wakeup_decoder(); } while (dc.start); - - decodeParent(); + assert(pthread_equal(pthread_self(), dc.thread)); + cond_wait(&dc_halt_cond); } -- cgit v1.2.3 From 548385ac6cc0bc344762e19117f94258e7ea2251 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 19 Aug 2008 03:31:25 -0700 Subject: fix output buffer deadlock when daemonizing We spawned the output buffer thread before daemonizing in initPlayerData(), which is ultra bad because daemonizes forks and threads are not preserved on exit. Since playerData has been stripped bare by this core-rewrite anyways, move this code into the outputBuffer_* group and drop playerData.[ch] completely I completely forgot to test this :< --- src/decode.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/decode.c') diff --git a/src/decode.c b/src/decode.c index 12c1b8746..150a0a58b 100644 --- a/src/decode.c +++ b/src/decode.c @@ -20,7 +20,6 @@ #include "outputBuffer.h" #include "player_error.h" #include "playlist.h" -#include "playerData.h" #include "pcm_utils.h" #include "path.h" #include "log.h" -- cgit v1.2.3