diff options
Diffstat (limited to 'src/player_thread.c')
-rw-r--r-- | src/player_thread.c | 140 |
1 files changed, 76 insertions, 64 deletions
diff --git a/src/player_thread.c b/src/player_thread.c index 7fc55d3d1..6777d5d61 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; @@ -157,7 +151,6 @@ player_wait_for_decoder(struct player *player) player->song = pc.next_song; pc.next_song = NULL; - pc.elapsed_time = 0; player->queued = false; /* set the "starting" flag, which will be cleared by @@ -180,10 +173,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 +188,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 +199,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 +224,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; @@ -331,7 +329,6 @@ static bool player_seek_decoder(struct player *player) return false; } - pc.elapsed_time = where; player_command_finished(); player->xfade = XFADE_UNKNOWN; @@ -348,7 +345,6 @@ static void player_process_command(struct player *player) { switch (pc.command) { case PLAYER_COMMAND_NONE: - case PLAYER_COMMAND_PLAY: case PLAYER_COMMAND_STOP: case PLAYER_COMMAND_EXIT: case PLAYER_COMMAND_CLOSE_AUDIO: @@ -411,9 +407,42 @@ static void player_process_command(struct player *player) player->queued = false; player_command_finished(); break; + + case PLAYER_COMMAND_REFRESH: + if (audio_format_defined(&player->play_audio_format)) + audio_output_all_check(); + + pc.elapsed_time = audio_output_all_get_elapsed_time(); + player_command_finished(); + break; } } +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,52 +450,20 @@ 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); return true; } - 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 +472,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 +523,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 +551,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 +567,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 +587,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 +620,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(); @@ -624,7 +635,6 @@ static void do_play(void) return; } - pc.elapsed_time = 0; pc.state = PLAYER_STATE_PLAY; player_command_finished(); @@ -643,7 +653,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 +688,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 +701,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 +739,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 */ @@ -744,13 +754,11 @@ static void do_play(void) } } - if (player.queued) { - assert(pc.next_song != NULL); - pc.next_song = NULL; - } - player_dc_stop(&player); + assert(!player.queued || pc.next_song != NULL); + pc.next_song = NULL; + music_pipe_clear(player.pipe, player_buffer); music_pipe_free(player.pipe); @@ -766,7 +774,6 @@ static gpointer player_task(G_GNUC_UNUSED gpointer arg) while (1) { switch (pc.command) { - case PLAYER_COMMAND_PLAY: case PLAYER_COMMAND_QUEUE: assert(pc.next_song != NULL); @@ -810,6 +817,11 @@ static gpointer player_task(G_GNUC_UNUSED gpointer arg) player_command_finished(); break; + case PLAYER_COMMAND_REFRESH: + /* no-op when not playing */ + player_command_finished(); + break; + case PLAYER_COMMAND_NONE: notify_wait(&pc.notify); break; |