Add Workaround for alsa blocking audio device.

This commit is contained in:
Johns 2014-01-29 10:07:07 +01:00
parent a45b9a3abe
commit 340e10a0eb
5 changed files with 49 additions and 8 deletions

View File

@ -1,3 +1,9 @@
User johns
Date:
Add Workaround for alsa blocking audio device.
Improves thread handling for audio flush and close.
User mini73 User mini73
Date: Fri Jan 24 11:30:49 CET 2014 Date: Fri Jan 24 11:30:49 CET 2014

38
audio.c
View File

@ -123,6 +123,8 @@ static const AudioModule NoopModule; ///< forward definition of noop module
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
char AudioAlsaDriverBroken; ///< disable broken driver message 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 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 // FIXME: if open fails for fe. pass-through, we never recover
return -1; 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; snd_pcm_t *handle;
handle = AlsaPCMHandle; handle = AlsaPCMHandle;
// FIXME: need lock // FIXME: need lock
AlsaPCMHandle = NULL; // other threads should check handle AlsaPCMHandle = NULL; // other threads should check handle
snd_pcm_close(handle); snd_pcm_close(handle);
if (AudioAlsaCloseOpenDelay) {
usleep(50 * 1000); // 50ms delay for alsa recovery
}
// FIXME: can use multiple retries
if (!(handle = AlsaOpenPCM(passthrough))) { if (!(handle = AlsaOpenPCM(passthrough))) {
return -1; return -1;
} }
@ -2043,25 +2049,27 @@ static void *AudioPlayHandlerThread(void *dummy)
int read; int read;
int flush; int flush;
int err; int err;
int i;
// look if there is a flush command in the queue // look if there is a flush command in the queue
flush = 0; flush = 0;
filled = atomic_read(&AudioRingFilled); filled = atomic_read(&AudioRingFilled);
read = AudioRingRead; read = AudioRingRead;
while (filled--) { i = filled;
while (i--) {
read = (read + 1) % AUDIO_RING_MAX; read = (read + 1) % AUDIO_RING_MAX;
if (AudioRing[read].FlushBuffers) { if (AudioRing[read].FlushBuffers) {
AudioRing[read].FlushBuffers = 0; AudioRing[read].FlushBuffers = 0;
AudioRingRead = read; AudioRingRead = read;
atomic_set(&AudioRingFilled, filled);
// handle all flush in queue // handle all flush in queue
flush = 1; flush = filled - i;
} }
} }
if (flush) { if (flush) {
Debug(3, "audio: flush\n"); Debug(3, "audio: flush %d ring buffer(s)\n", flush);
AudioUsedModule->FlushBuffers(); AudioUsedModule->FlushBuffers();
atomic_sub(flush, &AudioRingFilled);
if (AudioNextRing()) { if (AudioNextRing()) {
Debug(3, "audio: break after flush\n"); Debug(3, "audio: break after flush\n");
break; break;
@ -2421,8 +2429,23 @@ void AudioFlushBuffers(void)
int old; int old;
int i; 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; old = AudioRingWrite;
// FIXME: check ring buffer overflow
AudioRingWrite = (AudioRingWrite + 1) % AUDIO_RING_MAX; AudioRingWrite = (AudioRingWrite + 1) % AUDIO_RING_MAX;
AudioRing[AudioRingWrite].FlushBuffers = 1; AudioRing[AudioRingWrite].FlushBuffers = 1;
AudioRing[AudioRingWrite].Passthrough = AudioRing[old].Passthrough; AudioRing[AudioRingWrite].Passthrough = AudioRing[old].Passthrough;
@ -2439,12 +2462,13 @@ void AudioFlushBuffers(void)
atomic_inc(&AudioRingFilled); atomic_inc(&AudioRingFilled);
// FIXME: wait for flush complete? // FIXME: wait for flush complete needed?
for (i = 0; i < 24 * 2; ++i) { for (i = 0; i < 24 * 2; ++i) {
if (!AudioRunning) { // wakeup thread to flush buffers if (!AudioRunning) { // wakeup thread to flush buffers
AudioRunning = 1; AudioRunning = 1;
pthread_cond_signal(&AudioStartCond); pthread_cond_signal(&AudioStartCond);
} }
// FIXME: waiting on zero isn't correct, but currently works
if (!atomic_read(&AudioRingFilled)) { if (!atomic_read(&AudioRingFilled)) {
break; break;
} }

View File

@ -60,5 +60,7 @@ extern void AudioExit(void); ///< cleanup and exit audio module
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
extern char AudioAlsaDriverBroken; ///< disable broken driver message extern char AudioAlsaDriverBroken; ///< disable broken driver message
extern char AudioAlsaNoCloseOpen; ///< disable alsa close/open fix
extern char AudioAlsaCloseOpenDelay; ///< enable alsa close/open delay fix
/// @} /// @}

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: VDR \n" "Project-Id-Version: VDR \n"
"Report-Msgid-Bugs-To: <see README>\n" "Report-Msgid-Bugs-To: <see README>\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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -239,6 +239,9 @@ msgstr ""
msgid "audio: can't place %d samples in ring buffer\n" msgid "audio: can't place %d samples in ring buffer\n"
msgstr "" msgstr ""
msgid "audio: flush out of ring buffers\n"
msgstr ""
#, c-format #, c-format
msgid "audio: '%s' output module used\n" msgid "audio: '%s' output module used\n"
msgstr "" msgstr ""

View File

@ -2888,6 +2888,8 @@ const char *CommandLineHelp(void)
"\tstill-hw-decoder\tenable hardware decoder for still-pictures\n" "\tstill-hw-decoder\tenable hardware decoder for still-pictures\n"
"\tstill-h264-hw-decoder\tenable h264 hw 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-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" "\tignore-repeat-pict\tdisable repeat pict message\n"
" -D\t\tstart in detached mode\n"; " -D\t\tstart in detached mode\n";
} }
@ -2964,6 +2966,10 @@ int ProcessArgs(int argc, char *const argv[])
ConfigStillDecoder = 1; ConfigStillDecoder = 1;
} else if (!strcasecmp("alsa-driver-broken", optarg)) { } else if (!strcasecmp("alsa-driver-broken", optarg)) {
AudioAlsaDriverBroken = 1; 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)) { } else if (!strcasecmp("ignore-repeat-pict", optarg)) {
VideoIgnoreRepeatPict = 1; VideoIgnoreRepeatPict = 1;
} else { } else {