diff --git a/ChangeLog b/ChangeLog index 972b633..f71f899 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +User johns +Date: + + Add Workaround for alsa blocking audio device. + Improves thread handling for audio flush and close. + User mini73 Date: Fri Jan 24 11:30:49 CET 2014 diff --git a/audio.c b/audio.c index 6ad2907..78463fb 100644 --- a/audio.c +++ b/audio.c @@ -123,6 +123,8 @@ static const AudioModule NoopModule; ///< forward definition of noop module //---------------------------------------------------------------------------- char AudioAlsaDriverBroken; ///< disable broken driver message +char AudioAlsaNoCloseOpen; ///< disable alsa close/open fix +char AudioAlsaCloseOpenDelay; ///< enable alsa close/open delay fix static const char *AudioModuleName; ///< which audio module to use @@ -1189,13 +1191,17 @@ static int AlsaSetup(int *freq, int *channels, int passthrough) // FIXME: if open fails for fe. pass-through, we never recover return -1; } - if (1) { // close+open to fix HDMI no sound bug + if (!AudioAlsaNoCloseOpen) { // close+open to fix HDMI no sound bug snd_pcm_t *handle; handle = AlsaPCMHandle; // FIXME: need lock AlsaPCMHandle = NULL; // other threads should check handle snd_pcm_close(handle); + if (AudioAlsaCloseOpenDelay) { + usleep(50 * 1000); // 50ms delay for alsa recovery + } + // FIXME: can use multiple retries if (!(handle = AlsaOpenPCM(passthrough))) { return -1; } @@ -2043,25 +2049,27 @@ static void *AudioPlayHandlerThread(void *dummy) int read; int flush; int err; + int i; // look if there is a flush command in the queue flush = 0; filled = atomic_read(&AudioRingFilled); read = AudioRingRead; - while (filled--) { + i = filled; + while (i--) { read = (read + 1) % AUDIO_RING_MAX; if (AudioRing[read].FlushBuffers) { AudioRing[read].FlushBuffers = 0; AudioRingRead = read; - atomic_set(&AudioRingFilled, filled); // handle all flush in queue - flush = 1; + flush = filled - i; } } if (flush) { - Debug(3, "audio: flush\n"); + Debug(3, "audio: flush %d ring buffer(s)\n", flush); AudioUsedModule->FlushBuffers(); + atomic_sub(flush, &AudioRingFilled); if (AudioNextRing()) { Debug(3, "audio: break after flush\n"); break; @@ -2421,8 +2429,23 @@ void AudioFlushBuffers(void) int old; int i; + if (atomic_read(&AudioRingFilled) >= AUDIO_RING_MAX) { + // wait for space in ring buffer, should never happen + for (i = 0; i < 24 * 2; ++i) { + if (atomic_read(&AudioRingFilled) < AUDIO_RING_MAX) { + break; + } + Debug(3, "audio: flush out of ring buffers\n"); + usleep(1 * 1000); // avoid hot polling + } + if (atomic_read(&AudioRingFilled) >= AUDIO_RING_MAX) { + // FIXME: We can set the flush flag in the last wrote ring buffer + Error(_("audio: flush out of ring buffers\n")); + return; + } + } + old = AudioRingWrite; - // FIXME: check ring buffer overflow AudioRingWrite = (AudioRingWrite + 1) % AUDIO_RING_MAX; AudioRing[AudioRingWrite].FlushBuffers = 1; AudioRing[AudioRingWrite].Passthrough = AudioRing[old].Passthrough; @@ -2439,12 +2462,13 @@ void AudioFlushBuffers(void) atomic_inc(&AudioRingFilled); - // FIXME: wait for flush complete? + // FIXME: wait for flush complete needed? for (i = 0; i < 24 * 2; ++i) { if (!AudioRunning) { // wakeup thread to flush buffers AudioRunning = 1; pthread_cond_signal(&AudioStartCond); } + // FIXME: waiting on zero isn't correct, but currently works if (!atomic_read(&AudioRingFilled)) { break; } diff --git a/audio.h b/audio.h index 4a0ac51..30fefae 100644 --- a/audio.h +++ b/audio.h @@ -60,5 +60,7 @@ extern void AudioExit(void); ///< cleanup and exit audio module //---------------------------------------------------------------------------- extern char AudioAlsaDriverBroken; ///< disable broken driver message +extern char AudioAlsaNoCloseOpen; ///< disable alsa close/open fix +extern char AudioAlsaCloseOpenDelay; ///< enable alsa close/open delay fix /// @} diff --git a/po/de_DE.po b/po/de_DE.po index 7edfebb..1f3d0a1 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: VDR \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-10-06 22:20+0200\n" +"POT-Creation-Date: 2013-12-05 12:15+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -239,6 +239,9 @@ msgstr "" msgid "audio: can't place %d samples in ring buffer\n" msgstr "" +msgid "audio: flush out of ring buffers\n" +msgstr "" + #, c-format msgid "audio: '%s' output module used\n" msgstr "" diff --git a/softhddev.c b/softhddev.c index 2631df7..b88290e 100644 --- a/softhddev.c +++ b/softhddev.c @@ -2888,6 +2888,8 @@ const char *CommandLineHelp(void) "\tstill-hw-decoder\tenable hardware decoder for still-pictures\n" "\tstill-h264-hw-decoder\tenable h264 hw decoder for still-pictures\n" "\talsa-driver-broken\tdisable broken alsa driver message\n" + "-talsa-no-close-open\tdisable close open to fix alsa no sound bug\n" + "-talsa-close-open-delay\tenable close open delay to fix no sound bug\n" "\tignore-repeat-pict\tdisable repeat pict message\n" " -D\t\tstart in detached mode\n"; } @@ -2964,6 +2966,10 @@ int ProcessArgs(int argc, char *const argv[]) ConfigStillDecoder = 1; } else if (!strcasecmp("alsa-driver-broken", optarg)) { AudioAlsaDriverBroken = 1; + } else if (!strcasecmp("alsa-no-close-open", optarg)) { + AudioAlsaNoCloseOpen = 1; + } else if (!strcasecmp("alsa-close-open-delay", optarg)) { + AudioAlsaCloseOpenDelay = 1; } else if (!strcasecmp("ignore-repeat-pict", optarg)) { VideoIgnoreRepeatPict = 1; } else {