diff --git a/plugins/channelrx/udpsink/udpsink.cpp b/plugins/channelrx/udpsink/udpsink.cpp index ba828f590..240584867 100644 --- a/plugins/channelrx/udpsink/udpsink.cpp +++ b/plugins/channelrx/udpsink/udpsink.cpp @@ -17,6 +17,9 @@ #include #include +#include +#include +#include #include "SWGChannelSettings.h" #include "SWGUDPSinkSettings.h" @@ -110,10 +113,15 @@ UDPSink::UDPSink(DeviceSourceAPI *deviceAPI) : m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_deviceAPI->addThreadedSink(m_threadedChannelizer); m_deviceAPI->addChannelAPI(this); + + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } UDPSink::~UDPSink() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; delete m_audioSocket; delete m_udpBuffer24; delete m_udpBuffer16; @@ -505,6 +513,57 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force) << " m_audioPort: " << settings.m_audioPort << " force: " << force; + QList reverseAPIKeys; + + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) { + reverseAPIKeys.append("inputFrequencyOffset"); + } + if ((settings.m_audioActive != m_settings.m_audioActive) || force) { + reverseAPIKeys.append("audioActive"); + } + if ((settings.m_audioStereo != m_settings.m_audioStereo) || force) { + reverseAPIKeys.append("audioStereo"); + } + if ((settings.m_gain != m_settings.m_gain) || force) { + reverseAPIKeys.append("gain"); + } + if ((settings.m_volume != m_settings.m_volume) || force) { + reverseAPIKeys.append("volume"); + } + if ((settings.m_squelchEnabled != m_settings.m_squelchEnabled) || force) { + reverseAPIKeys.append("squelchEnabled"); + } + if ((settings.m_squelchdB != m_settings.m_squelchdB) || force) { + reverseAPIKeys.append("squelchDB"); + } + if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) { + reverseAPIKeys.append("squelchGate"); + } + if ((settings.m_agc != m_settings.m_agc) || force) { + reverseAPIKeys.append("agc"); + } + if ((settings.m_sampleFormat != m_settings.m_sampleFormat) || force) { + reverseAPIKeys.append("sampleFormat"); + } + if ((settings.m_outputSampleRate != m_settings.m_outputSampleRate) || force) { + reverseAPIKeys.append("outputSampleRate"); + } + if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { + reverseAPIKeys.append("rfBandwidth"); + } + if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) { + reverseAPIKeys.append("fmDeviation"); + } + if ((settings.m_udpAddress != m_settings.m_udpAddress) || force) { + reverseAPIKeys.append("udpAddress"); + } + if ((settings.m_udpPort != m_settings.m_udpPort) || force) { + reverseAPIKeys.append("udpPort"); + } + if ((settings.m_audioPort != m_settings.m_audioPort) || force) { + reverseAPIKeys.append("audioPort"); + } + m_settingsMutex.lock(); if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || @@ -617,6 +676,16 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force) m_settingsMutex.unlock(); + if (settings.m_useReverseAPI) + { + bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || + (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) || + (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) || + (m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) || + (m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + m_settings = settings; } @@ -798,3 +867,108 @@ void UDPSink::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) response.getUdpSinkReport()->setSquelch(m_squelchOpen ? 1 : 0); response.getUdpSinkReport()->setInputSampleRate(m_inputSampleRate); } + +void UDPSink::webapiReverseSendSettings(QList& channelSettingsKeys, const UDPSinkSettings& settings, bool force) +{ + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + swgChannelSettings->setTx(0); + swgChannelSettings->setChannelType(new QString("UDPSink")); + swgChannelSettings->setUdpSinkSettings(new SWGSDRangel::SWGUDPSinkSettings()); + SWGSDRangel::SWGUDPSinkSettings *swgUDPSinkSettings = swgChannelSettings->getUdpSinkSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("outputSampleRate") || force) { + swgUDPSinkSettings->setOutputSampleRate(settings.m_outputSampleRate); + } + if (channelSettingsKeys.contains("sampleFormat") || force) { + swgUDPSinkSettings->setSampleFormat((int) settings.m_sampleFormat); + } + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgUDPSinkSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgUDPSinkSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("fmDeviation") || force) { + swgUDPSinkSettings->setFmDeviation(settings.m_fmDeviation); + } + if (channelSettingsKeys.contains("channelMute") || force) { + swgUDPSinkSettings->setChannelMute(settings.m_channelMute ? 1 : 0); + } + if (channelSettingsKeys.contains("gain") || force) { + swgUDPSinkSettings->setGain(settings.m_gain); + } + if (channelSettingsKeys.contains("squelchDB") || force) { + swgUDPSinkSettings->setSquelchDb(settings.m_squelchdB); + } + if (channelSettingsKeys.contains("squelchGate") || force) { + swgUDPSinkSettings->setSquelchGate(settings.m_squelchGate); + } + if (channelSettingsKeys.contains("squelchEnabled") || force) { + swgUDPSinkSettings->setSquelchEnabled(settings.m_squelchEnabled ? 1 : 0); + } + if (channelSettingsKeys.contains("agc") || force) { + swgUDPSinkSettings->setAgc(settings.m_agc ? 1 : 0); + } + if (channelSettingsKeys.contains("audioActive") || force) { + swgUDPSinkSettings->setAudioActive(settings.m_audioActive ? 1 : 0); + } + if (channelSettingsKeys.contains("audioStereo") || force) { + swgUDPSinkSettings->setAudioStereo(settings.m_audioStereo ? 1 : 0); + } + if (channelSettingsKeys.contains("volume") || force) { + swgUDPSinkSettings->setVolume(settings.m_volume); + } + if (channelSettingsKeys.contains("udpAddress") || force) { + swgUDPSinkSettings->setUdpAddress(new QString(settings.m_udpAddress)); + } + if (channelSettingsKeys.contains("udpPort") || force) { + swgUDPSinkSettings->setUdpPort(settings.m_udpPort); + } + if (channelSettingsKeys.contains("audioPort") || force) { + swgUDPSinkSettings->setAudioPort(settings.m_audioPort); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgUDPSinkSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("title") || force) { + swgUDPSinkSettings->setTitle(new QString(settings.m_title)); + } + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIDeviceIndex) + .arg(settings.m_reverseAPIChannelIndex); + m_networkRequest.setUrl(QUrl(channelSettingsURL)); + m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QBuffer *buffer=new QBuffer(); + buffer->open((QBuffer::ReadWrite)); + buffer->write(swgChannelSettings->asJson().toUtf8()); + buffer->seek(0); + + // Always use PATCH to avoid passing reverse API settings + m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + + delete swgChannelSettings; +} + +void UDPSink::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "UDPSink::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("UDPSink::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/channelrx/udpsink/udpsink.h b/plugins/channelrx/udpsink/udpsink.h index 5923226b0..9f2e7a919 100644 --- a/plugins/channelrx/udpsink/udpsink.h +++ b/plugins/channelrx/udpsink/udpsink.h @@ -20,6 +20,7 @@ #include #include +#include #include "dsp/basebandsamplesink.h" #include "channel/channelsinkapi.h" @@ -36,6 +37,8 @@ #include "udpsinksettings.h" +class QNetworkAccessManager; +class QNetworkReply; class QUdpSocket; class DeviceSourceAPI; class ThreadedBasebandSampleSink; @@ -135,6 +138,9 @@ public: public slots: void audioReadyRead(); +private slots: + void networkManagerFinished(QNetworkReply *reply); + protected: class MsgUDPSinkSpectrum : public Message { MESSAGE_CLASS_DECLARATION @@ -227,6 +233,9 @@ protected: MagAGC m_agc; Bandpass m_bandpass; + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + QMutex m_settingsMutex; void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = true); @@ -234,6 +243,7 @@ protected: void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const UDPSinkSettings& settings); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); + void webapiReverseSendSettings(QList& channelSettingsKeys, const UDPSinkSettings& settings, bool force); inline void calculateSquelch(double value) { diff --git a/plugins/channelrx/udpsink/udpsinkgui.cpp b/plugins/channelrx/udpsink/udpsinkgui.cpp index c4c8a06bb..ab50c9bd2 100644 --- a/plugins/channelrx/udpsink/udpsinkgui.cpp +++ b/plugins/channelrx/udpsink/udpsinkgui.cpp @@ -615,13 +615,23 @@ void UDPSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) void UDPSinkGUI::onMenuDialogCalled(const QPoint &p) { BasicChannelSettingsDialog dialog(&m_channelMarker, this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); diff --git a/plugins/channelrx/udpsink/udpsinksettings.cpp b/plugins/channelrx/udpsink/udpsinksettings.cpp index fdf24a6d8..d67c1b98b 100644 --- a/plugins/channelrx/udpsink/udpsinksettings.cpp +++ b/plugins/channelrx/udpsink/udpsinksettings.cpp @@ -49,6 +49,11 @@ void UDPSinkSettings::resetToDefaults() m_audioPort = 9997; m_rgbColor = QColor(225, 25, 99).rgb(); m_title = "UDP Sample Sink"; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; + m_reverseAPIChannelIndex = 0; } QByteArray UDPSinkSettings::serialize() const @@ -80,6 +85,11 @@ QByteArray UDPSinkSettings::serialize() const s.writeString(20, m_udpAddress); s.writeU32(21, m_udpPort); s.writeU32(22, m_audioPort); + s.writeBool(23, m_useReverseAPI); + s.writeString(24, m_reverseAPIAddress); + s.writeU32(25, m_reverseAPIPort); + s.writeU32(26, m_reverseAPIDeviceIndex); + s.writeU32(27, m_reverseAPIChannelIndex); return s.final(); @@ -155,6 +165,21 @@ bool UDPSinkSettings::deserialize(const QByteArray& data) m_audioPort = 9997; } + d.readBool(23, &m_useReverseAPI, false); + d.readString(24, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(25, &u32tmp, 0); + + if ((u32tmp > 1023) && (u32tmp < 65535)) { + m_reverseAPIPort = u32tmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(26, &u32tmp, 0); + m_reverseAPIDeviceIndex = u32tmp > 99 ? 99 : u32tmp; + d.readU32(27, &u32tmp, 0); + m_reverseAPIChannelIndex = u32tmp > 99 ? 99 : u32tmp; + return true; } else diff --git a/plugins/channelrx/udpsink/udpsinksettings.h b/plugins/channelrx/udpsink/udpsinksettings.h index c825ead71..3007ec4c0 100644 --- a/plugins/channelrx/udpsink/udpsinksettings.h +++ b/plugins/channelrx/udpsink/udpsinksettings.h @@ -62,6 +62,12 @@ struct UDPSinkSettings QString m_title; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; + uint16_t m_reverseAPIChannelIndex; + Serializable *m_channelMarker; Serializable *m_spectrumGUI;