aboutsummaryrefslogtreecommitdiffstats
path: root/src/decode.c
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2008-08-16 09:28:15 -0700
committerEric Wong <normalperson@yhbt.net>2008-08-16 09:39:32 -0700
commit44d9f62f34e0561d83ea32941f0ea1b529b1490d (patch)
tree5345eba046b6e3bcf8c063e7bae8b501b7a99f4a /src/decode.c
parentf9f70860622613686e6ac0bf7ebd448f437d92a7 (diff)
downloadmpd-44d9f62f34e0561d83ea32941f0ea1b529b1490d.tar.gz
mpd-44d9f62f34e0561d83ea32941f0ea1b529b1490d.tar.xz
mpd-44d9f62f34e0561d83ea32941f0ea1b529b1490d.zip
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.
Diffstat (limited to 'src/decode.c')
-rw-r--r--src/decode.c666
1 files changed, 203 insertions, 463 deletions
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);
}