From 581d40010fdd0826329db59a5c2811d7b6cbabac Mon Sep 17 00:00:00 2001 From: Jordan Sherer Date: Tue, 8 Oct 2019 21:26:17 -0400 Subject: [PATCH] Fixed bug causing segfault when QAudioOutput was stopped --- Configuration.cpp | 4 +++- Configuration.ui | 22 ++++++++++++---------- NotificationAudio.cpp | 43 ++++++++++++++++++++++++++++--------------- NotificationAudio.h | 1 + mainwindow.cpp | 21 ++++++++++++++++++--- mainwindow.h | 2 ++ 6 files changed, 64 insertions(+), 29 deletions(-) diff --git a/Configuration.cpp b/Configuration.cpp index 007b01c..7264577 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -1416,7 +1416,9 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory, table->setCellWidget(i, 3, w3); i++; } - table->resizeColumnsToContents(); + table->resizeColumnToContents(0); + table->resizeColumnToContents(1); + table->resizeColumnToContents(2); // diff --git a/Configuration.ui b/Configuration.ui index cf8e20f..df2204f 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -23,7 +23,7 @@ Select tab to change configuration parameters. - 6 + 0 @@ -278,7 +278,7 @@ 0 0 - 615 + 724 508 @@ -793,8 +793,8 @@ text message. 0 0 - 616 - 331 + 738 + 453 @@ -2082,20 +2082,22 @@ both here. - Select the audio CODEC to use for transmitting. -If this is your default device for system sounds then + Select the audio CODEC to use for notifications. +If this is your default device for system sounds and transmission then ensure that all system sounds are disabled otherwise -you will broadcast any systems sounds generated during +you will broadcast any systems sounds and notifications generated during transmitting periods. + + false + - Select the audio channel used for transmission. -Unless you have multiple radios connected on different -channels; then you will usually want to select mono or + Select the audio channel used for notifications. +You will usually want to select mono or both here. diff --git a/NotificationAudio.cpp b/NotificationAudio.cpp index 1e1a5d4..b6df985 100644 --- a/NotificationAudio.cpp +++ b/NotificationAudio.cpp @@ -4,8 +4,8 @@ NotificationAudio::NotificationAudio(QObject *parent) : QIODevice(parent), m_state(State::Stopped), - m_input(&m_data), - m_output(&m_data), + m_input(&m_data, this), + m_output(&m_data, this), m_decoder(nullptr), m_audio(nullptr) { @@ -15,6 +15,16 @@ NotificationAudio::NotificationAudio(QObject *parent) : m_isDecodingFinished = false; } +NotificationAudio::~NotificationAudio(){ + stop(); + + delete m_decoder; + m_decoder = nullptr; + + delete m_audio; + m_audio = nullptr; +} + // initialize an audio device void NotificationAudio::init(const QAudioDeviceInfo &device, const QAudioFormat& format) { m_device = device; @@ -28,7 +38,7 @@ void NotificationAudio::init(const QAudioDeviceInfo &device, const QAudioFormat& m_decoder->setAudioFormat(m_format); if(!m_audio){ - m_audio = new QAudioOutput(m_device, m_format); + m_audio = new QAudioOutput(m_device, m_format, this); } if (!m_output.open(QIODevice::ReadOnly) || !m_input.open(QIODevice::WriteOnly)){ @@ -42,6 +52,10 @@ void NotificationAudio::init(const QAudioDeviceInfo &device, const QAudioFormat& // play an audio file void NotificationAudio::play(const QString &filePath) { + if(m_state == NotificationAudio::Playing){ + return; + } + QFile *file = new QFile(this); file->setFileName(filePath); if (!file->open(QIODevice::ReadOnly)){ @@ -78,8 +92,9 @@ void NotificationAudio::stop() { // Reset the internal buffers and ensure the decoder and audio device is stopped void NotificationAudio::resetBuffers() { if(m_audio){ - if(m_audio->state() != QAudio::StoppedState){ - m_audio->stop(); + + if(m_audio->state() != QAudio::SuspendedState){ + m_audio->suspend(); } } @@ -105,21 +120,18 @@ void NotificationAudio::resetBuffers() { qint64 NotificationAudio::readData(char* data, qint64 maxlen) { memset(data, 0, maxlen); - if (m_state == State::Playing) - { + if (m_state == State::Playing){ m_output.read(data, maxlen); // There is we send readed audio data via signal, for ability get audio signal for the who listen this signal. // Other word this emulate QAudioProbe behaviour for retrieve audio data which of sent to output device (speaker). - if (maxlen > 0) - { - QByteArray buff(data, maxlen); - emit newData(buff); - } + // if (maxlen > 0){ + // QByteArray buff(data, maxlen); + // emit newData(buff); + // } // Is finish of file - if (atEnd()) - { + if (atEnd()){ stop(); } } @@ -137,9 +149,10 @@ qint64 NotificationAudio::writeData(const char* data, qint64 len) { // io device, at end of device bool NotificationAudio::atEnd() const { - return m_output.size() + bool value = m_output.size() && m_output.atEnd() && m_isDecodingFinished; + return value; } // handle buffered data ready diff --git a/NotificationAudio.h b/NotificationAudio.h index cc9a64c..8458578 100644 --- a/NotificationAudio.h +++ b/NotificationAudio.h @@ -18,6 +18,7 @@ class NotificationAudio : public QIODevice public: NotificationAudio(QObject * parent=nullptr); + ~NotificationAudio(); bool isInitialized() const { return m_init; } diff --git a/mainwindow.cpp b/mainwindow.cpp index 783f82f..dcc5d22 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -439,6 +439,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_framesAudioInputBuffered (RX_SAMPLE_RATE / 10), m_downSampleFactor (downSampleFactor), m_audioThreadPriority (QThread::HighPriority), + m_notificationAudioThreadPriority (QThread::LowPriority), m_bandEdited {false}, m_splitMode {false}, m_monitoring {false}, @@ -503,12 +504,13 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_modulator->moveToThread (&m_audioThread); m_soundInput->moveToThread (&m_audioThread); m_detector->moveToThread (&m_audioThread); - m_notification->moveToThread(&m_audioThread); + + // notification audio operates in its own thread at a lower priority + m_notification->moveToThread(&m_notificationAudioThread); // hook up sound output stream slots & signals and disposal connect (this, &MainWindow::initializeAudioOutputStream, m_soundOutput, &SoundOutput::setFormat); connect (m_soundOutput, &SoundOutput::error, this, &MainWindow::showSoundOutError); - // connect (m_soundOutput, &SoundOutput::status, this, &MainWindow::showStatusMessage); connect (this, &MainWindow::outAttenuationChanged, m_soundOutput, &SoundOutput::setAttenuation); connect (&m_audioThread, &QThread::finished, m_soundOutput, &QObject::deleteLater); @@ -517,7 +519,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, emit playNotification("/tmp/test.wav"); }); connect(this, &MainWindow::playNotification, m_notification, &NotificationAudio::play); - connect (&m_audioThread, &QThread::finished, m_notification, &QObject::deleteLater); + connect (&m_notificationAudioThread, &QThread::finished, m_notification, &QObject::deleteLater); // hook up Modulator slots and disposal connect (this, &MainWindow::transmitFrequency, m_modulator, &Modulator::setFrequency); @@ -841,6 +843,10 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, connect(m_wideGraph.data(), &WideGraph::qsy, this, &MainWindow::qsy); + connect(ui->tableWidgetCalls, &QTableWidget::clicked, this, [this](){ + emit playNotification("/tmp/test.wav"); + }); + decodeBusy(false); QString t1[28]={"1 uW","2 uW","5 uW","10 uW","20 uW","50 uW","100 uW","200 uW","500 uW", "1 mW","2 mW","5 mW","10 mW","20 mW","50 mW","100 mW","200 mW","500 mW", @@ -870,7 +876,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, displayDialFrequency(); readSettings(); //Restore user's setup params + m_audioThread.start (m_audioThreadPriority); + m_notificationAudioThread.start(m_notificationAudioThreadPriority); #ifdef WIN32 if (!m_multiple) @@ -943,6 +951,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, // 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_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 initializeNotificationAudioOutputStream(m_config.notification_audio_output_device(), m_config.notification_audio_output_device().preferredFormat()); Q_EMIT transmitFrequency (ui->TxFreqSpinBox->value () - m_XIT); enable_DXCC_entity (m_config.DXCC ()); // sets text window proportions and (re)inits the logbook @@ -2141,9 +2150,15 @@ MainWindow::~MainWindow() m_astroWidget.reset (); QString fname {QDir::toNativeSeparators(m_config.writeable_data_dir ().absoluteFilePath ("wsjtx_wisdom.dat"))}; QByteArray cfname=fname.toLocal8Bit(); + fftwf_export_wisdom_to_filename(cfname); + m_audioThread.quit (); m_audioThread.wait (); + + m_notificationAudioThread.quit(); + m_notificationAudioThread.wait(); + remove_child_from_event_filter (this); } diff --git a/mainwindow.h b/mainwindow.h index 09fb9e1..28576e9 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -507,6 +507,7 @@ private: SoundOutput * m_soundOutput; NotificationAudio * m_notification; QThread m_audioThread; + QThread m_notificationAudioThread; qint64 m_msErase; qint64 m_secBandChanged; @@ -906,6 +907,7 @@ private: unsigned m_framesAudioInputBuffered; unsigned m_downSampleFactor; QThread::Priority m_audioThreadPriority; + QThread::Priority m_notificationAudioThreadPriority; bool m_bandEdited; bool m_splitMode; bool m_monitoring;