diff --git a/fcdhid/hid-libusb.c b/fcdhid/hid-libusb.c index c45de4a40..ac6d3565b 100644 --- a/fcdhid/hid-libusb.c +++ b/fcdhid/hid-libusb.c @@ -1220,6 +1220,7 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) { + (void) dev; return NULL; } diff --git a/fcdhid/hid-libusb.h b/fcdhid/hid-libusb.h index 2296dc3a7..0d71d5ae1 100644 --- a/fcdhid/hid-libusb.h +++ b/fcdhid/hid-libusb.h @@ -1214,6 +1214,7 @@ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) { + (void) dev; return NULL; } diff --git a/plugins/feature/simpleptt/simpleptt.cpp b/plugins/feature/simpleptt/simpleptt.cpp index 18a010a10..a6f5eb507 100644 --- a/plugins/feature/simpleptt/simpleptt.cpp +++ b/plugins/feature/simpleptt/simpleptt.cpp @@ -147,6 +147,13 @@ bool SimplePTT::deserialize(const QByteArray& data) } } +void SimplePTT::getAudioPeak(float& peak) +{ + if (m_worker) { + m_worker->getAudioPeak(peak); + } +} + void SimplePTT::applySettings(const SimplePTTSettings& settings, bool force) { qDebug() << "SimplePTT::applySettings:" @@ -156,6 +163,11 @@ void SimplePTT::applySettings(const SimplePTTSettings& settings, bool force) << " m_txDeviceSetIndex: " << settings.m_txDeviceSetIndex << " m_rx2TxDelayMs: " << settings.m_rx2TxDelayMs << " m_tx2RxDelayMs: " << settings.m_tx2RxDelayMs + << " m_vox: " << settings.m_vox + << " m_voxEnable: " << settings.m_voxEnable + << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_voxLevel: " << settings.m_voxLevel + << " m_voxHold: " << settings.m_voxHold << " force: " << force; QList reverseAPIKeys; @@ -178,6 +190,18 @@ void SimplePTT::applySettings(const SimplePTTSettings& settings, bool force) if ((m_settings.m_tx2RxDelayMs != settings.m_tx2RxDelayMs) || force) { reverseAPIKeys.append("tx2RxDelayMs"); } + if ((m_settings.m_vox != settings.m_vox) || force) { + reverseAPIKeys.append("vox"); + } + if ((m_settings.m_voxEnable != settings.m_voxEnable) || force) { + reverseAPIKeys.append("voxEnable"); + } + if ((m_settings.m_voxHold != settings.m_voxHold) || force) { + reverseAPIKeys.append("voxHold"); + } + if ((m_settings.m_voxLevel != settings.m_voxLevel) || force) { + reverseAPIKeys.append("voxLevel"); + } SimplePTTWorker::MsgConfigureSimplePTTWorker *msg = SimplePTTWorker::MsgConfigureSimplePTTWorker::create( settings, force @@ -321,6 +345,10 @@ void SimplePTT::webapiFormatFeatureSettings( response.getSimplePttSettings()->setTxDeviceSetIndex(settings.m_txDeviceSetIndex); response.getSimplePttSettings()->setRx2TxDelayMs(settings.m_rx2TxDelayMs); response.getSimplePttSettings()->setTx2RxDelayMs(settings.m_tx2RxDelayMs); + response.getSimplePttSettings()->setVox(settings.m_vox ? 1 : 0); + response.getSimplePttSettings()->setVoxEnable(settings.m_voxEnable ? 1 : 0); + response.getSimplePttSettings()->setVoxHold(settings.m_voxHold); + response.getSimplePttSettings()->setVoxLevel(settings.m_voxLevel); response.getSimplePttSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); @@ -358,6 +386,18 @@ void SimplePTT::webapiUpdateFeatureSettings( if (featureSettingsKeys.contains("tx2RxDelayMs")) { settings.m_tx2RxDelayMs = response.getSimplePttSettings()->getTx2RxDelayMs(); } + if (featureSettingsKeys.contains("vox")) { + settings.m_vox = response.getSimplePttSettings()->getVox() != 0; + } + if (featureSettingsKeys.contains("voxEnable")) { + settings.m_voxEnable = response.getSimplePttSettings()->getVoxEnable() != 0; + } + if (featureSettingsKeys.contains("voxHold")) { + settings.m_voxHold = response.getSimplePttSettings()->getVoxHold(); + } + if (featureSettingsKeys.contains("voxLevel")) { + settings.m_voxLevel = response.getSimplePttSettings()->getVoxLevel(); + } if (featureSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getSimplePttSettings()->getUseReverseApi() != 0; } @@ -410,6 +450,18 @@ void SimplePTT::webapiReverseSendSettings(QList& channelSettingsKeys, c if (channelSettingsKeys.contains("tx2RxDelayMs") || force) { swgSimplePTTSettings->setTx2RxDelayMs(settings.m_tx2RxDelayMs); } + if (channelSettingsKeys.contains("vox") || force) { + swgSimplePTTSettings->setVox(settings.m_vox ? 1 : 0); + } + if (channelSettingsKeys.contains("voxEnable") || force) { + swgSimplePTTSettings->setVoxEnable(settings.m_voxEnable ? 1 : 0); + } + if (channelSettingsKeys.contains("voxHold") || force) { + swgSimplePTTSettings->setVoxHold(settings.m_voxHold); + } + if (channelSettingsKeys.contains("voxLevel") || force) { + swgSimplePTTSettings->setVoxLevel(settings.m_voxLevel); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/feature/simpleptt/simpleptt.h b/plugins/feature/simpleptt/simpleptt.h index 9970ff50a..5f57fac03 100644 --- a/plugins/feature/simpleptt/simpleptt.h +++ b/plugins/feature/simpleptt/simpleptt.h @@ -142,6 +142,8 @@ public: const QStringList& featureSettingsKeys, SWGSDRangel::SWGFeatureSettings& response); + void getAudioPeak(float& peak); + static const char* const m_featureIdURI; static const char* const m_featureId; diff --git a/plugins/feature/simpleptt/simplepttgui.cpp b/plugins/feature/simpleptt/simplepttgui.cpp index 3b8166708..037e03b26 100644 --- a/plugins/feature/simpleptt/simplepttgui.cpp +++ b/plugins/feature/simpleptt/simplepttgui.cpp @@ -19,7 +19,11 @@ #include "feature/featureuiset.h" #include "gui/basicfeaturesettingsdialog.h" +#include "gui/crightclickenabler.h" +#include "gui/audioselectdialog.h" +#include "dsp/dspengine.h" #include "device/deviceset.h" +#include "util/db.h" #include "maincore.h" #include "ui_simplepttgui.h" @@ -89,6 +93,19 @@ bool SimplePTTGUI::handleMessage(const Message& message) return true; } + else if (SimplePTTReport::MsgVox::match(message)) + { + qDebug("SimplePTTGUI::handleMessage: SimplePTTReport::MsgVox"); + const SimplePTTReport::MsgVox& cfg = (const SimplePTTReport::MsgVox&) message; + + if (cfg.getVox()) { + ui->voxLevelText->setStyleSheet("QLabel { background-color : green; }"); + } else { + ui->voxLevelText->setStyleSheet("QLabel { background:rgb(79,79,79); }"); + } + + return true; + } else if (SimplePTT::MsgPTT::match(message)) { qDebug("SimplePTTGUI::handleMessage: SimplePTT::MsgPTT"); @@ -145,9 +162,11 @@ SimplePTTGUI::SimplePTTGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Fea connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + CRightClickEnabler *voxRightClickEnabler = new CRightClickEnabler(ui->vox); + connect(voxRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); - m_statusTimer.start(1000); + m_statusTimer.start(500); m_statusTooltips.push_back("Idle"); // 0 - all off m_statusTooltips.push_back("Rx on"); // 1 - Rx on @@ -180,6 +199,11 @@ void SimplePTTGUI::displaySettings() ui->rxtxDelay->setValue(m_settings.m_rx2TxDelayMs); ui->txrxDelay->setValue(m_settings.m_tx2RxDelayMs); restoreState(m_settings.m_rollupState); + ui->vox->setChecked(m_settings.m_vox); + ui->voxEnable->setChecked(m_settings.m_voxEnable); + ui->voxLevel->setValue(m_settings.m_voxLevel); + ui->voxLevelText->setText(tr("%1").arg(m_settings.m_voxLevel)); + ui->voxHold->setValue(m_settings.m_voxHold); blockApplySettings(false); } @@ -354,6 +378,31 @@ void SimplePTTGUI::on_ptt_toggled(bool checked) applyPTT(checked); } +void SimplePTTGUI::on_vox_toggled(bool checked) +{ + m_settings.m_vox = checked; + applySettings(); +} + +void SimplePTTGUI::on_voxEnable_clicked(bool checked) +{ + m_settings.m_voxEnable = checked; + applySettings(); +} + +void SimplePTTGUI::on_voxLevel_valueChanged(int value) +{ + m_settings.m_voxLevel = value; + ui->voxLevelText->setText(tr("%1dB").arg(m_settings.m_voxLevel)); + applySettings(); +} + +void SimplePTTGUI::on_voxHold_valueChanged(int value) +{ + m_settings.m_voxHold = value; + applySettings(); +} + void SimplePTTGUI::updateStatus() { int state = m_simplePTT->getState(); @@ -381,6 +430,14 @@ void SimplePTTGUI::updateStatus() m_lastFeatureState = state; } + + if (m_settings.m_vox) + { + float peak; + m_simplePTT->getAudioPeak(peak); + int peakDB = CalcDb::dbPower(peak); + ui->audioPeak->setText(tr("%1 dB").arg(peakDB)); + } } void SimplePTTGUI::applySettings(bool force) @@ -400,3 +457,16 @@ void SimplePTTGUI::applyPTT(bool tx) m_simplePTT->getInputMessageQueue()->push(message); } } + +void SimplePTTGUI::audioSelect() +{ + qDebug("SimplePTTGUI::audioSelect"); + AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName); + audioSelect.exec(); + + if (audioSelect.m_selected) + { + m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName; + applySettings(); + } +} diff --git a/plugins/feature/simpleptt/simplepttgui.h b/plugins/feature/simpleptt/simplepttgui.h index 539073eb4..7c47f1531 100644 --- a/plugins/feature/simpleptt/simplepttgui.h +++ b/plugins/feature/simpleptt/simplepttgui.h @@ -81,7 +81,12 @@ private slots: void on_rxtxDelay_valueChanged(int value); void on_txrxDelay_valueChanged(int value); void on_ptt_toggled(bool checked); + void on_vox_toggled(bool checked); + void on_voxEnable_clicked(bool checked); + void on_voxLevel_valueChanged(int value); + void on_voxHold_valueChanged(int value); void updateStatus(); + void audioSelect(); }; diff --git a/plugins/feature/simpleptt/simplepttgui.ui b/plugins/feature/simpleptt/simplepttgui.ui index 4a91e4a20..92999e4be 100644 --- a/plugins/feature/simpleptt/simplepttgui.ui +++ b/plugins/feature/simpleptt/simplepttgui.ui @@ -92,6 +92,7 @@ + Liberation Sans 20 75 true @@ -132,6 +133,148 @@ + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + Toggle vox system - right click to select audio device + + + + + + + :/audio_mic.png:/audio_mic.png + + + + + + + Enable vox to control PTT + + + + + + + + + + + 24 + 24 + + + + Vox threshold (dB) + + + -99 + + + 0 + + + 1 + + + 1 + + + -20 + + + + + + + + 30 + 0 + + + + -20 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + 0 + + + + Audio signal peak in dB (with Vox on) + + + 14 + + + -100 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Vox delay (ms) + + + 200 + + + 2000 + + + 100 + + + + + + + ms + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/plugins/feature/simpleptt/simplepttreport.cpp b/plugins/feature/simpleptt/simplepttreport.cpp index e84f57355..ee53e3f03 100644 --- a/plugins/feature/simpleptt/simplepttreport.cpp +++ b/plugins/feature/simpleptt/simplepttreport.cpp @@ -18,6 +18,7 @@ #include "simplepttreport.h" MESSAGE_CLASS_DEFINITION(SimplePTTReport::MsgRadioState, Message) +MESSAGE_CLASS_DEFINITION(SimplePTTReport::MsgVox, Message) SimplePTTReport::SimplePTTReport() {} diff --git a/plugins/feature/simpleptt/simplepttreport.h b/plugins/feature/simpleptt/simplepttreport.h index 8f687b91b..3f1977ac4 100644 --- a/plugins/feature/simpleptt/simplepttreport.h +++ b/plugins/feature/simpleptt/simplepttreport.h @@ -34,8 +34,7 @@ public: public: RadioState getState() const { return m_state; } - static MsgRadioState* create(RadioState state) - { + static MsgRadioState* create(RadioState state) { return new MsgRadioState(state); } @@ -48,6 +47,25 @@ public: { } }; + class MsgVox : public Message { + MESSAGE_CLASS_DECLARATION + + public: + bool getVox() const { return m_vox; } + + static MsgVox* create(bool vox) { + return new MsgVox(vox); + } + + private: + bool m_vox; + + MsgVox(bool vox) : + Message(), + m_vox(vox) + {} + }; + SimplePTTReport(); ~SimplePTTReport(); }; diff --git a/plugins/feature/simpleptt/simplepttsettings.cpp b/plugins/feature/simpleptt/simplepttsettings.cpp index b77511624..7fd6f5e7d 100644 --- a/plugins/feature/simpleptt/simplepttsettings.cpp +++ b/plugins/feature/simpleptt/simplepttsettings.cpp @@ -19,6 +19,7 @@ #include "util/simpleserializer.h" #include "settings/serializable.h" +#include "audio/audiodevicemanager.h" #include "simplepttsettings.h" @@ -35,6 +36,11 @@ void SimplePTTSettings::resetToDefaults() m_txDeviceSetIndex = -1; m_rx2TxDelayMs = 100; m_tx2RxDelayMs = 100; + m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; + m_voxLevel = -20; + m_voxHold = 500; + m_vox = false; + m_voxEnable = false; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -58,6 +64,11 @@ QByteArray SimplePTTSettings::serialize() const s.writeU32(10, m_reverseAPIFeatureSetIndex); s.writeU32(11, m_reverseAPIFeatureIndex); s.writeBlob(12, m_rollupState); + s.writeString(13, m_audioDeviceName); + s.writeS32(14, m_voxLevel); + s.writeBool(15, m_vox); + s.writeBool(16, m_voxEnable); + s.writeS32(17, m_voxHold); return s.final(); } @@ -99,6 +110,11 @@ bool SimplePTTSettings::deserialize(const QByteArray& data) d.readU32(11, &utmp, 0); m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp; d.readBlob(12, &m_rollupState); + d.readString(13, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName); + d.readS32(14, &m_voxLevel, -20); + d.readBool(15, &m_vox, false); + d.readBool(16, &m_voxEnable, false); + d.readS32(16, &m_voxHold, 500); return true; } diff --git a/plugins/feature/simpleptt/simplepttsettings.h b/plugins/feature/simpleptt/simplepttsettings.h index 333c514b1..af67d90a9 100644 --- a/plugins/feature/simpleptt/simplepttsettings.h +++ b/plugins/feature/simpleptt/simplepttsettings.h @@ -31,6 +31,11 @@ struct SimplePTTSettings int m_txDeviceSetIndex; unsigned int m_rx2TxDelayMs; unsigned int m_tx2RxDelayMs; + QString m_audioDeviceName; //!< for Vox + int m_voxLevel; //!< Vox threshold level in dB + int m_voxHold; //!< Vox hold in milliseconds + bool m_vox; + bool m_voxEnable; bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/feature/simpleptt/simplepttworker.cpp b/plugins/feature/simpleptt/simplepttworker.cpp index 1e2cc9f7f..9bb19b484 100644 --- a/plugins/feature/simpleptt/simplepttworker.cpp +++ b/plugins/feature/simpleptt/simplepttworker.cpp @@ -22,6 +22,9 @@ #include "SWGErrorResponse.h" #include "webapi/webapiadapterinterface.h" +#include "audio/audiodevicemanager.h" +#include "dsp/dspengine.h" +#include "util/db.h" #include "simplepttreport.h" #include "simplepttworker.h" @@ -34,9 +37,16 @@ SimplePTTWorker::SimplePTTWorker(WebAPIAdapterInterface *webAPIAdapterInterface) m_msgQueueToGUI(nullptr), m_running(false), m_tx(false), + m_audioFifo(12000), + m_audioSampleRate(48000), + m_voxLevel(1.0), + m_voxHoldCount(0), + m_voxState(false), m_updateTimer(this), m_mutex(QMutex::Recursive) { + m_audioReadBuffer.resize(16384); + m_audioReadBufferFill = 0; qDebug("SimplePTTWorker::SimplePTTWorker"); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); } @@ -44,6 +54,8 @@ SimplePTTWorker::SimplePTTWorker(WebAPIAdapterInterface *webAPIAdapterInterface) SimplePTTWorker::~SimplePTTWorker() { m_inputMessageQueue.clear(); + AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); + audioDeviceManager->removeAudioSource(&m_audioFifo); } void SimplePTTWorker::reset() @@ -115,7 +127,48 @@ void SimplePTTWorker::applySettings(const SimplePTTSettings& settings, bool forc << " m_txDeviceSetIndex: " << settings.m_txDeviceSetIndex << " m_rx2TxDelayMs: " << settings.m_rx2TxDelayMs << " m_tx2RxDelayMs: " << settings.m_tx2RxDelayMs + << " m_vox: " << settings.m_vox + << " m_voxEnable: " << settings.m_voxEnable + << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_voxLevel: " << settings.m_voxLevel + << " m_voxHold: " << settings.m_voxHold << " force: " << force; + + if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) + { + QMutexLocker mlock(&m_mutex); + AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); + int audioDeviceIndex = audioDeviceManager->getInputDeviceIndex(settings.m_audioDeviceName); + audioDeviceManager->removeAudioSource(&m_audioFifo); + audioDeviceManager->addAudioSource(&m_audioFifo, getInputMessageQueue(), audioDeviceIndex); + m_audioSampleRate = audioDeviceManager->getInputSampleRate(audioDeviceIndex); + } + + if ((settings.m_vox != m_settings.m_vox) || force) + { + QMutexLocker mlock(&m_mutex); + m_voxHoldCount = 0; + m_audioReadBufferFill = 0; + m_voxState = false; + + if (m_msgQueueToGUI) + { + SimplePTTReport::MsgVox *msg = SimplePTTReport::MsgVox::create(false); + m_msgQueueToGUI->push(msg); + } + + if (settings.m_vox) { + connect(&m_audioFifo, SIGNAL(dataReady()), this, SLOT(handleAudio())); + } else { + disconnect(&m_audioFifo, SIGNAL(dataReady()), this, SLOT(handleAudio())); + } + } + + if ((settings.m_voxLevel != m_settings.m_voxLevel) || force) + { + m_voxLevel = CalcDb::powerFromdB(settings.m_voxLevel); + } + m_settings = settings; } @@ -126,29 +179,29 @@ void SimplePTTWorker::sendPTT(bool tx) bool switchedOff = false; m_mutex.lock(); - if (tx) + if (tx) { - if (m_settings.m_rxDeviceSetIndex >= 0) + if (m_settings.m_rxDeviceSetIndex >= 0) { m_tx = false; switchedOff = turnDevice(false); } - - if (m_settings.m_txDeviceSetIndex >= 0) + + if (m_settings.m_txDeviceSetIndex >= 0) { m_tx = true; m_updateTimer.start(m_settings.m_rx2TxDelayMs); } - } - else + } + else { - if (m_settings.m_txDeviceSetIndex >= 0) + if (m_settings.m_txDeviceSetIndex >= 0) { m_tx = true; switchedOff = turnDevice(false); } - if (m_settings.m_rxDeviceSetIndex >= 0) + if (m_settings.m_rxDeviceSetIndex >= 0) { m_tx = false; m_updateTimer.start(m_settings.m_tx2RxDelayMs); @@ -190,7 +243,7 @@ bool SimplePTTWorker::turnDevice(bool on) SWGSDRangel::SWGDeviceState response; SWGSDRangel::SWGErrorResponse error; int httpCode; - + if (on) { httpCode = m_webAPIAdapterInterface->devicesetDeviceRunPost( m_tx ? m_settings.m_txDeviceSetIndex : m_settings.m_rxDeviceSetIndex, response, error); @@ -208,4 +261,63 @@ bool SimplePTTWorker::turnDevice(bool on) qWarning("SimplePTTWorker::turnDevice: error: %s", qPrintable(*error.getMessage())); return false; } -} \ No newline at end of file +} + +void SimplePTTWorker::handleAudio() +{ + unsigned int nbRead; + QMutexLocker mlock(&m_mutex); + + while ((nbRead = m_audioFifo.read(reinterpret_cast(&m_audioReadBuffer[m_audioReadBufferFill]), 4096)) != 0) + { + if (m_audioReadBufferFill + nbRead + 4096 < m_audioReadBuffer.size()) + { + m_audioReadBufferFill += nbRead; + } + else + { + bool voxState = m_voxState; + + for (const auto &it : m_audioReadBuffer) + { + std::complex za{it.l / 32768.0f, it.r / 32768.0f}; + float magSq = std::norm(za); + + if (magSq > m_audioMagsqPeak) { + m_audioMagsqPeak = magSq; + } + + if (magSq > m_voxLevel) + { + voxState = true; + m_voxHoldCount = 0; + } + else + { + if (m_voxHoldCount < (m_settings.m_voxHold * m_audioSampleRate) / 1000) { + m_voxHoldCount++; + } else { + voxState = false; + } + } + + if (voxState != m_voxState) + { + if (m_settings.m_voxEnable) { + sendPTT(voxState); + } + + if (m_msgQueueToGUI) + { + SimplePTTReport::MsgVox *msg = SimplePTTReport::MsgVox::create(voxState); + m_msgQueueToGUI->push(msg); + } + + m_voxState = voxState; + } + } + + m_audioReadBufferFill = 0; + } + } +} diff --git a/plugins/feature/simpleptt/simplepttworker.h b/plugins/feature/simpleptt/simplepttworker.h index b064021e6..e1d67098e 100644 --- a/plugins/feature/simpleptt/simplepttworker.h +++ b/plugins/feature/simpleptt/simplepttworker.h @@ -23,6 +23,7 @@ #include "util/message.h" #include "util/messagequeue.h" +#include "audio/audiofifo.h" #include "simplepttsettings.h" @@ -83,6 +84,12 @@ public: MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; } + void getAudioPeak(float& peak) + { + peak = m_audioMagsqPeak; + m_audioMagsqPeak = 0; + } + private: WebAPIAdapterInterface *m_webAPIAdapterInterface; MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication @@ -90,6 +97,14 @@ private: SimplePTTSettings m_settings; bool m_running; bool m_tx; + AudioFifo m_audioFifo; + AudioVector m_audioReadBuffer; + unsigned int m_audioReadBufferFill; + int m_audioSampleRate; + float m_audioMagsqPeak; + float m_voxLevel; + int m_voxHoldCount; + bool m_voxState; QTimer m_updateTimer; QMutex m_mutex; @@ -101,6 +116,7 @@ private: private slots: void handleInputMessages(); void updateHardware(); + void handleAudio(); }; -#endif // INCLUDE_FEATURE_SIMPLEPTTWORKER_H_ \ No newline at end of file +#endif // INCLUDE_FEATURE_SIMPLEPTTWORKER_H_ diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index fdd59c023..bc939c17f 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -11231,6 +11231,25 @@ margin-bottom: 20px; "type" : "integer", "description" : "Delay in milliseconds from Tx off to Rx on" }, + "vox" : { + "type" : "integer", + "description" : "Activate vox system\n * 0 - not active\n * 1 - active\n" + }, + "voxEnable" : { + "type" : "integer", + "description" : "Allow vox to control PTT\n * 0 - vox does not control PTT\n * 1 - vox controls PTT\n" + }, + "voxLevel" : { + "type" : "integer", + "description" : "Vox threshold level in dB" + }, + "voxHold" : { + "type" : "integer", + "description" : "Vox hold timeout in milliseconds" + }, + "audioDeviceName" : { + "type" : "string" + }, "useReverseAPI" : { "type" : "integer", "description" : "Synchronize with reverse API (1 for yes, 0 for no)" @@ -51634,7 +51653,7 @@ except ApiException as e:
- Generated 2021-12-27T21:57:14.290+01:00 + Generated 2021-12-29T17:23:49.058+01:00
diff --git a/sdrbase/resources/webapi/doc/swagger/include/SimplePTT.yaml b/sdrbase/resources/webapi/doc/swagger/include/SimplePTT.yaml index d8fe6fd35..14f753ac6 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/SimplePTT.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/SimplePTT.yaml @@ -17,6 +17,26 @@ SimplePTTSettings: tx2RxDelayMs: description: Delay in milliseconds from Tx off to Rx on type: integer + vox: + type: integer + description: > + Activate vox system + * 0 - not active + * 1 - active + voxEnable: + type: integer + description: > + Allow vox to control PTT + * 0 - vox does not control PTT + * 1 - vox controls PTT + voxLevel: + type: integer + description: Vox threshold level in dB + voxHold: + type: integer + description: Vox hold timeout in milliseconds + audioDeviceName: + type: string useReverseAPI: description: Synchronize with reverse API (1 for yes, 0 for no) type: integer diff --git a/sdrgui/resources/audio_mic.png b/sdrgui/resources/audio_mic.png new file mode 100644 index 000000000..d9494c539 Binary files /dev/null and b/sdrgui/resources/audio_mic.png differ diff --git a/sdrgui/resources/res.qrc b/sdrgui/resources/res.qrc index f62409640..3bc51a654 100644 --- a/sdrgui/resources/res.qrc +++ b/sdrgui/resources/res.qrc @@ -1,5 +1,6 @@ + audio_mic.png info.png darklight.png lightdark.png diff --git a/swagger/sdrangel/api/swagger/include/SimplePTT.yaml b/swagger/sdrangel/api/swagger/include/SimplePTT.yaml index d8fe6fd35..14f753ac6 100644 --- a/swagger/sdrangel/api/swagger/include/SimplePTT.yaml +++ b/swagger/sdrangel/api/swagger/include/SimplePTT.yaml @@ -17,6 +17,26 @@ SimplePTTSettings: tx2RxDelayMs: description: Delay in milliseconds from Tx off to Rx on type: integer + vox: + type: integer + description: > + Activate vox system + * 0 - not active + * 1 - active + voxEnable: + type: integer + description: > + Allow vox to control PTT + * 0 - vox does not control PTT + * 1 - vox controls PTT + voxLevel: + type: integer + description: Vox threshold level in dB + voxHold: + type: integer + description: Vox hold timeout in milliseconds + audioDeviceName: + type: string useReverseAPI: description: Synchronize with reverse API (1 for yes, 0 for no) type: integer diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index fdd59c023..bc939c17f 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -11231,6 +11231,25 @@ margin-bottom: 20px; "type" : "integer", "description" : "Delay in milliseconds from Tx off to Rx on" }, + "vox" : { + "type" : "integer", + "description" : "Activate vox system\n * 0 - not active\n * 1 - active\n" + }, + "voxEnable" : { + "type" : "integer", + "description" : "Allow vox to control PTT\n * 0 - vox does not control PTT\n * 1 - vox controls PTT\n" + }, + "voxLevel" : { + "type" : "integer", + "description" : "Vox threshold level in dB" + }, + "voxHold" : { + "type" : "integer", + "description" : "Vox hold timeout in milliseconds" + }, + "audioDeviceName" : { + "type" : "string" + }, "useReverseAPI" : { "type" : "integer", "description" : "Synchronize with reverse API (1 for yes, 0 for no)" @@ -51634,7 +51653,7 @@ except ApiException as e:
- Generated 2021-12-27T21:57:14.290+01:00 + Generated 2021-12-29T17:23:49.058+01:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.cpp index cd4c0bec0..89c4f0060 100644 --- a/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.cpp @@ -40,6 +40,16 @@ SWGSimplePTTSettings::SWGSimplePTTSettings() { m_rx2_tx_delay_ms_isSet = false; tx2_rx_delay_ms = 0; m_tx2_rx_delay_ms_isSet = false; + vox = 0; + m_vox_isSet = false; + vox_enable = 0; + m_vox_enable_isSet = false; + vox_level = 0; + m_vox_level_isSet = false; + vox_hold = 0; + m_vox_hold_isSet = false; + audio_device_name = nullptr; + m_audio_device_name_isSet = false; use_reverse_api = 0; m_use_reverse_api_isSet = false; reverse_api_address = nullptr; @@ -70,6 +80,16 @@ SWGSimplePTTSettings::init() { m_rx2_tx_delay_ms_isSet = false; tx2_rx_delay_ms = 0; m_tx2_rx_delay_ms_isSet = false; + vox = 0; + m_vox_isSet = false; + vox_enable = 0; + m_vox_enable_isSet = false; + vox_level = 0; + m_vox_level_isSet = false; + vox_hold = 0; + m_vox_hold_isSet = false; + audio_device_name = new QString(""); + m_audio_device_name_isSet = false; use_reverse_api = 0; m_use_reverse_api_isSet = false; reverse_api_address = new QString(""); @@ -93,6 +113,13 @@ SWGSimplePTTSettings::cleanup() { + + + + if(audio_device_name != nullptr) { + delete audio_device_name; + } + if(reverse_api_address != nullptr) { delete reverse_api_address; } @@ -124,6 +151,16 @@ SWGSimplePTTSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&tx2_rx_delay_ms, pJson["tx2RxDelayMs"], "qint32", ""); + ::SWGSDRangel::setValue(&vox, pJson["vox"], "qint32", ""); + + ::SWGSDRangel::setValue(&vox_enable, pJson["voxEnable"], "qint32", ""); + + ::SWGSDRangel::setValue(&vox_level, pJson["voxLevel"], "qint32", ""); + + ::SWGSDRangel::setValue(&vox_hold, pJson["voxHold"], "qint32", ""); + + ::SWGSDRangel::setValue(&audio_device_name, pJson["audioDeviceName"], "QString", "QString"); + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); @@ -168,6 +205,21 @@ SWGSimplePTTSettings::asJsonObject() { if(m_tx2_rx_delay_ms_isSet){ obj->insert("tx2RxDelayMs", QJsonValue(tx2_rx_delay_ms)); } + if(m_vox_isSet){ + obj->insert("vox", QJsonValue(vox)); + } + if(m_vox_enable_isSet){ + obj->insert("voxEnable", QJsonValue(vox_enable)); + } + if(m_vox_level_isSet){ + obj->insert("voxLevel", QJsonValue(vox_level)); + } + if(m_vox_hold_isSet){ + obj->insert("voxHold", QJsonValue(vox_hold)); + } + if(audio_device_name != nullptr && *audio_device_name != QString("")){ + toJsonValue(QString("audioDeviceName"), audio_device_name, obj, QString("QString")); + } if(m_use_reverse_api_isSet){ obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); } @@ -247,6 +299,56 @@ SWGSimplePTTSettings::setTx2RxDelayMs(qint32 tx2_rx_delay_ms) { this->m_tx2_rx_delay_ms_isSet = true; } +qint32 +SWGSimplePTTSettings::getVox() { + return vox; +} +void +SWGSimplePTTSettings::setVox(qint32 vox) { + this->vox = vox; + this->m_vox_isSet = true; +} + +qint32 +SWGSimplePTTSettings::getVoxEnable() { + return vox_enable; +} +void +SWGSimplePTTSettings::setVoxEnable(qint32 vox_enable) { + this->vox_enable = vox_enable; + this->m_vox_enable_isSet = true; +} + +qint32 +SWGSimplePTTSettings::getVoxLevel() { + return vox_level; +} +void +SWGSimplePTTSettings::setVoxLevel(qint32 vox_level) { + this->vox_level = vox_level; + this->m_vox_level_isSet = true; +} + +qint32 +SWGSimplePTTSettings::getVoxHold() { + return vox_hold; +} +void +SWGSimplePTTSettings::setVoxHold(qint32 vox_hold) { + this->vox_hold = vox_hold; + this->m_vox_hold_isSet = true; +} + +QString* +SWGSimplePTTSettings::getAudioDeviceName() { + return audio_device_name; +} +void +SWGSimplePTTSettings::setAudioDeviceName(QString* audio_device_name) { + this->audio_device_name = audio_device_name; + this->m_audio_device_name_isSet = true; +} + qint32 SWGSimplePTTSettings::getUseReverseApi() { return use_reverse_api; @@ -320,6 +422,21 @@ SWGSimplePTTSettings::isSet(){ if(m_tx2_rx_delay_ms_isSet){ isObjectUpdated = true; break; } + if(m_vox_isSet){ + isObjectUpdated = true; break; + } + if(m_vox_enable_isSet){ + isObjectUpdated = true; break; + } + if(m_vox_level_isSet){ + isObjectUpdated = true; break; + } + if(m_vox_hold_isSet){ + isObjectUpdated = true; break; + } + if(audio_device_name && *audio_device_name != QString("")){ + isObjectUpdated = true; break; + } if(m_use_reverse_api_isSet){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.h b/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.h index 046d8c471..7deaf984e 100644 --- a/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGSimplePTTSettings.h @@ -60,6 +60,21 @@ public: qint32 getTx2RxDelayMs(); void setTx2RxDelayMs(qint32 tx2_rx_delay_ms); + qint32 getVox(); + void setVox(qint32 vox); + + qint32 getVoxEnable(); + void setVoxEnable(qint32 vox_enable); + + qint32 getVoxLevel(); + void setVoxLevel(qint32 vox_level); + + qint32 getVoxHold(); + void setVoxHold(qint32 vox_hold); + + QString* getAudioDeviceName(); + void setAudioDeviceName(QString* audio_device_name); + qint32 getUseReverseApi(); void setUseReverseApi(qint32 use_reverse_api); @@ -97,6 +112,21 @@ private: qint32 tx2_rx_delay_ms; bool m_tx2_rx_delay_ms_isSet; + qint32 vox; + bool m_vox_isSet; + + qint32 vox_enable; + bool m_vox_enable_isSet; + + qint32 vox_level; + bool m_vox_level_isSet; + + qint32 vox_hold; + bool m_vox_hold_isSet; + + QString* audio_device_name; + bool m_audio_device_name_isSet; + qint32 use_reverse_api; bool m_use_reverse_api_isSet;