From b2f03e76ffd3af918d8eda0968f54c0b81bbff54 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 6 Oct 2011 20:30:46 +0200 Subject: [PATCH] player_thread: add flag "output_open", fixes assertion failure Previously, the condition "defined(play_audio_format)" was used to see if an output device has been opened, but if the device had failed on startup, an assertion failure could occur. This patch adds a separate flag. --- NEWS | 1 + src/player_thread.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index eab7062fd..44f78e470 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ ver 0.16.5 (2010/??/??) - make seeking to CUE track more reliable - the "seek" command works when MPD is stopped - restore song position from state file (bug fix) + - fix crash that sometimes occurred when audio device fails on startup * WIN32: close sockets properly * install systemd service file if systemd is available diff --git a/src/player_thread.c b/src/player_thread.c index 9a7c917f4..52788e518 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -73,6 +73,14 @@ struct player { */ bool queued; + /** + * Was any audio output opened successfully? It might have + * failed meanwhile, but was not explicitly closed by the + * player thread. When this flag is unset, some output + * methods must not be called. + */ + bool output_open; + /** * the song currently being played */ @@ -290,6 +298,7 @@ player_open_output(struct player *player) pc.state == PLAYER_STATE_PAUSE); if (audio_output_all_open(&player->play_audio_format, player_buffer)) { + player->output_open = true; player->paused = false; player_lock(); @@ -298,6 +307,8 @@ player_open_output(struct player *player) return true; } else { + player->output_open = false; + /* pause: the user may resume playback as soon as an audio output becomes available */ player->paused = true; @@ -342,7 +353,7 @@ player_check_decoder_startup(struct player *player) decoder_unlock(dc); - if (audio_format_defined(&player->play_audio_format) && + if (player->output_open && !audio_output_all_wait(1)) /* the output devices havn't finished playing all chunks yet - wait for that */ @@ -386,6 +397,7 @@ player_check_decoder_startup(struct player *player) static bool player_send_silence(struct player *player) { + assert(player->output_open); assert(audio_format_defined(&player->play_audio_format)); struct music_chunk *chunk = music_buffer_allocate(player_buffer); @@ -579,8 +591,7 @@ static void player_process_command(struct player *player) break; case PLAYER_COMMAND_REFRESH: - if (audio_format_defined(&player->play_audio_format) && - !player->paused) { + if (player->output_open && !player->paused) { player_unlock(); audio_output_all_check(); player_lock(); @@ -831,6 +842,7 @@ static void do_play(struct decoder_control *dc) .decoder_starting = false, .paused = false, .queued = true, + .output_open = false, .song = NULL, .xfade = XFADE_UNKNOWN, .cross_fading = false, @@ -883,7 +895,7 @@ static void do_play(struct decoder_control *dc) /* not enough decoded buffer space yet */ if (!player.paused && - audio_format_defined(&player.play_audio_format) && + player.output_open && audio_output_all_check() < 4 && !player_send_silence(&player)) break; @@ -988,7 +1000,7 @@ static void do_play(struct decoder_control *dc) audio_output_all_drain(); break; } - } else { + } else if (player.output_open) { /* the decoder is too busy and hasn't provided new PCM data in time: send silence (if the output pipe is empty) */