diff options
Diffstat (limited to 'src/player_thread.c')
-rw-r--r-- | src/player_thread.c | 113 |
1 files changed, 60 insertions, 53 deletions
diff --git a/src/player_thread.c b/src/player_thread.c index 7fc55d3d1..b501937b6 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -93,12 +93,6 @@ struct player { * The current audio format for the audio outputs. */ struct audio_format play_audio_format; - - /** - * Coefficient for converting a PCM buffer size into a time - * span. - */ - double size_to_time; }; static struct music_buffer *player_buffer; @@ -141,7 +135,7 @@ player_wait_for_decoder(struct player *player) { dc_command_wait(&pc.notify); - if (decoder_has_failed()) { + if (decoder_lock_has_failed()) { assert(dc.next_song == NULL || dc.next_song->url != NULL); pc.errored_song = dc.next_song; pc.error = PLAYER_ERROR_FILE; @@ -180,10 +174,14 @@ player_check_decoder_startup(struct player *player) { assert(player->decoder_starting); + decoder_lock(); + if (decoder_has_failed()) { /* the decoder failed */ assert(dc.next_song == NULL || dc.next_song->url != NULL); + decoder_unlock(); + pc.errored_song = dc.next_song; pc.error = PLAYER_ERROR_FILE; @@ -191,6 +189,8 @@ player_check_decoder_startup(struct player *player) } else if (!decoder_is_starting()) { /* the decoder is ready and ok */ + decoder_unlock(); + if (audio_format_defined(&player->play_audio_format) && !audio_output_all_wait(1)) /* the output devices havn't finished playing @@ -200,8 +200,6 @@ player_check_decoder_startup(struct player *player) pc.total_time = dc.total_time; pc.audio_format = dc.in_audio_format; player->play_audio_format = dc.out_audio_format; - player->size_to_time = - audioFormatSizeToTime(&dc.out_audio_format); player->decoder_starting = false; if (!player->paused && @@ -227,6 +225,7 @@ player_check_decoder_startup(struct player *player) } else { /* the decoder is not yet ready; wait some more */ + decoder_unlock(); notify_wait(&pc.notify); return true; @@ -414,6 +413,31 @@ static void player_process_command(struct player *player) } } +static void +update_song_tag(struct song *song, const struct tag *new_tag) +{ + struct tag *old_tag; + + if (song_is_file(song)) + /* don't update tags of local files, only remote + streams may change tags dynamically */ + return; + + old_tag = song->tag; + song->tag = tag_dup(new_tag); + + if (old_tag != NULL) + tag_free(old_tag); + + /* the main thread will update the playlist version when he + receives this event */ + event_pipe_emit(PIPE_EVENT_TAG); + + /* notify all clients that the tag of the current song has + changed */ + idle_add(IDLE_PLAYER); +} + /** * Plays a #music_chunk object (after applying software volume). If * it contains a (stream) tag, copy it to the current song, so MPD's @@ -421,31 +445,12 @@ static void player_process_command(struct player *player) */ static bool play_chunk(struct song *song, struct music_chunk *chunk, - const struct audio_format *format, double sizeToTime) + const struct audio_format *format) { - bool success; - assert(music_chunk_check_format(chunk, format)); - if (chunk->tag != NULL) { - if (!song_is_file(song)) { - /* always update the tag of remote streams */ - struct tag *old_tag = song->tag; - - song->tag = tag_dup(chunk->tag); - - if (old_tag != NULL) - tag_free(old_tag); - - /* the main thread will update the playlist - version when he receives this event */ - event_pipe_emit(PIPE_EVENT_TAG); - - /* notify all clients that the tag of the - current song has changed */ - idle_add(IDLE_PLAYER); - } - } + if (chunk->tag != NULL) + update_song_tag(song, chunk->tag); if (chunk->length == 0) { music_buffer_return(player_buffer, chunk); @@ -455,18 +460,6 @@ play_chunk(struct song *song, struct music_chunk *chunk, pc.elapsed_time = chunk->times; pc.bit_rate = chunk->bit_rate; - /* apply software volume */ - - success = pcm_volume(chunk->data, chunk->length, - format, pc.software_volume); - if (!success) { - g_warning("pcm_volume() failed on %u:%u:%u", - format->sample_rate, format->bits, format->channels); - pc.errored_song = dc.current_song; - pc.error = PLAYER_ERROR_AUDIO; - return false; - } - /* send the chunk to the audio outputs */ if (!audio_output_all_play(chunk)) { @@ -475,7 +468,8 @@ play_chunk(struct song *song, struct music_chunk *chunk, return false; } - pc.total_play_time += sizeToTime * chunk->length; + pc.total_play_time += (double)chunk->length / + audio_format_time_to_size(format); return true; } @@ -525,13 +519,20 @@ play_next_chunk(struct player *player) music_buffer_return(player_buffer, other_chunk); } else { /* there are not enough decoded chunks yet */ + + decoder_lock(); + if (decoder_is_idle()) { /* the decoder isn't running, abort cross fading */ + decoder_unlock(); + player->xfade = XFADE_DISABLED; } else { /* wait for the decoder */ - notify_signal(&dc.notify); + decoder_signal(); + decoder_unlock(); + notify_wait(&pc.notify); return true; @@ -546,8 +547,7 @@ play_next_chunk(struct player *player) /* play the current chunk */ - success = play_chunk(player->song, chunk, &player->play_audio_format, - player->size_to_time); + success = play_chunk(player->song, chunk, &player->play_audio_format); if (!success) { music_buffer_return(player_buffer, chunk); @@ -563,10 +563,12 @@ play_next_chunk(struct player *player) /* 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 */ + decoder_lock(); if (!decoder_is_idle() && music_pipe_size(dc.pipe) <= (pc.buffered_before_play + music_buffer_size(player_buffer) * 3) / 4) - notify_signal(&dc.notify); + decoder_signal(); + decoder_unlock(); return true; } @@ -581,8 +583,14 @@ play_next_chunk(struct player *player) static bool player_song_border(struct player *player) { + char *uri; + player->xfade = XFADE_UNKNOWN; + uri = song_get_uri(player->song); + g_message("played \"%s\"", uri); + g_free(uri); + music_pipe_free(player->pipe); player->pipe = dc.pipe; @@ -608,7 +616,6 @@ static void do_play(void) .xfade = XFADE_UNKNOWN, .cross_fading = false, .cross_fade_chunks = 0, - .size_to_time = 0.0, }; player.pipe = music_pipe_new(); @@ -643,7 +650,7 @@ static void do_play(void) prevent stuttering on slow machines */ if (music_pipe_size(player.pipe) < pc.buffered_before_play && - !decoder_is_idle()) { + !decoder_lock_is_idle()) { /* not enough decoded buffer space yet */ if (!player.paused && @@ -678,7 +685,7 @@ static void do_play(void) */ #endif - if (decoder_is_idle() && player.queued) { + if (decoder_lock_is_idle() && player.queued) { /* the decoder has finished the current song; make it decode the next song */ assert(pc.next_song != NULL); @@ -691,7 +698,7 @@ static void do_play(void) if (dc.pipe != NULL && dc.pipe != player.pipe && player.xfade == XFADE_UNKNOWN && - !decoder_is_starting()) { + !decoder_lock_is_starting()) { /* enable cross fading in this song? if yes, calculate how many chunks will be required for it */ @@ -729,7 +736,7 @@ static void do_play(void) if (!player_song_border(&player)) break; - } else if (decoder_is_idle()) { + } else if (decoder_lock_is_idle()) { /* check the size of the pipe again, because the decoder thread may have added something since we last checked */ |