aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/player_thread.c176
1 files changed, 103 insertions, 73 deletions
diff --git a/src/player_thread.c b/src/player_thread.c
index f42b74a1f..9b9787261 100644
--- a/src/player_thread.c
+++ b/src/player_thread.c
@@ -79,6 +79,16 @@ struct player {
enum xfade_state xfade;
/**
+ * has cross-fading begun?
+ */
+ bool cross_fading;
+
+ /**
+ * The number of chunks used for crossfading.
+ */
+ unsigned cross_fade_chunks;
+
+ /**
* The current audio format for the audio outputs.
*/
struct audio_format play_audio_format;
@@ -364,6 +374,91 @@ play_chunk(struct song *song, struct music_chunk *chunk,
return true;
}
+/**
+ * Obtains the next chunk from the music pipe, optionally applies
+ * cross-fading, and sends it to all audio outputs.
+ *
+ * @return true on success, false on error (playback will be stopped)
+ */
+static bool
+play_next_chunk(struct player *player)
+{
+ struct music_chunk *chunk = NULL;
+ unsigned cross_fade_position;
+ bool success;
+
+ if (player->xfade == XFADE_ENABLED &&
+ dc.pipe != NULL && dc.pipe != player->pipe &&
+ (cross_fade_position = music_pipe_size(player->pipe))
+ <= player->cross_fade_chunks) {
+ /* perform cross fade */
+ struct music_chunk *other_chunk =
+ music_pipe_shift(dc.pipe);
+
+ if (!player->cross_fading) {
+ /* beginning of the cross fade
+ - adjust crossFadeChunks
+ which might be bigger than
+ the remaining number of
+ chunks in the old song */
+ player->cross_fade_chunks = cross_fade_position;
+ player->cross_fading = true;
+ }
+
+ if (other_chunk != NULL) {
+ chunk = music_pipe_shift(player->pipe);
+ assert(chunk != NULL);
+
+ cross_fade_apply(chunk, other_chunk,
+ &dc.out_audio_format,
+ cross_fade_position,
+ player->cross_fade_chunks);
+ music_buffer_return(player_buffer, other_chunk);
+ } else {
+ /* there are not enough
+ decoded chunks yet */
+ if (decoder_is_idle()) {
+ /* the decoder isn't
+ running, abort
+ cross fading */
+ player->xfade = XFADE_DISABLED;
+ } else {
+ /* wait for the
+ decoder */
+ notify_signal(&dc.notify);
+ notify_wait(&pc.notify);
+
+ return true;
+ }
+ }
+ }
+
+ if (chunk == NULL)
+ chunk = music_pipe_shift(player->pipe);
+
+ assert(chunk != NULL);
+
+ /* play the current chunk */
+
+ success = play_chunk(player->song, chunk, &player->play_audio_format,
+ player->size_to_time);
+ music_buffer_return(player_buffer, chunk);
+
+ if (!success)
+ return false;
+
+ /* this formula should prevent that the
+ decoder gets woken up with each chunk; it
+ is more efficient to make it decode a
+ larger block at a time */
+ if (!decoder_is_idle() &&
+ music_pipe_size(dc.pipe) <= (pc.buffered_before_play +
+ music_buffer_size(player_buffer) * 3) / 4)
+ notify_signal(&dc.notify);
+
+ return true;
+}
+
static void do_play(void)
{
struct player player = {
@@ -373,11 +468,10 @@ static void do_play(void)
.queued = false,
.song = NULL,
.xfade = XFADE_UNKNOWN,
+ .cross_fading = false,
+ .cross_fade_chunks = 0,
.size_to_time = 0.0,
};
- unsigned int crossFadeChunks = 0;
- /** has cross-fading begun? */
- bool cross_fading = false;
static const char silence[CHUNK_SIZE];
player.pipe = music_pipe_new();
@@ -452,15 +546,15 @@ static void do_play(void)
/* enable cross fading in this song? if yes,
calculate how many chunks will be required
for it */
- crossFadeChunks =
+ player.cross_fade_chunks =
cross_fade_calc(pc.cross_fade_seconds, dc.total_time,
&dc.out_audio_format,
&player.play_audio_format,
music_buffer_size(player_buffer) -
pc.buffered_before_play);
- if (crossFadeChunks > 0) {
+ if (player.cross_fade_chunks > 0) {
player.xfade = XFADE_ENABLED;
- cross_fading = false;
+ player.cross_fading = false;
} else
/* cross fading is disabled or the
next song is too short */
@@ -470,75 +564,11 @@ static void do_play(void)
if (player.paused)
notify_wait(&pc.notify);
else if (music_pipe_size(player.pipe) > 0) {
- struct music_chunk *chunk = NULL;
- unsigned int fadePosition;
- bool success;
-
- if (player.xfade == XFADE_ENABLED &&
- dc.pipe != NULL && dc.pipe != player.pipe &&
- (fadePosition = music_pipe_size(player.pipe))
- <= crossFadeChunks) {
- /* perform cross fade */
- struct music_chunk *other_chunk =
- music_pipe_shift(dc.pipe);
-
- if (!cross_fading) {
- /* beginning of the cross fade
- - adjust crossFadeChunks
- which might be bigger than
- the remaining number of
- chunks in the old song */
- crossFadeChunks = fadePosition;
- cross_fading = true;
- }
-
- if (other_chunk != NULL) {
- chunk = music_pipe_shift(player.pipe);
- cross_fade_apply(chunk, other_chunk,
- &dc.out_audio_format,
- fadePosition,
- crossFadeChunks);
- music_buffer_return(player_buffer, other_chunk);
- } else {
- /* there are not enough
- decoded chunks yet */
- if (decoder_is_idle()) {
- /* the decoder isn't
- running, abort
- cross fading */
- player.xfade = XFADE_DISABLED;
- } else {
- /* wait for the
- decoder */
- notify_signal(&dc.notify);
- notify_wait(&pc.notify);
-
- continue;
- }
- }
- }
-
- if (chunk == NULL)
- chunk = music_pipe_shift(player.pipe);
+ /* at least one music chunk is ready - send it
+ to the audio output */
- /* play the current chunk */
-
- success = play_chunk(player.song, chunk,
- &player.play_audio_format,
- player.size_to_time);
- music_buffer_return(player_buffer, chunk);
-
- if (!success)
+ if (!play_next_chunk(&player))
break;
-
- /* this formula should prevent that the
- decoder gets woken up with each chunk; it
- is more efficient to make it decode a
- larger block at a time */
- if (!decoder_is_idle() &&
- music_pipe_size(dc.pipe) <= (pc.buffered_before_play +
- music_buffer_size(player_buffer) * 3) / 4)
- notify_signal(&dc.notify);
} else if (dc.pipe != NULL && dc.pipe != player.pipe) {
/* at the beginning of a new song */