From 91d5b90e2a5bda5fd6e7cde9893223640892b14d Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Sun, 2 Dec 2018 03:19:48 +0000 Subject: [PATCH] Fix transmit failures when using virtual devices Direwolf does not send a continuous stream to the audio device. It merely sends samples when it has a transmission to accomplish. This seems to work okay on hardware devices, but is causing an issue when working against a virtual device like plug or dmix because the vitual device seems to get into a weird state while direwolf is not sending samples. This causes it to error out with -EBADFD on every transmission after the first. Direwolf tries to recover from this error by running snd_pcm_recover() on the output device. Inspecting the code of this function revealed that it was a noop on any errors other than -EPIPE or -ESTRPIPE, so it had no hope of fixing any issues other than a buffer underrun or a suspended device. This patch breaks things out so that we only run snd_pcm_recover() on -EPIPE or -ESTRPIPE, and for any other error we go ahead and just try to prepare the device again. This appears to work to make transmissions subsequent to the first work correctly on virtual devices. We handle -EBADFD differently merely so that we don't print the error message for a quasi-expected condition. This problem could also possibly be solved by unprotecting the snd_pcm_prepare() on line 1174 of audio.c and just preparing the device whether it apparently needs it or not, but I'm wary of the unintended consequences of doing so in cases where the code is currently working. Much more testing would be necessary for that solution. This solution should only touch cases that are not working currently regardless. --- audio.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/audio.c b/audio.c index f66971d..613be06 100644 --- a/audio.c +++ b/audio.c @@ -1204,6 +1204,17 @@ int audio_flush (int a) snd_pcm_recover (adev[a].audio_out_handle, k, 1); } + else if (k == -ESTRPIPE) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Driver suspended, recovering\n"); + snd_pcm_recover(adev[a].audio_out_handle, k, 1); + } + else if (k == -EBADFD) { + k = snd_pcm_prepare (adev[a].audio_out_handle); + if(k < 0) { + dw_printf ("Error preparing after bad state: %s\n", snd_strerror(k)); + } + } else if (k < 0) { text_color_set(DW_COLOR_ERROR); dw_printf ("Audio write error: %s\n", snd_strerror(k)); @@ -1211,7 +1222,10 @@ int audio_flush (int a) /* Some other error condition. */ /* Try again. What do we have to lose? */ - snd_pcm_recover (adev[a].audio_out_handle, k, 1); + k = snd_pcm_prepare (adev[a].audio_out_handle); + if(k < 0) { + dw_printf ("Error preparing after error: %s\n", snd_strerror(k)); + } } else if (k != adev[a].outbuf_len / adev[a].bytes_per_frame) { text_color_set(DW_COLOR_ERROR);