diff --git a/src/applications/gqrx/main.cpp b/src/applications/gqrx/main.cpp index 9df8d157c..7f612cf50 100644 --- a/src/applications/gqrx/main.cpp +++ b/src/applications/gqrx/main.cpp @@ -98,41 +98,6 @@ int main(int argc, char *argv[]) return 0; } - // check whether audio backend is functional -#ifdef WITH_PORTAUDIO - PaError err = Pa_Initialize(); - if (err != paNoError) - { - QString message = QString("Portaudio error: %1").arg(Pa_GetErrorText(err)); - qCritical() << message; - QMessageBox::critical(nullptr, "Audio Error", message, - QMessageBox::Abort, QMessageBox::NoButton); - return 1; - } -#endif - -#ifdef WITH_PULSEAUDIO - int error = 0; - pa_simple *test_sink; - pa_sample_spec ss; - - ss.format = PA_SAMPLE_FLOAT32LE; - ss.rate = 48000; - ss.channels = 2; - test_sink = pa_simple_new(NULL, "Gqrx Test", PA_STREAM_PLAYBACK, NULL, - "Test stream", &ss, NULL, NULL, &error); - if (!test_sink) - { - QString message = QString("Pulseaudio error: %1").arg(pa_strerror(error)); - qCritical() << message; - QMessageBox::critical(0, "Audio Error", message, - QMessageBox::Abort, QMessageBox::NoButton); - return 1; - } - pa_simple_free(test_sink); -#endif - - if (parser.isSet("conf")) { cfg_file = parser.value("conf"); diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index f58df152e..aa38a204e 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -553,7 +553,8 @@ bool MainWindow::loadConfig(const QString& cfgfile, bool check_crash, } // Update window title - setWindowTitle(QString("Gqrx %1 - %2").arg(VERSION).arg(indev)); + const char* audio_status = rx->has_audio_device() ? "" : " - NO AUDIO"; + setWindowTitle(QString("Gqrx %1 - %2%3").arg(VERSION).arg(indev).arg(audio_status)); // Add available antenna connectors to the UI std::vector antennas = rx->get_antennas(); diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 9bdf979ff..667ae1408 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -72,7 +72,8 @@ receiver::receiver(const std::string input_device, d_iq_rev(false), d_dc_cancel(false), d_iq_balance(false), - d_demod(RX_DEMOD_OFF) + d_demod(RX_DEMOD_OFF), + d_has_audio_device(false) { tb = gr::make_top_block("gqrx"); @@ -125,13 +126,20 @@ receiver::receiver(const std::string input_device, audio_udp_sink = make_udp_sink_f(); + try { #ifdef WITH_PULSEAUDIO - audio_snk = make_pa_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); + audio_snk = make_pa_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); #elif WITH_PORTAUDIO - audio_snk = make_portaudio_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); + audio_snk = make_portaudio_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); #else - audio_snk = gr::audio::sink::make(d_audio_rate, audio_device, true); + audio_snk = gr::audio::sink::make(d_audio_rate, audio_device, true); #endif + d_has_audio_device = true; + } + // No audio device a null sink. + catch (const std::exception& error) { + audio_snk = gr::blocks::null_sink::make(sizeof(float)); + } output_devstr = audio_device; @@ -142,10 +150,6 @@ receiver::receiver(const std::string input_device, /* sniffer_rr is created at each activation. */ set_demod(RX_DEMOD_NFM); - - gr::prefs pref; - qDebug() << "Using audio backend:" - << pref.get_string("audio", "audio_module", "N/A").c_str(); } receiver::~receiver() @@ -284,20 +288,17 @@ void receiver::set_output_device(const std::string device) #else audio_snk = gr::audio::sink::make(d_audio_rate, device, true); #endif - - if (d_demod != RX_DEMOD_OFF) - { - tb->connect(audio_gain0, 0, audio_snk, 0); - tb->connect(audio_gain1, 0, audio_snk, 1); - } - - tb->unlock(); - - } catch (std::exception &x) { - tb->unlock(); - // handle problems on non-freeing devices - throw x; } + catch (const std::exception& error) { + audio_snk = gr::blocks::null_sink::make(sizeof(float)); + } + if (d_demod != RX_DEMOD_OFF) + { + tb->connect(audio_gain0, 0, audio_snk, 0); + tb->connect(audio_gain1, 0, audio_snk, 1); + } + + tb->unlock(); } /** Get a list of available antenna connectors. */ diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index d3e8834c7..72a2ac6aa 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -206,6 +206,8 @@ class receiver status start_udp_streaming(const std::string host, int port, bool stereo); status stop_udp_streaming(); + bool has_audio_device(void) { return d_has_audio_device; } + /* I/Q recording and playback */ status start_iq_recording(const std::string filename); status stop_iq_recording(); @@ -285,13 +287,8 @@ class receiver sniffer_f_sptr sniffer; /*!< Sample sniffer for data decoders. */ resampler_ff_sptr sniffer_rr; /*!< Sniffer resampler. */ -#ifdef WITH_PULSEAUDIO - pa_sink_sptr audio_snk; /*!< Pulse audio sink. */ -#elif WITH_PORTAUDIO - portaudio_sink_sptr audio_snk; /*!< portaudio sink */ -#else - gr::audio::sink::sptr audio_snk; /*!< gr audio sink */ -#endif + bool d_has_audio_device; + gr::basic_block_sptr audio_snk; /*!< Audio sink (pulse, portaudio, gr-audio). */ //! Get a path to a file containing random bytes static std::string get_zero_file(void); diff --git a/src/pulseaudio/pa_sink.cc b/src/pulseaudio/pa_sink.cc index 6752c66e2..edd7d3db1 100644 --- a/src/pulseaudio/pa_sink.cc +++ b/src/pulseaudio/pa_sink.cc @@ -69,8 +69,7 @@ pa_sink::pa_sink(const string device_name, int audio_rate, &error); if (!d_pasink) { - /** FIXME: Throw an exception **/ - fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); + throw std::runtime_error("Unable to open pulseaudio device."); } }