mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-12-24 11:40:31 -05:00
Improve audio device handling and error recovery
where possible audio devices that disappear are not forgotten until the user selects another device, this should allow temporarily missing devices or forgetting to switch on devices before starting WSJT-X to be handled more cleanly. If all else fails, visiting the Settings dialog and clicking OK should get things going again. Note that we still do not have a reliable way of detecting failed audio out devices, in that case selecting another device and then returning to the original should work. Enumerating audio devices is expensive and on Linux may take many seconds per device. To avoid lengthy blocking behaviour until it is absolutely necessary, audio devices are not enumerated until one of the "Settings->Audio" device drop-down lists is opened. Elsewhere when devices must be discovered the enumeration stops as soon as the configured device is discovered. A status bar message is posted when audio devices are being enumerated as a reminder that the UI may block while this is happening. The message box warning about unaccounted-for input audio samples now only triggers when >5 seconds of audio appears to be missing or over provided. Hopefully this will make the warning less annoying for those that are using audio sources with high and/or variable latencies. A status bar message is still posted for any amount of audio input samples unaccounted for >1/5 second, this message appearing a lot should be considered as notification that there is a problem with the audio sub-system, system load is too high, or time synchronization is stepping the PC clock rather than adjusting the frequency to maintain monotonic clock ticks.
This commit is contained in:
parent
1ab59a8d6b
commit
542ffe8311
@ -7,4 +7,3 @@ bool AudioDevice::initialize (OpenMode mode, Channel channel)
|
||||
// open and ensure we are unbuffered if possible
|
||||
return QIODevice::open (mode | QIODevice::Unbuffered);
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@ public:
|
||||
Channel channel () const {return m_channel;}
|
||||
|
||||
protected:
|
||||
AudioDevice (QObject * parent = 0)
|
||||
: QIODevice (parent)
|
||||
AudioDevice (QObject * parent = nullptr)
|
||||
: QIODevice {parent}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -10,11 +10,9 @@
|
||||
|
||||
#include "moc_soundin.cpp"
|
||||
|
||||
bool SoundInput::audioError () const
|
||||
bool SoundInput::checkStream ()
|
||||
{
|
||||
bool result (true);
|
||||
|
||||
Q_ASSERT_X (m_stream, "SoundInput", "programming error");
|
||||
bool result (false);
|
||||
if (m_stream)
|
||||
{
|
||||
switch (m_stream->error ())
|
||||
@ -36,9 +34,13 @@ bool SoundInput::audioError () const
|
||||
break;
|
||||
|
||||
case QAudio::NoError:
|
||||
result = false;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -74,12 +76,13 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi
|
||||
// qDebug () << "Selected audio input format:" << format;
|
||||
|
||||
m_stream.reset (new QAudioInput {device, format});
|
||||
if (audioError ())
|
||||
if (!checkStream ())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged);
|
||||
connect (m_stream.data(), &QAudioInput::notify, [this] () {checkStream ();});
|
||||
|
||||
//qDebug () << "SoundIn default buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
|
||||
// the Windows MME version of QAudioInput uses 1/5 of the buffer
|
||||
@ -89,10 +92,10 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi
|
||||
#else
|
||||
Q_UNUSED (framesPerBuffer);
|
||||
#endif
|
||||
if (sink->initialize (QIODevice::WriteOnly, channel))
|
||||
if (m_sink->initialize (QIODevice::WriteOnly, channel))
|
||||
{
|
||||
m_stream->start (sink);
|
||||
audioError ();
|
||||
checkStream ();
|
||||
cummulative_lost_usec_ = -1;
|
||||
//qDebug () << "SoundIn selected buffer size (bytes):" << m_stream->bufferSize () << "peirod size:" << m_stream->periodSize ();
|
||||
}
|
||||
@ -107,7 +110,7 @@ void SoundInput::suspend ()
|
||||
if (m_stream)
|
||||
{
|
||||
m_stream->suspend ();
|
||||
audioError ();
|
||||
checkStream ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,14 +125,12 @@ void SoundInput::resume ()
|
||||
if (m_stream)
|
||||
{
|
||||
m_stream->resume ();
|
||||
audioError ();
|
||||
checkStream ();
|
||||
}
|
||||
}
|
||||
|
||||
void SoundInput::handleStateChanged (QAudio::State newState)
|
||||
{
|
||||
//qDebug () << "SoundInput::handleStateChanged: newState:" << newState;
|
||||
|
||||
switch (newState)
|
||||
{
|
||||
case QAudio::IdleState:
|
||||
@ -152,7 +153,7 @@ void SoundInput::handleStateChanged (QAudio::State newState)
|
||||
#endif
|
||||
|
||||
case QAudio::StoppedState:
|
||||
if (audioError ())
|
||||
if (!checkStream ())
|
||||
{
|
||||
Q_EMIT status (tr ("Error"));
|
||||
}
|
||||
@ -193,11 +194,6 @@ void SoundInput::stop()
|
||||
m_stream->stop ();
|
||||
}
|
||||
m_stream.reset ();
|
||||
|
||||
if (m_sink)
|
||||
{
|
||||
m_sink->close ();
|
||||
}
|
||||
}
|
||||
|
||||
SoundInput::~SoundInput ()
|
||||
|
@ -24,7 +24,6 @@ class SoundInput
|
||||
public:
|
||||
SoundInput (QObject * parent = nullptr)
|
||||
: QObject {parent}
|
||||
, m_sink {nullptr}
|
||||
, cummulative_lost_usec_ {std::numeric_limits<qint64>::min ()}
|
||||
{
|
||||
}
|
||||
@ -47,7 +46,7 @@ private:
|
||||
// used internally
|
||||
Q_SLOT void handleStateChanged (QAudio::State);
|
||||
|
||||
bool audioError () const;
|
||||
bool checkStream ();
|
||||
|
||||
QScopedPointer<QAudioInput> m_stream;
|
||||
QPointer<AudioDevice> m_sink;
|
||||
|
@ -7,11 +7,13 @@
|
||||
#include <qmath.h>
|
||||
#include <QDebug>
|
||||
|
||||
#include "Audio/AudioDevice.hpp"
|
||||
|
||||
#include "moc_soundout.cpp"
|
||||
|
||||
bool SoundOutput::audioError () const
|
||||
bool SoundOutput::checkStream () const
|
||||
{
|
||||
bool result (true);
|
||||
bool result {false};
|
||||
|
||||
Q_ASSERT_X (m_stream, "SoundOutput", "programming error");
|
||||
if (m_stream) {
|
||||
@ -34,7 +36,7 @@ bool SoundOutput::audioError () const
|
||||
break;
|
||||
|
||||
case QAudio::NoError:
|
||||
result = false;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -43,15 +45,19 @@ bool SoundOutput::audioError () const
|
||||
|
||||
void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered)
|
||||
{
|
||||
if (!device.isNull ())
|
||||
Q_ASSERT (0 < channels && channels < 3);
|
||||
m_device = device;
|
||||
m_channels = channels;
|
||||
m_framesBuffered = frames_buffered;
|
||||
}
|
||||
|
||||
void SoundOutput::restart (AudioDevice * source)
|
||||
{
|
||||
if (!m_device.isNull ())
|
||||
{
|
||||
Q_ASSERT (0 < channels && channels < 3);
|
||||
|
||||
m_framesBuffered = frames_buffered;
|
||||
|
||||
QAudioFormat format (device.preferredFormat ());
|
||||
QAudioFormat format (m_device.preferredFormat ());
|
||||
// qDebug () << "Preferred audio output format:" << format;
|
||||
format.setChannelCount (channels);
|
||||
format.setChannelCount (m_channels);
|
||||
format.setCodec ("audio/pcm");
|
||||
format.setSampleRate (48000);
|
||||
format.setSampleType (QAudioFormat::SignedInt);
|
||||
@ -61,29 +67,25 @@ void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels,
|
||||
{
|
||||
Q_EMIT error (tr ("Requested output audio format is not valid."));
|
||||
}
|
||||
else if (!device.isFormatSupported (format))
|
||||
else if (!m_device.isFormatSupported (format))
|
||||
{
|
||||
Q_EMIT error (tr ("Requested output audio format is not supported on device."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// qDebug () << "Selected audio output format:" << format;
|
||||
|
||||
m_stream.reset (new QAudioOutput (device, format));
|
||||
audioError ();
|
||||
m_stream.reset (new QAudioOutput (m_device, format));
|
||||
checkStream ();
|
||||
m_stream->setVolume (m_volume);
|
||||
m_stream->setNotifyInterval(100);
|
||||
m_stream->setNotifyInterval(1000);
|
||||
error_ = false;
|
||||
|
||||
connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged);
|
||||
connect (m_stream.data(), &QAudioOutput::notify, [this] () {checkStream ();});
|
||||
|
||||
// qDebug() << "A" << m_volume << m_stream->notifyInterval();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundOutput::restart (QIODevice * source)
|
||||
{
|
||||
if (!m_stream)
|
||||
{
|
||||
if (!error_)
|
||||
@ -109,6 +111,7 @@ void SoundOutput::restart (QIODevice * source)
|
||||
#endif
|
||||
}
|
||||
m_stream->setCategory ("production");
|
||||
m_source = source;
|
||||
m_stream->start (source);
|
||||
// qDebug () << "SoundOut selected buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
|
||||
}
|
||||
@ -118,7 +121,7 @@ void SoundOutput::suspend ()
|
||||
if (m_stream && QAudio::ActiveState == m_stream->state ())
|
||||
{
|
||||
m_stream->suspend ();
|
||||
audioError ();
|
||||
checkStream ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +130,7 @@ void SoundOutput::resume ()
|
||||
if (m_stream && QAudio::SuspendedState == m_stream->state ())
|
||||
{
|
||||
m_stream->resume ();
|
||||
audioError ();
|
||||
checkStream ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +139,7 @@ void SoundOutput::reset ()
|
||||
if (m_stream)
|
||||
{
|
||||
m_stream->reset ();
|
||||
audioError ();
|
||||
checkStream ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,9 +147,10 @@ void SoundOutput::stop ()
|
||||
{
|
||||
if (m_stream)
|
||||
{
|
||||
m_stream->reset ();
|
||||
m_stream->stop ();
|
||||
audioError ();
|
||||
}
|
||||
m_stream.reset ();
|
||||
}
|
||||
|
||||
qreal SoundOutput::attenuation () const
|
||||
@ -176,8 +180,6 @@ void SoundOutput::resetAttenuation ()
|
||||
|
||||
void SoundOutput::handleStateChanged (QAudio::State newState)
|
||||
{
|
||||
// qDebug () << "SoundOutput::handleStateChanged: newState:" << newState;
|
||||
|
||||
switch (newState)
|
||||
{
|
||||
case QAudio::IdleState:
|
||||
@ -199,7 +201,7 @@ void SoundOutput::handleStateChanged (QAudio::State newState)
|
||||
#endif
|
||||
|
||||
case QAudio::StoppedState:
|
||||
if (audioError ())
|
||||
if (!checkStream ())
|
||||
{
|
||||
Q_EMIT status (tr ("Error"));
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
#include <QString>
|
||||
#include <QAudioOutput>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QPointer>
|
||||
|
||||
class AudioDevice;
|
||||
class QAudioDeviceInfo;
|
||||
|
||||
// An instance of this sends audio data to a specified soundcard.
|
||||
@ -28,7 +30,7 @@ public:
|
||||
|
||||
public Q_SLOTS:
|
||||
void setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered = 0);
|
||||
void restart (QIODevice *);
|
||||
void restart (AudioDevice *);
|
||||
void suspend ();
|
||||
void resume ();
|
||||
void reset ();
|
||||
@ -41,13 +43,16 @@ Q_SIGNALS:
|
||||
void status (QString message) const;
|
||||
|
||||
private:
|
||||
bool audioError () const;
|
||||
bool checkStream () const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleStateChanged (QAudio::State);
|
||||
|
||||
private:
|
||||
QAudioDeviceInfo m_device;
|
||||
unsigned m_channels;
|
||||
QScopedPointer<QAudioOutput> m_stream;
|
||||
QPointer<AudioDevice> m_source;
|
||||
int m_framesBuffered;
|
||||
qreal m_volume;
|
||||
bool error_;
|
||||
|
@ -293,6 +293,7 @@ set (wsjt_qt_CXXSRCS
|
||||
logbook/WorkedBefore.cpp
|
||||
logbook/Multiplier.cpp
|
||||
Network/NetworkAccessManager.cpp
|
||||
widgets/LazyFillComboBox.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
|
@ -188,6 +188,7 @@
|
||||
#include "Network/LotWUsers.hpp"
|
||||
#include "models/DecodeHighlightingModel.hpp"
|
||||
#include "logbook/logbook.h"
|
||||
#include "widgets/LazyFillComboBox.hpp"
|
||||
|
||||
#include "ui_Configuration.h"
|
||||
#include "moc_Configuration.cpp"
|
||||
@ -432,7 +433,6 @@ private:
|
||||
void read_settings ();
|
||||
void write_settings ();
|
||||
|
||||
Q_SLOT void lazy_models_load (int);
|
||||
void find_audio_devices ();
|
||||
QAudioDeviceInfo find_audio_device (QAudio::Mode, QComboBox *, QString const& device_name);
|
||||
void load_audio_devices (QAudio::Mode, QComboBox *, QAudioDeviceInfo *);
|
||||
@ -653,9 +653,13 @@ private:
|
||||
bool pwrBandTuneMemory_;
|
||||
|
||||
QAudioDeviceInfo audio_input_device_;
|
||||
QAudioDeviceInfo next_audio_input_device_;
|
||||
AudioDevice::Channel audio_input_channel_;
|
||||
AudioDevice::Channel next_audio_input_channel_;
|
||||
QAudioDeviceInfo audio_output_device_;
|
||||
QAudioDeviceInfo next_audio_output_device_;
|
||||
AudioDevice::Channel audio_output_channel_;
|
||||
AudioDevice::Channel next_audio_output_channel_;
|
||||
|
||||
friend class Configuration;
|
||||
};
|
||||
@ -856,6 +860,16 @@ void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_s
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::invalidate_audio_input_device (QString /* error */)
|
||||
{
|
||||
m_->audio_input_device_ = QAudioDeviceInfo {};
|
||||
}
|
||||
|
||||
void Configuration::invalidate_audio_output_device (QString /* error */)
|
||||
{
|
||||
m_->audio_output_device_ = QAudioDeviceInfo {};
|
||||
}
|
||||
|
||||
bool Configuration::valid_n1mm_info () const
|
||||
{
|
||||
// do very rudimentary checking on the n1mm server name and port number.
|
||||
@ -1029,6 +1043,17 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
// this must be done after the default paths above are set
|
||||
read_settings ();
|
||||
|
||||
connect (ui_->sound_input_combo_box, &LazyFillComboBox::about_to_show_popup, [this] () {
|
||||
load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &next_audio_input_device_);
|
||||
update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false);
|
||||
ui_->sound_input_channel_combo_box->setCurrentIndex (next_audio_input_channel_);
|
||||
});
|
||||
connect (ui_->sound_output_combo_box, &LazyFillComboBox::about_to_show_popup, [this] () {
|
||||
load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &next_audio_output_device_);
|
||||
update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true);
|
||||
ui_->sound_output_channel_combo_box->setCurrentIndex (next_audio_output_channel_);
|
||||
});
|
||||
|
||||
// set up LoTW users CSV file fetching
|
||||
connect (&lotw_users_, &LotWUsers::load_finished, [this] () {
|
||||
ui_->LotW_CSV_fetch_push_button->setEnabled (true);
|
||||
@ -1102,7 +1127,6 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
//
|
||||
// setup hooks to keep audio channels aligned with devices
|
||||
//
|
||||
connect (ui_->configuration_tabs, &QTabWidget::currentChanged, this, &Configuration::impl::lazy_models_load);
|
||||
{
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
@ -1199,6 +1223,11 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
enumerate_rigs ();
|
||||
initialize_models ();
|
||||
|
||||
audio_input_device_ = next_audio_input_device_;
|
||||
audio_input_channel_ = next_audio_input_channel_;
|
||||
audio_output_device_ = next_audio_output_device_;
|
||||
audio_output_channel_ = next_audio_output_channel_;
|
||||
|
||||
transceiver_thread_ = new QThread {this};
|
||||
transceiver_thread_->start ();
|
||||
}
|
||||
@ -1210,31 +1239,14 @@ Configuration::impl::~impl ()
|
||||
write_settings ();
|
||||
}
|
||||
|
||||
void Configuration::impl::lazy_models_load (int current_tab_index)
|
||||
{
|
||||
switch (current_tab_index)
|
||||
{
|
||||
case 2: // Audio
|
||||
//
|
||||
// load combo boxes with audio setup choices
|
||||
//
|
||||
load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_);
|
||||
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_);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::impl::initialize_models ()
|
||||
{
|
||||
next_audio_input_device_ = audio_input_device_;
|
||||
next_audio_input_channel_ = audio_input_channel_;
|
||||
next_audio_output_device_ = audio_output_device_;
|
||||
next_audio_output_channel_ = audio_output_channel_;
|
||||
restart_sound_input_device_ = false;
|
||||
restart_sound_output_device_ = false;
|
||||
{
|
||||
SettingsGroup g {settings_, "Configuration"};
|
||||
find_audio_devices ();
|
||||
@ -1413,8 +1425,6 @@ void Configuration::impl::read_settings ()
|
||||
save_directory_.setPath (settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString ());
|
||||
azel_directory_.setPath (settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ());
|
||||
|
||||
find_audio_devices ();
|
||||
|
||||
type_2_msg_gen_ = settings_->value ("Type2MsgGen", QVariant::fromValue (Configuration::type_2_msg_3_full)).value<Configuration::Type2MsgGen> ();
|
||||
|
||||
monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool ();
|
||||
@ -1522,24 +1532,24 @@ void Configuration::impl::find_audio_devices ()
|
||||
// retrieve audio input device
|
||||
//
|
||||
auto saved_name = settings_->value ("SoundInName").toString ();
|
||||
if (audio_input_device_.deviceName () != saved_name)
|
||||
if (next_audio_input_device_.deviceName () != saved_name || next_audio_input_device_.isNull ())
|
||||
{
|
||||
audio_input_device_ = find_audio_device (QAudio::AudioInput, ui_->sound_input_combo_box, saved_name);
|
||||
audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ());
|
||||
next_audio_input_device_ = find_audio_device (QAudio::AudioInput, ui_->sound_input_combo_box, saved_name);
|
||||
next_audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ());
|
||||
update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false);
|
||||
ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_);
|
||||
ui_->sound_input_channel_combo_box->setCurrentIndex (next_audio_input_channel_);
|
||||
}
|
||||
|
||||
//
|
||||
// retrieve audio output device
|
||||
//
|
||||
saved_name = settings_->value("SoundOutName").toString();
|
||||
if (audio_output_device_.deviceName () != saved_name)
|
||||
if (next_audio_output_device_.deviceName () != saved_name || next_audio_output_device_.isNull ())
|
||||
{
|
||||
audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ());
|
||||
audio_output_device_ = find_audio_device (QAudio::AudioOutput, ui_->sound_output_combo_box, saved_name);
|
||||
next_audio_output_device_ = find_audio_device (QAudio::AudioOutput, ui_->sound_output_combo_box, saved_name);
|
||||
next_audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ());
|
||||
update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true);
|
||||
ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_);
|
||||
ui_->sound_output_channel_combo_box->setCurrentIndex (next_audio_output_channel_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1562,10 +1572,16 @@ void Configuration::impl::write_settings ()
|
||||
settings_->setValue ("PTTport", rig_params_.ptt_port);
|
||||
settings_->setValue ("SaveDir", save_directory_.absolutePath ());
|
||||
settings_->setValue ("AzElDir", azel_directory_.absolutePath ());
|
||||
settings_->setValue ("SoundInName", audio_input_device_.deviceName ());
|
||||
settings_->setValue ("SoundOutName", audio_output_device_.deviceName ());
|
||||
settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_));
|
||||
settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_));
|
||||
if (!audio_input_device_.isNull ())
|
||||
{
|
||||
settings_->setValue ("SoundInName", audio_input_device_.deviceName ());
|
||||
settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_));
|
||||
}
|
||||
if (!audio_output_device_.isNull ())
|
||||
{
|
||||
settings_->setValue ("SoundOutName", audio_output_device_.deviceName ());
|
||||
settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_));
|
||||
}
|
||||
settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_));
|
||||
settings_->setValue ("MonitorOFF", monitor_off_at_startup_);
|
||||
settings_->setValue ("MonitorLastUsed", monitor_last_used_);
|
||||
@ -1770,7 +1786,7 @@ void Configuration::impl::set_rig_invariants ()
|
||||
bool Configuration::impl::validate ()
|
||||
{
|
||||
if (ui_->sound_input_combo_box->currentIndex () < 0
|
||||
&& audio_input_device_.isNull ())
|
||||
&& next_audio_input_device_.isNull ())
|
||||
{
|
||||
find_tab (ui_->sound_input_combo_box);
|
||||
MessageBox::critical_message (this, tr ("Invalid audio input device"));
|
||||
@ -1778,7 +1794,7 @@ bool Configuration::impl::validate ()
|
||||
}
|
||||
|
||||
if (ui_->sound_input_channel_combo_box->currentIndex () < 0
|
||||
&& audio_input_device_.isNull ())
|
||||
&& next_audio_input_device_.isNull ())
|
||||
{
|
||||
find_tab (ui_->sound_input_combo_box);
|
||||
MessageBox::critical_message (this, tr ("Invalid audio input device"));
|
||||
@ -1786,7 +1802,7 @@ bool Configuration::impl::validate ()
|
||||
}
|
||||
|
||||
if (ui_->sound_output_combo_box->currentIndex () < 0
|
||||
&& audio_output_device_.isNull ())
|
||||
&& next_audio_output_device_.isNull ())
|
||||
{
|
||||
find_tab (ui_->sound_output_combo_box);
|
||||
MessageBox::information_message (this, tr ("Invalid audio output device"));
|
||||
@ -1842,7 +1858,6 @@ int Configuration::impl::exec ()
|
||||
rig_changed_ = false;
|
||||
|
||||
initialize_models ();
|
||||
lazy_models_load (ui_->configuration_tabs->currentIndex ());
|
||||
|
||||
return QDialog::exec();
|
||||
}
|
||||
@ -1941,39 +1956,60 @@ void Configuration::impl::accept ()
|
||||
// related configuration parameters
|
||||
rig_is_dummy_ = TransceiverFactory::basic_transceiver_name_ == rig_params_.rig_name;
|
||||
|
||||
// Check to see whether SoundInThread must be restarted,
|
||||
// and save user parameters.
|
||||
{
|
||||
auto const& selected_device = ui_->sound_input_combo_box->currentData ().value<audio_info_type> ().first;
|
||||
if (selected_device != audio_input_device_)
|
||||
if (selected_device != next_audio_input_device_)
|
||||
{
|
||||
audio_input_device_ = selected_device;
|
||||
restart_sound_input_device_ = true;
|
||||
next_audio_input_device_ = selected_device;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const& selected_device = ui_->sound_output_combo_box->currentData ().value<audio_info_type> ().first;
|
||||
if (selected_device != audio_output_device_)
|
||||
if (selected_device != next_audio_output_device_)
|
||||
{
|
||||
audio_output_device_ = selected_device;
|
||||
restart_sound_output_device_ = true;
|
||||
next_audio_output_device_ = selected_device;
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_input_channel_ != static_cast<AudioDevice::Channel> (ui_->sound_input_channel_combo_box->currentIndex ()))
|
||||
if (next_audio_input_channel_ != static_cast<AudioDevice::Channel> (ui_->sound_input_channel_combo_box->currentIndex ()))
|
||||
{
|
||||
audio_input_channel_ = static_cast<AudioDevice::Channel> (ui_->sound_input_channel_combo_box->currentIndex ());
|
||||
next_audio_input_channel_ = static_cast<AudioDevice::Channel> (ui_->sound_input_channel_combo_box->currentIndex ());
|
||||
}
|
||||
Q_ASSERT (next_audio_input_channel_ <= AudioDevice::Right);
|
||||
|
||||
if (next_audio_output_channel_ != static_cast<AudioDevice::Channel> (ui_->sound_output_channel_combo_box->currentIndex ()))
|
||||
{
|
||||
next_audio_output_channel_ = static_cast<AudioDevice::Channel> (ui_->sound_output_channel_combo_box->currentIndex ());
|
||||
}
|
||||
Q_ASSERT (next_audio_output_channel_ <= AudioDevice::Both);
|
||||
|
||||
if (audio_input_device_ != next_audio_input_device_ || next_audio_input_device_.isNull ())
|
||||
{
|
||||
audio_input_device_ = next_audio_input_device_;
|
||||
restart_sound_input_device_ = true;
|
||||
}
|
||||
Q_ASSERT (audio_input_channel_ <= AudioDevice::Right);
|
||||
|
||||
if (audio_output_channel_ != static_cast<AudioDevice::Channel> (ui_->sound_output_channel_combo_box->currentIndex ()))
|
||||
if (audio_input_channel_ != next_audio_input_channel_)
|
||||
{
|
||||
audio_output_channel_ = static_cast<AudioDevice::Channel> (ui_->sound_output_channel_combo_box->currentIndex ());
|
||||
audio_input_channel_ = next_audio_input_channel_;
|
||||
restart_sound_input_device_ = true;
|
||||
}
|
||||
if (audio_output_device_ != next_audio_output_device_ || next_audio_output_device_.isNull ())
|
||||
{
|
||||
audio_output_device_ = next_audio_output_device_;
|
||||
restart_sound_output_device_ = true;
|
||||
}
|
||||
Q_ASSERT (audio_output_channel_ <= AudioDevice::Both);
|
||||
if (audio_output_channel_ != next_audio_output_channel_)
|
||||
{
|
||||
audio_output_channel_ = next_audio_output_channel_;
|
||||
restart_sound_output_device_ = true;
|
||||
}
|
||||
// qDebug () << "Configure::accept: audio i/p:" << audio_input_device_.deviceName ()
|
||||
// << "chan:" << audio_input_channel_
|
||||
// << "o/p:" << audio_output_device_.deviceName ()
|
||||
// << "chan:" << audio_output_channel_
|
||||
// << "reset i/p:" << restart_sound_input_device_
|
||||
// << "reset o/p:" << restart_sound_output_device_;
|
||||
|
||||
my_callsign_ = ui_->callsign_line_edit->text ();
|
||||
my_grid_ = ui_->grid_line_edit->text ();
|
||||
@ -2112,6 +2148,13 @@ void Configuration::impl::reject ()
|
||||
}
|
||||
}
|
||||
|
||||
// qDebug () << "Configure::reject: audio i/p:" << audio_input_device_.deviceName ()
|
||||
// << "chan:" << audio_input_channel_
|
||||
// << "o/p:" << audio_output_device_.deviceName ()
|
||||
// << "chan:" << audio_output_channel_
|
||||
// << "reset i/p:" << restart_sound_input_device_
|
||||
// << "reset o/p:" << restart_sound_output_device_;
|
||||
|
||||
QDialog::reject ();
|
||||
}
|
||||
|
||||
@ -2772,27 +2815,25 @@ QAudioDeviceInfo Configuration::impl::find_audio_device (QAudio::Mode mode, QCom
|
||||
|
||||
if (device_name.size ())
|
||||
{
|
||||
combo_box->clear ();
|
||||
|
||||
int current_index = -1;
|
||||
Q_EMIT self_->enumerating_audio_devices ();
|
||||
auto const& devices = QAudioDeviceInfo::availableDevices (mode);
|
||||
Q_FOREACH (auto const& p, devices)
|
||||
{
|
||||
|
||||
// convert supported channel counts into something we can store in the item model
|
||||
QList<QVariant> channel_counts;
|
||||
auto scc = p.supportedChannelCounts ();
|
||||
copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts));
|
||||
|
||||
combo_box->addItem (p.deviceName (), QVariant::fromValue (audio_info_type {p, channel_counts}));
|
||||
qDebug () << "Configuration::impl::find_audio_device: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes ();
|
||||
if (p.deviceName () == device_name)
|
||||
{
|
||||
current_index = combo_box->count () - 1;
|
||||
combo_box->setCurrentIndex (current_index);
|
||||
// convert supported channel counts into something we can store in the item model
|
||||
QList<QVariant> channel_counts;
|
||||
auto scc = p.supportedChannelCounts ();
|
||||
copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts));
|
||||
combo_box->insertItem (0, device_name, QVariant::fromValue (audio_info_type {p, channel_counts}));
|
||||
combo_box->setCurrentIndex (0);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
combo_box->setCurrentIndex (current_index);
|
||||
// insert a place holder for the not found device
|
||||
combo_box->insertItem (0, device_name + " (" + tr ("Not found", "audio device missing") + ")", QVariant::fromValue (audio_info_type {}));
|
||||
combo_box->setCurrentIndex (0);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@ -2811,7 +2852,7 @@ void Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * com
|
||||
auto const& devices = QAudioDeviceInfo::availableDevices (mode);
|
||||
Q_FOREACH (auto const& p, devices)
|
||||
{
|
||||
// qDebug () << "Audio device: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes ();
|
||||
// qDebug () << "Configuration::impl::load_audio_devices: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes ();
|
||||
|
||||
// convert supported channel counts into something we can store in the item model
|
||||
QList<QVariant> channel_counts;
|
||||
|
@ -260,6 +260,8 @@ public:
|
||||
// i.e. the transceiver is ready for use.
|
||||
Q_SLOT void sync_transceiver (bool force_signal = false, bool enforce_mode_and_split = false);
|
||||
|
||||
Q_SLOT void invalidate_audio_input_device (QString error);
|
||||
Q_SLOT void invalidate_audio_output_device (QString error);
|
||||
|
||||
//
|
||||
// These signals indicate a font has been selected and accepted for
|
||||
|
143
Configuration.ui
143
Configuration.ui
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>554</width>
|
||||
<height>557</height>
|
||||
<height>556</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -1364,71 +1364,8 @@ radio interface behave as expected.</string>
|
||||
<string>Soundcard</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="sound_output_label">
|
||||
<property name="text">
|
||||
<string>Ou&tput:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sound_output_combo_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="sound_input_label">
|
||||
<property name="text">
|
||||
<string>&Input:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sound_input_combo_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="sound_output_channel_combo_box">
|
||||
<property name="toolTip">
|
||||
<string>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
|
||||
both here.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mono</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Both</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="sound_input_combo_box">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select the audio CODEC to use for receiving.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="sound_output_combo_box">
|
||||
<widget class="LazyFillComboBox" name="sound_output_combo_box">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
@ -1471,6 +1408,69 @@ transmitting periods.</string>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="LazyFillComboBox" name="sound_input_combo_box">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select the audio CODEC to use for receiving.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="sound_output_label">
|
||||
<property name="text">
|
||||
<string>Ou&tput:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sound_output_combo_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="sound_output_channel_combo_box">
|
||||
<property name="toolTip">
|
||||
<string>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
|
||||
both here.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Mono</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Both</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="sound_input_label">
|
||||
<property name="text">
|
||||
<string>&Input:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>sound_input_combo_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -2997,6 +2997,11 @@ Right click for insert and delete options.</string>
|
||||
<extends>QListView</extends>
|
||||
<header>widgets/DecodeHighlightingListView.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LazyFillComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>widgets/LazyFillComboBox.hpp</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>configuration_tabs</tabstop>
|
||||
@ -3187,13 +3192,13 @@ Right click for insert and delete options.</string>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="special_op_activity_button_group"/>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="split_mode_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="CAT_handshake_button_group"/>
|
||||
<buttongroup name="split_mode_button_group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
@ -36,7 +36,7 @@ void Detector::setBlockSize (unsigned n)
|
||||
bool Detector::reset ()
|
||||
{
|
||||
clear ();
|
||||
// don't call base call reset because it calls seek(0) which causes
|
||||
// don't call base class reset because it calls seek(0) which causes
|
||||
// a warning
|
||||
return isOpen ();
|
||||
}
|
||||
@ -56,7 +56,6 @@ void Detector::clear ()
|
||||
|
||||
qint64 Detector::writeData (char const * data, qint64 maxSize)
|
||||
{
|
||||
//qDebug () << "Detector::writeData: size:" << maxSize;
|
||||
static unsigned mstr0=999999;
|
||||
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time
|
||||
|
@ -149,8 +149,6 @@ void Modulator::close ()
|
||||
|
||||
qint64 Modulator::readData (char * data, qint64 maxSize)
|
||||
{
|
||||
// qDebug () << "readData: maxSize:" << maxSize;
|
||||
|
||||
double toneFrequency=1500.0;
|
||||
if(m_nsps==6) {
|
||||
toneFrequency=1000.0;
|
||||
|
3
widgets/LazyFillComboBox.cpp
Normal file
3
widgets/LazyFillComboBox.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "LazyFillComboBox.hpp"
|
||||
|
||||
#include "moc_LazyFillComboBox.cpp"
|
40
widgets/LazyFillComboBox.hpp
Normal file
40
widgets/LazyFillComboBox.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef LAZY_FILL_COMBO_BOX_HPP__
|
||||
#define LAZY_FILL_COMBO_BOX_HPP__
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
class QWidget;
|
||||
|
||||
//
|
||||
// Class LazyFillComboBox
|
||||
//
|
||||
// QComboBox derivative that signals show and hide of the pop up list.
|
||||
//
|
||||
class LazyFillComboBox final
|
||||
: public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_SIGNAL void about_to_show_popup ();
|
||||
Q_SIGNAL void popup_hidden ();
|
||||
|
||||
explicit LazyFillComboBox (QWidget * parent = nullptr)
|
||||
: QComboBox {parent}
|
||||
{
|
||||
}
|
||||
|
||||
void showPopup () override
|
||||
{
|
||||
Q_EMIT about_to_show_popup ();
|
||||
QComboBox::showPopup ();
|
||||
}
|
||||
|
||||
void hidePopup () override
|
||||
{
|
||||
QComboBox::hidePopup ();
|
||||
Q_EMIT popup_hidden ();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -454,6 +454,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
// 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::error, &m_config, &Configuration::invalidate_audio_output_device);
|
||||
// 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);
|
||||
@ -472,13 +473,14 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
connect (this, &MainWindow::reset_audio_input_stream, m_soundInput, &SoundInput::reset);
|
||||
connect (this, &MainWindow::finished, m_soundInput, &SoundInput::stop);
|
||||
connect(m_soundInput, &SoundInput::error, this, &MainWindow::showSoundInError);
|
||||
connect(m_soundInput, &SoundInput::error, &m_config, &Configuration::invalidate_audio_input_device);
|
||||
// connect(m_soundInput, &SoundInput::status, this, &MainWindow::showStatusMessage);
|
||||
connect (m_soundInput, &SoundInput::dropped_frames, this, [this] (qint32 dropped_frames, qint64 usec) {
|
||||
if (dropped_frames > 48000 / 5) // 1/5 second
|
||||
{
|
||||
showStatusMessage (tr ("%1 (%2 sec) audio frames dropped").arg (dropped_frames).arg (usec / 1.e6, 5, 'f', 3));
|
||||
}
|
||||
if (dropped_frames > 48000) // 1 second
|
||||
if (dropped_frames > 5 * 48000) // seconds
|
||||
{
|
||||
auto period = qt_truncate_date_time_to (QDateTime::currentDateTimeUtc ().addMSecs (-m_TRperiod / 2.), m_TRperiod * 1e3);
|
||||
MessageBox::warning_message (this
|
||||
@ -1824,14 +1826,14 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog
|
||||
m_psk_Reporter.sendReport (true);
|
||||
}
|
||||
|
||||
if(m_config.restart_audio_input ()) {
|
||||
if(m_config.restart_audio_input () && !m_config.audio_input_device ().isNull ()) {
|
||||
Q_EMIT startAudioInputStream (m_config.audio_input_device ()
|
||||
, rx_chunk_size * m_downSampleFactor
|
||||
, m_detector, m_downSampleFactor
|
||||
, m_config.audio_input_channel ());
|
||||
}
|
||||
|
||||
if(m_config.restart_audio_output ()) {
|
||||
if(m_config.restart_audio_output () && !m_config.audio_output_device ().isNull ()) {
|
||||
Q_EMIT initializeAudioOutputStream (m_config.audio_output_device ()
|
||||
, AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2
|
||||
, tx_audio_buffer_size);
|
||||
|
Loading…
Reference in New Issue
Block a user