1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-21 23:55:13 -05:00

Compare commits

..

3 Commits

Author SHA1 Message Date
f4exb
7142ef0b0d Updated versions and changelogs 2022-01-03 19:46:20 +01:00
f4exb
afc106b51f Simple PTT feature: implemented vox. Issue #1002 2022-01-03 19:08:47 +01:00
f4exb
79ac722e79 PTT: vox (1) 2022-01-03 19:08:47 +01:00
31 changed files with 756 additions and 26 deletions

View File

@ -1,3 +1,12 @@
sdrangel (6.17.7-1) unstable; urgency=medium
* Simple PTT feature: added vox control. Implements #1002
* Fix FileInput API report of absolute time following PR #981. PR #1094
* Support compilation with Boost >= 1.77. Fix for #1087. PR #1092
* Fixed some compiler warnings with Qt 5.15 and GCC 11
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Mon, 03 Jan 2022 18:24:33 +0100
sdrangel (6.17.6-1) unstable; urgency=medium
* Remote plugins: added capability to choose sample size in transmission. Implements #1078

View File

@ -16,7 +16,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# configure version
set(sdrangel_VERSION_MAJOR "6")
set(sdrangel_VERSION_MINOR "17")
set(sdrangel_VERSION_PATCH "6")
set(sdrangel_VERSION_PATCH "7")
set(sdrangel_VERSION_SUFFIX "")
# SDRAngel cmake options

9
debian/changelog vendored
View File

@ -1,3 +1,12 @@
sdrangel (6.17.7-1) unstable; urgency=medium
* Simple PTT feature: added vox control. Implements #1002
* Fix FileInput API report of absolute time following PR #981. PR #1094
* Support compilation with Boost >= 1.77. Fix for #1087. PR #1092
* Fixed some compiler warnings with Qt 5.15 and GCC 11
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Mon, 03 Jan 2022 18:24:33 +0100
sdrangel (6.17.6-1) unstable; urgency=medium
* Remote plugins: added capability to choose sample size in transmission. Implements #1078

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

BIN
doc/img/SimplePTT_vox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
doc/img/SimplePTT_vox.xcf Normal file

Binary file not shown.

View File

@ -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;
}

View File

@ -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;
}

View File

@ -6,7 +6,7 @@ This plugin controls switchover between a Rx (Device source) and Tx (Device sink
<h2>Interface</h2>
![File source channel plugin GUI](../../../doc/img/SimplePTT_plugin.png)
![PTT feature plugin GUI](../../../doc/img/SimplePTT_plugin.png)
<h3>1: Start/Stop plugin</h3>
@ -24,22 +24,52 @@ This LED type display shows the current PTT status:
- **Red**: Tx runs
- **Grey**: None active (transient)
<h3>4: Refresh list of devices</h3>
<h3>4: Vox control</h3>
![PTT feature vox control](../../../doc/img/SimplePTT_vox.png)
<h4>4.1: Activate vox system</h4>
Toggle this switch to activate or de-activate vox control. When activated the audio input level is monitored and appears in (4.5) and if the level exceeds the level set by (4.3) and displayed in (4.4) then the vox button turns green until vox goes off after the hold period (4.6). The vox system controls the PTT only if the vox PTT enable checkbox is checked (4.2). Thus you can set the appropriate level (4.3) before engaging PTT control.
Right click on this button to open the audio input device selection dialog.
<h4>4.2: Enable PTT control</h4>
Check this box to enable PTT control by the vox system.
<h4>4.3: Vox threshold level</h4>
Use this button to adjust the vox threshold level in power dB (0 dB = full range)
<h4>4.4: Vox threshold display</h4>
This is the value set by (4.3) in dB.
<h4>4.5: Audio input level</h4>
This is the audio input level in dB displayed when the vox system is active (4.1)
<h4>4.6: Vox hold period</h4>
The vox is held active for this amount of time in milliseconds after the audio input power goes below the threshold level (4.3)
<h3>5: Refresh list of devices</h3>
Use this button to refresh the list of devices (5) and (6)
<h3>5: Select Rx device set</h3>
<h3>6: Select Rx device set</h3>
Use this combo to select which Rx device is controlled
<h3>6: Select Tx device set</h3>
<h3>7: Select Tx device set</h3>
Use this combo to select which Tx device is controlled
<h3>7: Transistion delay from Rx to Tx</h3>
<h3>8: Transistion delay from Rx to Tx</h3>
Value in milliseconds between Rx stop and Tx start
<h3>8: Transistion delay from Tx to Rx</h3>
<h3>9: Transistion delay from Tx to Rx</h3>
Value in milliseconds between Tx stop and Rx start

View File

@ -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<QString> 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<QString>& 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)

View File

@ -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;

View File

@ -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->voxLevel->setStyleSheet("QDial { background-color : green; }");
} else {
ui->voxLevel->setStyleSheet("QDial { 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);
}
@ -307,6 +331,13 @@ void SimplePTTGUI::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
if (checked)
{
updateDeviceSetLists();
displaySettings();
applySettings();
}
SimplePTT::MsgStartStop *message = SimplePTT::MsgStartStop::create(checked);
m_simplePTT->getInputMessageQueue()->push(message);
}
@ -354,6 +385,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("%1").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 +437,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)
@ -396,7 +460,21 @@ void SimplePTTGUI::applyPTT(bool tx)
{
if (m_doApplySettings)
{
qDebug("SimplePTTGUI::applyPTT: %s", tx ? "tx" : "rx");
SimplePTT::MsgPTT* message = SimplePTT::MsgPTT::create(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();
}
}

View File

@ -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();
};

View File

@ -92,6 +92,7 @@
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold>
@ -132,6 +133,148 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="voxLayout">
<item>
<widget class="ButtonSwitch" name="vox">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Toggle vox system - right click to select audio device</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/audio_mic.png</normaloff>:/audio_mic.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="voxEnable">
<property name="toolTip">
<string>Enable vox to control PTT</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="voxLevel">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Vox threshold (dB)</string>
</property>
<property name="minimum">
<number>-99</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>-20</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="voxLevelText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>-20</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="audioPeak">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Audio signal peak in dB (with Vox on)</string>
</property>
<property name="toolTipDuration">
<number>14</number>
</property>
<property name="text">
<string>-100 dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="voxHold">
<property name="toolTip">
<string>Vox delay (ms)</string>
</property>
<property name="minimum">
<number>500</number>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="voxHoldUnits">
<property name="text">
<string>ms</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="localDeviceLayout">
<item>

View File

@ -29,7 +29,7 @@
const PluginDescriptor SimplePTTPlugin::m_pluginDescriptor = {
SimplePTT::m_featureId,
QStringLiteral("Simple PTT"),
QStringLiteral("6.17.2"),
QStringLiteral("6.17.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -18,6 +18,7 @@
#include "simplepttreport.h"
MESSAGE_CLASS_DEFINITION(SimplePTTReport::MsgRadioState, Message)
MESSAGE_CLASS_DEFINITION(SimplePTTReport::MsgVox, Message)
SimplePTTReport::SimplePTTReport()
{}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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()
@ -94,7 +106,7 @@ bool SimplePTTWorker::handleMessage(const Message& cmd)
else if (MsgPTT::match(cmd))
{
MsgPTT& cfg = (MsgPTT&) cmd;
qDebug() << "SimplePTTWorker::handleMessage: MsgPTT";
qDebug() << "SimplePTTWorker::handleMessage: MsgPTT tx:" << cfg.getTx();
sendPTT(cfg.getTx());
@ -115,40 +127,84 @@ 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);
m_voxHoldCount = 0;
m_voxState = false;
}
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;
}
void SimplePTTWorker::sendPTT(bool tx)
{
qDebug("SimplePTTWorker::sendPTT: %s", tx ? "tx" : "rx");
if (!m_updateTimer.isActive())
{
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);
@ -165,6 +221,7 @@ void SimplePTTWorker::sendPTT(bool tx)
void SimplePTTWorker::updateHardware()
{
qDebug("SimplePTTWorker::updateHardware: m_tx: %s", m_tx ? "on" : "off");
SWGSDRangel::SWGSuccessResponse response;
SWGSDRangel::SWGErrorResponse error;
m_updateTimer.stop();
@ -187,10 +244,11 @@ void SimplePTTWorker::updateHardware()
bool SimplePTTWorker::turnDevice(bool on)
{
qDebug("SimplePTTWorker::turnDevice %s: %s", m_tx ? "tx" : "rx", on ? "on" : "off");
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);
@ -201,6 +259,7 @@ bool SimplePTTWorker::turnDevice(bool on)
if (httpCode/100 == 2)
{
qDebug("SimplePTTWorker::turnDevice: %s success", on ? "on" : "off");
return true;
}
else
@ -208,4 +267,63 @@ bool SimplePTTWorker::turnDevice(bool on)
qWarning("SimplePTTWorker::turnDevice: error: %s", qPrintable(*error.getMessage()));
return false;
}
}
}
void SimplePTTWorker::handleAudio()
{
unsigned int nbRead;
QMutexLocker mlock(&m_mutex);
while ((nbRead = m_audioFifo.read(reinterpret_cast<quint8*>(&m_audioReadBuffer[m_audioReadBufferFill]), 4096)) != 0)
{
if (m_audioReadBufferFill + nbRead + 4096 < m_audioReadBuffer.size())
{
m_audioReadBufferFill += nbRead;
}
else
{
bool voxState = m_voxState;
for (unsigned int i = 0; i < m_audioReadBufferFill; i++)
{
std::complex<float> za{m_audioReadBuffer[i].l / 46334.0f, m_audioReadBuffer[i].r / 46334.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;
}
}
}

View File

@ -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_
#endif // INCLUDE_FEATURE_SIMPLEPTTWORKER_H_

View File

@ -31,7 +31,7 @@
const PluginDescriptor FileInputPlugin::m_pluginDescriptor = {
QStringLiteral("FileInput"),
QStringLiteral("File device input"),
QStringLiteral("6.17.5"),
QStringLiteral("6.17.7"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,

View File

@ -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:
</div>
<div id="generator">
<div class="content">
Generated 2021-12-27T21:57:14.290+01:00
Generated 2021-12-29T17:23:49.058+01:00
</div>
</div>
</div>

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/">
<file>audio_mic.png</file>
<file>info.png</file>
<file>darklight.png</file>
<file>lightdark.png</file>

View File

@ -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

View File

@ -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:
</div>
<div id="generator">
<div class="content">
Generated 2021-12-27T21:57:14.290+01:00
Generated 2021-12-29T17:23:49.058+01:00
</div>
</div>
</div>

View File

@ -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;
}

View File

@ -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;