From 79ac722e796180c81a729f5fc88d4e96da570faf Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 29 Dec 2021 21:20:06 +0100 Subject: [PATCH] PTT: vox (1) --- fcdhid/hid-libusb.c | 1 + fcdhid/hid-libusb.h | 1 + plugins/feature/simpleptt/simpleptt.cpp | 52 +++++++ plugins/feature/simpleptt/simpleptt.h | 2 + plugins/feature/simpleptt/simplepttgui.cpp | 72 ++++++++- plugins/feature/simpleptt/simplepttgui.h | 5 + plugins/feature/simpleptt/simplepttgui.ui | 143 ++++++++++++++++++ plugins/feature/simpleptt/simplepttreport.cpp | 1 + plugins/feature/simpleptt/simplepttreport.h | 22 ++- .../feature/simpleptt/simplepttsettings.cpp | 16 ++ plugins/feature/simpleptt/simplepttsettings.h | 5 + plugins/feature/simpleptt/simplepttworker.cpp | 132 ++++++++++++++-- plugins/feature/simpleptt/simplepttworker.h | 18 ++- sdrbase/resources/webapi/doc/html2/index.html | 21 ++- .../webapi/doc/swagger/include/SimplePTT.yaml | 20 +++ sdrgui/resources/audio_mic.png | Bin 0 -> 7252 bytes sdrgui/resources/res.qrc | 1 + .../api/swagger/include/SimplePTT.yaml | 20 +++ swagger/sdrangel/code/html2/index.html | 21 ++- .../code/qt5/client/SWGSimplePTTSettings.cpp | 117 ++++++++++++++ .../code/qt5/client/SWGSimplePTTSettings.h | 30 ++++ 21 files changed, 684 insertions(+), 16 deletions(-) create mode 100644 sdrgui/resources/audio_mic.png 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 0000000000000000000000000000000000000000..d9494c539ba059bb74b800bd5ef31c398018f0cc GIT binary patch literal 7252 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 literal 0 HcmV?d00001 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;