From a0ceace5b48ed56bd393ed14b833606f3638483d Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sat, 8 Aug 2020 16:25:14 +0100 Subject: [PATCH] User configurable audio device buffer sizes Adjusting these may help with audio drop-outs, particularly on slower CPU systems or heavily loaded systems. Smaller buffer sizes leave less margin for process interruptions, larger sizes waste resources that could impact other processes. --- Audio/soundin.cpp | 5 +- Audio/soundout.cpp | 19 ++--- Audio/soundout.h | 6 +- Configuration.cpp | 52 +++++++++--- Configuration.hpp | 2 + Configuration.ui | 185 +++++++++++++++++++++++++++++------------ widgets/mainwindow.cpp | 25 +++--- widgets/mainwindow.h | 2 - 8 files changed, 201 insertions(+), 95 deletions(-) diff --git a/Audio/soundin.cpp b/Audio/soundin.cpp index e08d45271..3e61b41b1 100644 --- a/Audio/soundin.cpp +++ b/Audio/soundin.cpp @@ -41,7 +41,8 @@ bool SoundInput::audioError () const return result; } -void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel channel) +void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, AudioDevice * sink + , unsigned downSampleFactor, AudioDevice::Channel channel) { Q_ASSERT (sink); @@ -79,7 +80,9 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged); + qDebug () << "SoundIn default buffer size (bytes):" << m_stream->bufferSize (); m_stream->setBufferSize (m_stream->format ().bytesForFrames (framesPerBuffer)); + qDebug () << "SoundIn selected buffer size (bytes):" << m_stream->bufferSize (); if (sink->initialize (QIODevice::WriteOnly, channel)) { m_stream->start (sink); diff --git a/Audio/soundout.cpp b/Audio/soundout.cpp index 0264ad91e..48bea9cc6 100644 --- a/Audio/soundout.cpp +++ b/Audio/soundout.cpp @@ -9,15 +9,6 @@ #include "moc_soundout.cpp" -/* -#if defined (WIN32) -# define MS_BUFFERED 1000u -#else -# define MS_BUFFERED 2000u -#endif -*/ -# define MS_BUFFERED 200u - bool SoundOutput::audioError () const { bool result (true); @@ -50,11 +41,11 @@ bool SoundOutput::audioError () const return result; } -void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered) +void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered) { Q_ASSERT (0 < channels && channels < 3); - m_msBuffered = msBuffered; + m_framesBuffered = frames_buffered; QAudioFormat format (device.preferredFormat ()); // qDebug () << "Preferred audio output format:" << format; @@ -101,9 +92,9 @@ void SoundOutput::restart (QIODevice * source) // we have to set this before every start on the stream because the // Windows implementation seems to forget the buffer size after a // stop. - m_stream->setBufferSize (m_stream->format().bytesForDuration((m_msBuffered ? m_msBuffered : MS_BUFFERED) * 1000)); - // qDebug() << "B" << m_stream->bufferSize() << - // m_stream->periodSize() << m_stream->notifyInterval(); + qDebug () << "SoundOut default buffer size (bytes):" << m_stream->bufferSize (); + m_stream->setBufferSize (m_stream->format().bytesForFrames (m_framesBuffered)); + qDebug () << "SoundOut selected buffer size (bytes):" << m_stream->bufferSize (); m_stream->setCategory ("production"); m_stream->start (source); } diff --git a/Audio/soundout.h b/Audio/soundout.h index 1e4b3a948..2699176f3 100644 --- a/Audio/soundout.h +++ b/Audio/soundout.h @@ -18,7 +18,7 @@ class SoundOutput public: SoundOutput () - : m_msBuffered {0u} + : m_framesBuffered {0} , m_volume {1.0} { } @@ -26,7 +26,7 @@ public: qreal attenuation () const; public Q_SLOTS: - void setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered = 0u); + void setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered = 0); void restart (QIODevice *); void suspend (); void resume (); @@ -47,7 +47,7 @@ private Q_SLOTS: private: QScopedPointer m_stream; - unsigned m_msBuffered; + int m_framesBuffered; qreal m_volume; }; diff --git a/Configuration.cpp b/Configuration.cpp index 0cbe744e6..4aeda730d 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -242,6 +242,8 @@ namespace // Magic numbers for file validation constexpr quint32 qrg_magic {0xadbccbdb}; constexpr quint32 qrg_version {100}; // M.mm + + constexpr int default_audio_buffer_size = 10; } @@ -649,9 +651,11 @@ private: QAudioDeviceInfo audio_input_device_; bool default_audio_input_device_selected_; AudioDevice::Channel audio_input_channel_; + int audio_input_buffer_size_; QAudioDeviceInfo audio_output_device_; bool default_audio_output_device_selected_; AudioDevice::Channel audio_output_channel_; + int audio_output_buffer_size_; friend class Configuration; }; @@ -681,8 +685,10 @@ bool Configuration::is_active () const {return m_->isVisible ();} QAudioDeviceInfo const& Configuration::audio_input_device () const {return m_->audio_input_device_;} AudioDevice::Channel Configuration::audio_input_channel () const {return m_->audio_input_channel_;} +int Configuration::audio_input_buffer_size () const {return m_->audio_input_buffer_size_ * 1024;} QAudioDeviceInfo const& Configuration::audio_output_device () const {return m_->audio_output_device_;} AudioDevice::Channel Configuration::audio_output_channel () const {return m_->audio_output_channel_;} +int Configuration::audio_output_buffer_size () const {return m_->audio_output_buffer_size_ * 1024;} bool Configuration::restart_audio_input () const {return m_->restart_sound_input_device_;} bool Configuration::restart_audio_output () const {return m_->restart_sound_output_device_;} auto Configuration::type_2_msg_gen () const -> Type2MsgGen {return m_->type_2_msg_gen_;} @@ -977,7 +983,9 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network , degrade_ {0.} // initialize to zero each run, not // saved in settings , default_audio_input_device_selected_ {false} + , audio_input_buffer_size_ {default_audio_buffer_size} , default_audio_output_device_selected_ {false} + , audio_output_buffer_size_ {default_audio_buffer_size} { ui_->setupUi (this); @@ -1189,18 +1197,6 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network // ui_->highlighting_list_view->setModel (&next_decode_highlighing_model_); - // - // load combo boxes with audio setup choices - // - default_audio_input_device_selected_ = load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_); - default_audio_output_device_selected_ = load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &audio_output_device_); - - update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false); - update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true); - - ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_); - ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_); - enumerate_rigs (); initialize_models (); @@ -1238,6 +1234,21 @@ void Configuration::impl::initialize_models () ui_->sbDegrade->setValue (degrade_); ui_->sbBandwidth->setValue (RxBandwidth_); ui_->PTT_method_button_group->button (rig_params_.ptt_type)->setChecked (true); + + // + // load combo boxes with audio setup choices + // + default_audio_input_device_selected_ = load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_); + default_audio_output_device_selected_ = load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &audio_output_device_); + + update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false); + update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true); + + ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_); + ui_->audio_ip_buffer_spin_box->setValue (audio_input_buffer_size_); + ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_); + ui_->audio_op_buffer_spin_box->setValue (audio_output_buffer_size_); + ui_->save_path_display_label->setText (save_directory_.absolutePath ()); ui_->azel_path_display_label->setText (azel_directory_.absolutePath ()); ui_->CW_id_after_73_check_box->setChecked (id_after_73_); @@ -1446,6 +1457,10 @@ void Configuration::impl::read_settings () audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ()); audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ()); + // retrieve audio buffer size values + audio_input_buffer_size_ = settings_->value ("AudioInputBufferSize", default_audio_buffer_size).toInt (); + audio_output_buffer_size_ = settings_->value ("AudioOutputBufferSize", default_audio_buffer_size).toInt (); + type_2_msg_gen_ = settings_->value ("Type2MsgGen", QVariant::fromValue (Configuration::type_2_msg_3_full)).value (); monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool (); @@ -1587,6 +1602,8 @@ void Configuration::impl::write_settings () settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_)); settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_)); + settings_->setValue ("AudioInputBufferSize", audio_input_buffer_size_); + settings_->setValue ("AudioOutputBufferSize", audio_output_buffer_size_); settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_)); settings_->setValue ("MonitorOFF", monitor_off_at_startup_); settings_->setValue ("MonitorLastUsed", monitor_last_used_); @@ -2041,6 +2058,17 @@ void Configuration::impl::accept () } Q_ASSERT (audio_output_channel_ <= AudioDevice::Both); + if (audio_input_buffer_size_ != ui_->audio_ip_buffer_spin_box->value ()) + { + audio_input_buffer_size_ = ui_->audio_ip_buffer_spin_box->value (); + restart_sound_input_device_ = true; + } + if (audio_output_buffer_size_ != ui_->audio_op_buffer_spin_box->value ()) + { + audio_output_buffer_size_ = ui_->audio_op_buffer_spin_box->value (); + restart_sound_output_device_ = true; + } + my_callsign_ = ui_->callsign_line_edit->text (); my_grid_ = ui_->grid_line_edit->text (); FD_exchange_= ui_->Field_Day_Exchange->text ().toUpper (); diff --git a/Configuration.hpp b/Configuration.hpp index 882a78629..3087ea855 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -87,8 +87,10 @@ public: QAudioDeviceInfo const& audio_input_device () const; AudioDevice::Channel audio_input_channel () const; + int audio_input_buffer_size () const; QAudioDeviceInfo const& audio_output_device () const; AudioDevice::Channel audio_output_channel () const; + int audio_output_buffer_size () const; // These query methods should be used after a call to exec() to // determine if either the audio input or audio output stream diff --git a/Configuration.ui b/Configuration.ui index eae6ab94f..57dca9b04 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -6,8 +6,8 @@ 0 0 - 559 - 553 + 553 + 563 @@ -1349,46 +1349,6 @@ radio interface behave as expected. Soundcard - - - - - 1 - 0 - - - - Select the audio CODEC to use for transmitting. -If this is your default device for system sounds then -ensure that all system sounds are disabled otherwise -you will broadcast any systems sounds generated during -transmitting periods. - - - - - - - - 1 - 0 - - - - Select the audio CODEC to use for receiving. - - - - - - - &Input: - - - sound_input_combo_box - - - @@ -1416,6 +1376,16 @@ transmitting periods. + + + + &Input: + + + sound_input_combo_box + + + @@ -1446,6 +1416,81 @@ both here. + + + + Audio output buffer size in kilo-frames + +Adjust for minimum dropped samples reported. Too low values are likely to cause dropped samples causing audio drop-outs. + + + k + + + 4 + + + 128 + + + 10 + + + + + + + + 1 + 0 + + + + Select the audio CODEC to use for receiving. + + + + + + + Audio input buffer size in kilo-frames + +Adjust for minimum dropped samples reported. Too low values are likely to cause dropped samples causing audio drop-outs. + + + k + + + + + + 4 + + + 128 + + + 10 + + + + + + + + 1 + 0 + + + + Select the audio CODEC to use for transmitting. +If this is your default device for system sounds then +ensure that all system sounds are disabled otherwise +you will broadcast any systems sounds generated during +transmitting periods. + + + @@ -1456,6 +1501,26 @@ both here. + + + + Buffer: + + + audio_ip_buffer_spin_box + + + + + + + Buffer: + + + audio_op_buffer_spin_box + + + @@ -2951,14 +3016,20 @@ Right click for insert and delete options. use_dynamic_grid region_combo_box type_2_msg_gen_combo_box + decodes_from_top_check_box + insert_blank_check_box + miles_check_box TX_messages_check_box DXCC_check_box + ppfx_check_box font_push_button decoded_text_font_push_button monitor_off_check_box monitor_last_used_check_box quick_call_check_box disable_TX_on_73_check_box + force_call_1st_check_box + alternate_bindings_check_box CW_id_after_73_check_box enable_VHF_features_check_box tx_QSY_check_box @@ -2977,8 +3048,8 @@ Right click for insert and delete options. CAT_one_stop_bit_radio_button CAT_two_stop_bit_radio_button CAT_handshake_default_radio_button - CAT_handshake_none_radio_button CAT_handshake_xon_radio_button + CAT_handshake_none_radio_button CAT_handshake_hardware_radio_button force_DTR_combo_box force_RTS_combo_box @@ -2999,8 +3070,10 @@ Right click for insert and delete options. test_PTT_push_button sound_input_combo_box sound_input_channel_combo_box + audio_ip_buffer_spin_box sound_output_combo_box sound_output_channel_combo_box + audio_op_buffer_spin_box save_path_select_push_button azel_path_select_push_button checkBoxPwrBandTxMemory @@ -3016,6 +3089,7 @@ Right click for insert and delete options. clear_DX_check_box opCallEntry psk_reporter_check_box + psk_reporter_tcpip_check_box udp_server_line_edit udp_server_port_spin_box accept_udp_requests_check_box @@ -3030,9 +3104,13 @@ Right click for insert and delete options. stations_table_view highlighting_list_view reset_highlighting_to_defaults_push_button + highlight_by_mode_check_box + only_fields_check_box + include_WAE_check_box + rescan_log_push_button LotW_CSV_URL_line_edit - LotW_CSV_fetch_push_button LotW_days_since_upload_spin_box + LotW_CSV_fetch_push_button sbNtrials sbAggressive cbTwoPass @@ -3041,13 +3119,18 @@ Right click for insert and delete options. sbTxDelay cbx2ToneSpacing cbx4ToneSpacing + rbLowSidelobes + rbMaxSensitivity + gbSpecialOpActivity rbFox + rbHound rbNA_VHF_Contest - rbEU_VHF_Contest rbField_Day Field_Day_Exchange + rbEU_VHF_Contest rbRTTY_Roundup RTTY_Exchange + rbWW_DIGI @@ -3117,13 +3200,13 @@ Right click for insert and delete options. - - - - - - + + + + + + diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index e9a533e1d..c9ee10b8a 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -394,8 +394,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, }, m_sfx {"P", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A"}, mem_jt9 {shdmem}, - m_msAudioOutputBuffered (0u), - m_framesAudioInputBuffered (RX_SAMPLE_RATE / 10), m_downSampleFactor (downSampleFactor), m_audioThreadPriority (QThread::HighPriority), m_bandEdited {false}, @@ -937,8 +935,12 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, connect (&m_wav_future_watcher, &QFutureWatcher::finished, this, &MainWindow::diskDat); connect(&watcher3, SIGNAL(finished()),this,SLOT(fast_decode_done())); - Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, m_detector, m_downSampleFactor, m_config.audio_input_channel ()); - Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); + Q_EMIT startAudioInputStream (m_config.audio_input_device () + , m_config.audio_input_buffer_size () + , m_detector, m_downSampleFactor, m_config.audio_input_channel ()); + Q_EMIT initializeAudioOutputStream (m_config.audio_output_device () + , AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2 + , m_config.audio_output_buffer_size ()); Q_EMIT transmitFrequency (ui->TxFreqSpinBox->value () - m_XIT); enable_DXCC_entity (m_config.DXCC ()); // sets text window proportions and (re)inits the logbook @@ -1277,8 +1279,6 @@ void MainWindow::readSettings() // use these initialisation settings to tune the audio o/p buffer // size and audio thread priority m_settings->beginGroup ("Tune"); - m_msAudioOutputBuffered = m_settings->value ("Audio/OutputBufferMs").toInt (); - m_framesAudioInputBuffered = m_settings->value ("Audio/InputBufferFrames", RX_SAMPLE_RATE / 10).toInt (); m_audioThreadPriority = static_cast (m_settings->value ("Audio/ThreadPriority", QThread::HighPriority).toInt () % 8); m_settings->endGroup (); @@ -1799,15 +1799,16 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog if(m_config.spot_to_psk_reporter ()) pskSetLocal (); if(m_config.restart_audio_input ()) { - Q_EMIT startAudioInputStream (m_config.audio_input_device (), - m_framesAudioInputBuffered, m_detector, m_downSampleFactor, - m_config.audio_input_channel ()); + Q_EMIT startAudioInputStream (m_config.audio_input_device () + , m_config.audio_input_buffer_size () + , m_detector, m_downSampleFactor + , m_config.audio_input_channel ()); } if(m_config.restart_audio_output ()) { - Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), - AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, - m_msAudioOutputBuffered); + Q_EMIT initializeAudioOutputStream (m_config.audio_output_device () + , AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2 + , m_config.audio_output_buffer_size ()); } displayDialFrequency (); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 79f65d080..2f95ac801 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -666,8 +666,6 @@ private: QSharedMemory *mem_jt9; QString m_QSOText; - unsigned m_msAudioOutputBuffered; - unsigned m_framesAudioInputBuffered; unsigned m_downSampleFactor; QThread::Priority m_audioThreadPriority; bool m_bandEdited;