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.