A patch to fix audio_alsa_sink[hw:0,0]: snd_pcm_hw_params failed

Last night, while I was preparing for the AMSAT-OZ satellite weekend, I noticed that my gqrx receiver didn’t work very well on my laptops. Every time I tried to change operating mode the receiver stopped with a runtime error:

audio_alsa_sink[hw:0,0]: snd_pcm_hw_params failed: File descriptor in bad state
terminate called after throwing an instance of 'std::runtime_error'
what():  check topology failed on audio_alsa_sink(1) using ninputs=1, noutputs=0

This happened on both my Acer and my MacBook Pro; both running the lates git of GNU Radio v3.3.1git-96-g1fa9a8ea. This was bad news because I was hoping to show off my new software receiver with Qt GUI during the weekend. Fortunately, there is an easy workaround that eliminates the problem.

A quick search in my mail archive reminded me of this thread from October, suggesting that the problem can be fixed by adding a static boolean flag and use it to only call snd_pcm_hw_params() once. The changes are trivial and fix the problem even though it may not be the right way to do so. I can imagine cases where this may not work, e.g. if the audio parameters are reconfigured at runtime. For now it is sufficient.

 

diff --git a/gr-audio-alsa/src/audio_alsa_sink.cc b/gr-audio-alsa/src/audio_alsa_sink.cc
index d6b7f84..38ed86b 100644
--- a/gr-audio-alsa/src/audio_alsa_sink.cc
+++ b/gr-audio-alsa/src/audio_alsa_sink.cc
@@ -219,9 +219,15 @@ audio_alsa_sink::check_topology (int ninputs, int noutputs)
int nchan = ninputs;
int err;
- // FIXME check_topology may be called more than once.
+ // Check the state of the stream
// Ensure that the pcm is in a state where we can still mess with the hw_params
-
+ snd_pcm_state_t state;
+ state=snd_pcm_state(d_pcm_handle);
+ if ( state== SND_PCM_STATE_RUNNING)
+ return true; // If stream is running, don't change any parameters
+ else if(state == SND_PCM_STATE_XRUN )
+ snd_pcm_prepare ( d_pcm_handle ); // Prepare stream on underrun, and we can set parameters;
+
bool special_case = nchan == 1 && d_special_case_mono_to_stereo;
if (special_case)
nchan = 2;

With this patch applied I think we could also implement a multi-mode receiver in GNU Radio Companion using the selector block.