SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
udpsink.cpp
Go to the documentation of this file.
1 // Copyright (C) 2015 F4EXB //
3 // written by Edouard Griffiths //
4 // //
5 // This program is free software; you can redistribute it and/or modify //
6 // it under the terms of the GNU General Public License as published by //
7 // the Free Software Foundation as version 3 of the License, or //
8 // (at your option) any later version. //
9 // //
10 // This program is distributed in the hope that it will be useful, //
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
13 // GNU General Public License V3 for more details. //
14 // //
15 // You should have received a copy of the GNU General Public License //
16 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
18 
19 #include <QUdpSocket>
20 #include <QHostAddress>
21 #include <QNetworkAccessManager>
22 #include <QNetworkReply>
23 #include <QBuffer>
24 
25 #include "SWGChannelSettings.h"
26 #include "SWGUDPSinkSettings.h"
27 #include "SWGChannelReport.h"
28 #include "SWGUDPSinkReport.h"
29 
30 #include "dsp/dspengine.h"
31 #include "util/db.h"
32 #include "dsp/downchannelizer.h"
34 #include "dsp/dspcommands.h"
35 #include "device/deviceapi.h"
36 
37 #include "udpsink.h"
38 
39 const Real UDPSink::m_agcTarget = 16384.0f;
40 
44 
45 const QString UDPSink::m_channelIdURI = "sdrangel.channel.udpsink";
46 const QString UDPSink::m_channelId = "UDPSink";
47 
49  ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
50  m_deviceAPI(deviceAPI),
51  m_inputSampleRate(48000),
52  m_inputFrequencyOffset(0),
53  m_outMovingAverage(480, 1e-10),
54  m_inMovingAverage(480, 1e-10),
55  m_amMovingAverage(1200, 1e-10),
56  m_audioFifo(24000),
57  m_spectrum(0),
58  m_squelch(1e-6),
59  m_squelchOpen(false),
60  m_squelchOpenCount(0),
61  m_squelchCloseCount(0),
62  m_squelchGate(4800),
63  m_squelchRelease(4800),
64  m_agc(9600, m_agcTarget, 1e-6),
65  m_settingsMutex(QMutex::Recursive)
66 {
67  setObjectName(m_channelId);
68 
72  m_audioSocket = new QUdpSocket(this);
74 
75  m_audioBuffer.resize(1<<9);
77 
81  m_spectrumEnabled = false;
82  m_nextSSBId = 0;
83  m_nextS16leId = 0;
84 
85  m_last = 0;
86  m_this = 0;
87  m_scale = 0;
88  m_magsq = 0;
89  m_inMagsq = 0;
90 
91  UDPFilter = new fftfilt(0.0, (m_settings.m_rfBandwidth / 2.0) / m_settings.m_outputSampleRate, udpBlockSize);
92 
93  m_phaseDiscri.setFMScaling((float) m_settings. m_outputSampleRate / (2.0f * m_settings.m_fmDeviation));
94 
95  if (m_audioSocket->bind(QHostAddress::LocalHost, m_settings.m_audioPort))
96  {
97  qDebug("UDPSink::UDPSink: bind audio socket to port %d", m_settings.m_audioPort);
98  connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection);
99  }
100  else
101  {
102  qWarning("UDPSink::UDPSink: cannot bind audio port");
103  }
104 
106  m_agc.setClamping(true);
107 
108  //DSPEngine::instance()->addAudioSink(&m_audioFifo);
109 
111  applySettings(m_settings, true);
112 
113  m_channelizer = new DownChannelizer(this);
117 
118  m_networkManager = new QNetworkAccessManager();
119  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
120 }
121 
123 {
124  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
125  delete m_networkManager;
126  delete m_audioSocket;
127  delete m_udpBuffer24;
128  delete m_udpBuffer16;
129  delete m_udpBufferMono16;
130  delete[] m_udpAudioBuf;
134  delete m_threadedChannelizer;
135  delete m_channelizer;
136  delete UDPFilter;
137 }
138 
139 void UDPSink::setSpectrum(MessageQueue* messageQueue, bool enabled)
140 {
141  Message* cmd = MsgUDPSinkSpectrum::create(enabled);
142  messageQueue->push(cmd);
143 }
144 
145 void UDPSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly)
146 {
147  Complex ci;
148  fftfilt::cmplx* sideband;
149  double l, r;
150 
151  m_sampleBuffer.clear();
152  m_settingsMutex.lock();
153 
154  for(SampleVector::const_iterator it = begin; it < end; ++it)
155  {
156  Complex c(it->real(), it->imag());
157  c *= m_nco.nextIQ();
158 
160  {
161  double inMagSq;
162  double agcFactor = 1.0;
163 
164  if ((m_settings.m_agc) &&
169  {
170  agcFactor = m_agc.feedAndGetValue(ci);
171  inMagSq = m_agc.getMagSq();
172  }
173  else
174  {
175  inMagSq = ci.real()*ci.real() + ci.imag()*ci.imag();
176  }
177 
180 
181  Sample ss(ci.real(), ci.imag());
182  m_sampleBuffer.push_back(ss);
183 
185 
187 
189  {
190  ci *= agcFactor;
191  int n_out = UDPFilter->runSSB(ci, &sideband, false);
192 
193  if (n_out)
194  {
195  for (int i = 0; i < n_out; i++)
196  {
197  l = m_squelchOpen ? sideband[i].real() * m_settings.m_gain : 0;
198  r = m_squelchOpen ? sideband[i].imag() * m_settings.m_gain : 0;
199  udpWrite(l, r);
200  m_outMovingAverage.feed((l*l + r*r) / (SDR_RX_SCALED*SDR_RX_SCALED));
201  }
202  }
203  }
205  {
206  ci *= agcFactor;
207  int n_out = UDPFilter->runSSB(ci, &sideband, true);
208 
209  if (n_out)
210  {
211  for (int i = 0; i < n_out; i++)
212  {
213  l = m_squelchOpen ? sideband[i].real() * m_settings.m_gain : 0;
214  r = m_squelchOpen ? sideband[i].imag() * m_settings.m_gain : 0;
215  udpWrite(l, r);
216  m_outMovingAverage.feed((l*l + r*r) / (SDR_RX_SCALED*SDR_RX_SCALED));
217  }
218  }
219  }
221  {
223  udpWriteNorm(discri, discri);
224  m_outMovingAverage.feed(discri*discri);
225  }
227  {
229  udpWriteNormMono(discri);
230  m_outMovingAverage.feed(discri*discri);
231  }
232  else if (m_settings.m_sampleFormat == UDPSinkSettings::FormatLSBMono) // Monaural LSB
233  {
234  ci *= agcFactor;
235  int n_out = UDPFilter->runSSB(ci, &sideband, false);
236 
237  if (n_out)
238  {
239  for (int i = 0; i < n_out; i++)
240  {
241  l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_settings.m_gain : 0;
242  udpWriteMono(l);
243  m_outMovingAverage.feed((l * l) / (SDR_RX_SCALED*SDR_RX_SCALED));
244  }
245  }
246  }
247  else if (m_settings.m_sampleFormat == UDPSinkSettings::FormatUSBMono) // Monaural USB
248  {
249  ci *= agcFactor;
250  int n_out = UDPFilter->runSSB(ci, &sideband, true);
251 
252  if (n_out)
253  {
254  for (int i = 0; i < n_out; i++)
255  {
256  l = m_squelchOpen ? (sideband[i].real() + sideband[i].imag()) * 0.7 * m_settings.m_gain : 0;
257  udpWriteMono(l);
258  m_outMovingAverage.feed((l * l) / (SDR_RX_SCALED*SDR_RX_SCALED));
259  }
260  }
261  }
263  {
264  Real amplitude = m_squelchOpen ? sqrt(inMagSq) * agcFactor * m_settings.m_gain : 0;
265  FixReal demod = (FixReal) amplitude;
266  udpWriteMono(demod);
267  m_outMovingAverage.feed((amplitude/SDR_RX_SCALEF)*(amplitude/SDR_RX_SCALEF));
268  }
270  {
271  if (m_squelchOpen)
272  {
273  double demodf = sqrt(inMagSq);
274  m_amMovingAverage.feed(demodf);
275  Real amplitude = (demodf - m_amMovingAverage.average()) * agcFactor * m_settings.m_gain;
276  FixReal demod = (FixReal) amplitude;
277  udpWriteMono(demod);
278  m_outMovingAverage.feed((amplitude/SDR_RX_SCALEF)*(amplitude/SDR_RX_SCALEF));
279  }
280  else
281  {
282  udpWriteMono(0);
284  }
285  }
287  {
288  if (m_squelchOpen)
289  {
290  double demodf = sqrt(inMagSq);
291  demodf = m_bandpass.filter(demodf);
292  demodf /= 301.0;
293  Real amplitude = demodf * agcFactor * m_settings.m_gain;
294  FixReal demod = (FixReal) amplitude;
295  udpWriteMono(demod);
296  m_outMovingAverage.feed((amplitude/SDR_RX_SCALEF)*(amplitude/SDR_RX_SCALEF));
297  }
298  else
299  {
300  udpWriteMono(0);
302  }
303  }
304  else // Raw I/Q samples
305  {
306  if (m_squelchOpen)
307  {
308  udpWrite(ci.real() * m_settings.m_gain, ci.imag() * m_settings.m_gain);
309  m_outMovingAverage.feed((inMagSq*m_settings.m_gain*m_settings.m_gain) / (SDR_RX_SCALED*SDR_RX_SCALED));
310  }
311  else
312  {
313  udpWrite(0, 0);
315  }
316  }
317 
319  }
320  }
321 
322  //qDebug() << "UDPSink::feed: " << m_sampleBuffer.size() * 4;
323 
324  if((m_spectrum != 0) && (m_spectrumEnabled))
325  {
326  m_spectrum->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), positiveOnly);
327  }
328 
329  m_settingsMutex.unlock();
330 }
331 
333 {
336 }
337 
339 {
340 }
341 
343 {
345  {
347  qDebug() << "UDPSink::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << notif.getSampleRate()
348  << " frequencyOffset: " << notif.getFrequencyOffset();
349 
351 
352 
353  return true;
354  }
355  else if (MsgConfigureChannelizer::match(cmd))
356  {
358  qDebug() << "UDPSink::handleMessage: MsgConfigureChannelizer:"
359  << " sampleRate: " << cfg.getSampleRate()
360  << " centerFrequency: " << cfg.getCenterFrequency();
361 
363  cfg.getSampleRate(),
364  cfg.getCenterFrequency());
365 
366  return true;
367  }
368  else if (MsgConfigureUDPSource::match(cmd))
369  {
371  qDebug("UDPSink::handleMessage: MsgConfigureUDPSource");
372 
373  applySettings(cfg.getSettings(), cfg.getForce());
374 
375  return true;
376  }
377  else if (MsgUDPSinkSpectrum::match(cmd))
378  {
380 
382 
383  qDebug() << "UDPSink::handleMessage: MsgUDPSinkSpectrum: m_spectrumEnabled: " << m_spectrumEnabled;
384 
385  return true;
386  }
387  else if (DSPSignalNotification::match(cmd))
388  {
389  return true;
390  }
391  else
392  {
393  if(m_spectrum != 0)
394  {
395  return m_spectrum->handleMessage(cmd);
396  }
397  else
398  {
399  return false;
400  }
401  }
402 }
403 
405 {
406  while (m_audioSocket->hasPendingDatagrams())
407  {
408  qint64 pendingDataSize = m_audioSocket->pendingDatagramSize();
409  qint64 udpReadBytes = m_audioSocket->readDatagram(m_udpAudioBuf, pendingDataSize, 0, 0);
410  //qDebug("UDPSink::audioReadyRead: %lld", udpReadBytes);
411 
413  {
415  {
416  for (int i = 0; i < udpReadBytes - 3; i += 4)
417  {
418  qint16 l_sample = (qint16) *(&m_udpAudioBuf[i]);
419  qint16 r_sample = (qint16) *(&m_udpAudioBuf[i+2]);
423 
424  if (m_audioBufferFill >= m_audioBuffer.size())
425  {
426  uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
427 
428  if (res != m_audioBufferFill)
429  {
430  qDebug("UDPSink::audioReadyRead: (stereo) lost %u samples", m_audioBufferFill - res);
431  }
432 
433  m_audioBufferFill = 0;
434  }
435  }
436  }
437  else
438  {
439  for (int i = 0; i < udpReadBytes - 1; i += 2)
440  {
441  qint16 sample = (qint16) *(&m_udpAudioBuf[i]);
445 
446  if (m_audioBufferFill >= m_audioBuffer.size())
447  {
448  uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
449 
450  if (res != m_audioBufferFill)
451  {
452  qDebug("UDPSink::audioReadyRead: (mono) lost %u samples", m_audioBufferFill - res);
453  }
454 
455  m_audioBufferFill = 0;
456  }
457  }
458  }
459 
461  {
462  qDebug("UDPSink::audioReadyRead: lost samples");
463  }
464 
465  m_audioBufferFill = 0;
466  }
467  }
468 
469  //qDebug("UDPSink::audioReadyRead: done");
470 }
471 
472 void UDPSink::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force)
473 {
474  qDebug() << "UDPSink::applyChannelSettings:"
475  << " inputSampleRate: " << inputSampleRate
476  << " inputFrequencyOffset: " << inputFrequencyOffset;
477 
478  if((inputFrequencyOffset != m_inputFrequencyOffset) ||
479  (inputSampleRate != m_inputSampleRate) || force)
480  {
481  m_nco.setFreq(-inputFrequencyOffset, inputSampleRate);
482  }
483 
484  if ((inputSampleRate != m_inputSampleRate) || force)
485  {
486  m_settingsMutex.lock();
487  m_interpolator.create(16, inputSampleRate, m_settings.m_rfBandwidth / 2.0);
489  m_settingsMutex.unlock();
490  }
491 
492  m_inputSampleRate = inputSampleRate;
493  m_inputFrequencyOffset = inputFrequencyOffset;
494 }
495 
496 void UDPSink::applySettings(const UDPSinkSettings& settings, bool force)
497 {
498  qDebug() << "UDPSink::applySettings:"
499  << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
500  << " m_audioActive: " << settings.m_audioActive
501  << " m_audioStereo: " << settings.m_audioStereo
502  << " m_gain: " << settings.m_gain
503  << " m_volume: " << settings.m_volume
504  << " m_squelchEnabled: " << settings.m_squelchEnabled
505  << " m_squelchdB: " << settings.m_squelchdB
506  << " m_squelchGate" << settings.m_squelchGate
507  << " m_agc" << settings.m_agc
508  << " m_sampleFormat: " << settings.m_sampleFormat
509  << " m_outputSampleRate: " << settings.m_outputSampleRate
510  << " m_rfBandwidth: " << settings.m_rfBandwidth
511  << " m_fmDeviation: " << settings.m_fmDeviation
512  << " m_udpAddressStr: " << settings.m_udpAddress
513  << " m_udpPort: " << settings.m_udpPort
514  << " m_audioPort: " << settings.m_audioPort
515  << " m_useReverseAPI: " << settings.m_useReverseAPI
516  << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
517  << " m_reverseAPIPort: " << settings.m_reverseAPIPort
518  << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
519  << " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
520  << " force: " << force;
521 
522  QList<QString> reverseAPIKeys;
523 
524  if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
525  reverseAPIKeys.append("inputFrequencyOffset");
526  }
527  if ((settings.m_audioActive != m_settings.m_audioActive) || force) {
528  reverseAPIKeys.append("audioActive");
529  }
530  if ((settings.m_audioStereo != m_settings.m_audioStereo) || force) {
531  reverseAPIKeys.append("audioStereo");
532  }
533  if ((settings.m_gain != m_settings.m_gain) || force) {
534  reverseAPIKeys.append("gain");
535  }
536  if ((settings.m_volume != m_settings.m_volume) || force) {
537  reverseAPIKeys.append("volume");
538  }
539  if ((settings.m_squelchEnabled != m_settings.m_squelchEnabled) || force) {
540  reverseAPIKeys.append("squelchEnabled");
541  }
542  if ((settings.m_squelchdB != m_settings.m_squelchdB) || force) {
543  reverseAPIKeys.append("squelchDB");
544  }
545  if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) {
546  reverseAPIKeys.append("squelchGate");
547  }
548  if ((settings.m_agc != m_settings.m_agc) || force) {
549  reverseAPIKeys.append("agc");
550  }
551  if ((settings.m_sampleFormat != m_settings.m_sampleFormat) || force) {
552  reverseAPIKeys.append("sampleFormat");
553  }
554  if ((settings.m_outputSampleRate != m_settings.m_outputSampleRate) || force) {
555  reverseAPIKeys.append("outputSampleRate");
556  }
557  if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
558  reverseAPIKeys.append("rfBandwidth");
559  }
560  if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) {
561  reverseAPIKeys.append("fmDeviation");
562  }
563  if ((settings.m_udpAddress != m_settings.m_udpAddress) || force) {
564  reverseAPIKeys.append("udpAddress");
565  }
566  if ((settings.m_udpPort != m_settings.m_udpPort) || force) {
567  reverseAPIKeys.append("udpPort");
568  }
569  if ((settings.m_audioPort != m_settings.m_audioPort) || force) {
570  reverseAPIKeys.append("audioPort");
571  }
572 
573  m_settingsMutex.lock();
574 
576  (settings.m_rfBandwidth != m_settings.m_rfBandwidth) ||
577  (settings.m_outputSampleRate != m_settings.m_outputSampleRate) || force)
578  {
581 
582  if ((settings.m_sampleFormat == UDPSinkSettings::FormatLSB) ||
586  {
587  m_squelchGate = settings.m_outputSampleRate * 0.05;
588  }
589  else
590  {
591  m_squelchGate = (settings.m_outputSampleRate * settings.m_squelchGate) / 100;
592  }
593 
594  m_squelchRelease = (settings.m_outputSampleRate * settings.m_squelchGate) / 100;
596  m_agc.resize(settings.m_outputSampleRate/5, settings.m_outputSampleRate/20, m_agcTarget); // Fixed 200 ms
597  int stepDownDelay = (settings.m_outputSampleRate * (settings.m_squelchGate == 0 ? 1 : settings.m_squelchGate))/100;
598  m_agc.setStepDownDelay(stepDownDelay);
599  m_agc.setGate(settings.m_outputSampleRate * 0.05);
600 
601  m_bandpass.create(301, settings.m_outputSampleRate, 300.0, settings.m_rfBandwidth / 2.0f);
602 
603  m_inMovingAverage.resize(settings.m_outputSampleRate * 0.01, 1e-10); // 10 ms
604  m_amMovingAverage.resize(settings.m_outputSampleRate * 0.005, 1e-10); // 5 ms
605  m_outMovingAverage.resize(settings.m_outputSampleRate * 0.01, 1e-10); // 10 ms
606  }
607 
608  if ((settings.m_audioActive != m_settings.m_audioActive) || force)
609  {
610  if (settings.m_audioActive)
611  {
612  m_audioBufferFill = 0;
614  }
615  else
616  {
618  }
619  }
620 
621  if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
622  {
623  if ((settings.m_sampleFormat == UDPSinkSettings::FormatLSB) ||
627  {
628  m_squelchGate = settings.m_outputSampleRate * 0.05;
629  }
630  else
631  {
632  m_squelchGate = (settings.m_outputSampleRate * settings.m_squelchGate)/100;
633  }
634 
635  m_squelchRelease = (settings.m_outputSampleRate * settings.m_squelchGate)/100;
637  int stepDownDelay = (settings.m_outputSampleRate * (settings.m_squelchGate == 0 ? 1 : settings.m_squelchGate))/100;
638  m_agc.setStepDownDelay(stepDownDelay); // same delay for up and down
639  }
640 
641  if ((settings.m_squelchdB != m_settings.m_squelchdB) || force)
642  {
644  m_agc.setThreshold(m_squelch*(1<<23));
645  }
646 
647  if ((settings.m_udpAddress != m_settings.m_udpAddress) || force)
648  {
649  m_udpBuffer16->setAddress(const_cast<QString&>(settings.m_udpAddress));
650  m_udpBufferMono16->setAddress(const_cast<QString&>(settings.m_udpAddress));
651  m_udpBuffer24->setAddress(const_cast<QString&>(settings.m_udpAddress));
652  }
653 
654  if ((settings.m_udpPort != m_settings.m_udpPort) || force)
655  {
656  m_udpBuffer16->setPort(settings.m_udpPort);
658  m_udpBuffer24->setPort(settings.m_udpPort);
659  }
660 
661  if ((settings.m_audioPort != m_settings.m_audioPort) || force)
662  {
663  disconnect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()));
664  delete m_audioSocket;
665  m_audioSocket = new QUdpSocket(this);
666 
667  if (m_audioSocket->bind(QHostAddress::LocalHost, settings.m_audioPort))
668  {
669  connect(m_audioSocket, SIGNAL(readyRead()), this, SLOT(audioReadyRead()), Qt::QueuedConnection);
670  qDebug("UDPSink::handleMessage: audio socket bound to port %d", settings.m_audioPort);
671  }
672  else
673  {
674  qWarning("UDPSink::handleMessage: cannot bind audio socket");
675  }
676  }
677 
678  if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
679  {
680  m_phaseDiscri.setFMScaling((float) settings.m_outputSampleRate / (2.0f * settings.m_fmDeviation));
681  }
682 
683  m_settingsMutex.unlock();
684 
685  if (settings.m_useReverseAPI)
686  {
687  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
692  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
693  }
694 
695  m_settings = settings;
696 }
697 
698 QByteArray UDPSink::serialize() const
699 {
700  return m_settings.serialize();
701 }
702 
703 bool UDPSink::deserialize(const QByteArray& data)
704 {
705  if (m_settings.deserialize(data))
706  {
709  return true;
710  }
711  else
712  {
716  return false;
717  }
718 }
719 
722  QString& errorMessage)
723 {
724  (void) errorMessage;
726  response.getUdpSinkSettings()->init();
728  return 200;
729 }
730 
732  bool force,
733  const QStringList& channelSettingsKeys,
735  QString& errorMessage)
736 {
737  (void) errorMessage;
738  UDPSinkSettings settings = m_settings;
739  bool frequencyOffsetChanged = false;
740 
741  if (channelSettingsKeys.contains("outputSampleRate")) {
743  }
744  if (channelSettingsKeys.contains("sampleFormat")) {
746  }
747  if (channelSettingsKeys.contains("inputFrequencyOffset"))
748  {
750  frequencyOffsetChanged = true;
751  }
752  if (channelSettingsKeys.contains("rfBandwidth")) {
753  settings.m_rfBandwidth = response.getUdpSinkSettings()->getRfBandwidth();
754  }
755  if (channelSettingsKeys.contains("fmDeviation")) {
756  settings.m_fmDeviation = response.getUdpSinkSettings()->getFmDeviation();
757  }
758  if (channelSettingsKeys.contains("channelMute")) {
759  settings.m_channelMute = response.getUdpSinkSettings()->getChannelMute() != 0;
760  }
761  if (channelSettingsKeys.contains("gain")) {
762  settings.m_gain = response.getUdpSinkSettings()->getGain();
763  }
764  if (channelSettingsKeys.contains("squelchDB")) {
765  settings.m_squelchdB = response.getUdpSinkSettings()->getSquelchDb();
766  }
767  if (channelSettingsKeys.contains("squelchGate")) {
768  settings.m_squelchGate = response.getUdpSinkSettings()->getSquelchGate();
769  }
770  if (channelSettingsKeys.contains("squelchEnabled")) {
771  settings.m_squelchEnabled = response.getUdpSinkSettings()->getSquelchEnabled() != 0;
772  }
773  if (channelSettingsKeys.contains("agc")) {
774  settings.m_agc = response.getUdpSinkSettings()->getAgc() != 0;
775  }
776  if (channelSettingsKeys.contains("audioActive")) {
777  settings.m_audioActive = response.getUdpSinkSettings()->getAudioActive() != 0;
778  }
779  if (channelSettingsKeys.contains("audioStereo")) {
780  settings.m_audioStereo = response.getUdpSinkSettings()->getAudioStereo() != 0;
781  }
782  if (channelSettingsKeys.contains("volume")) {
783  settings.m_volume = response.getUdpSinkSettings()->getVolume();
784  }
785  if (channelSettingsKeys.contains("udpAddress")) {
786  settings.m_udpAddress = *response.getUdpSinkSettings()->getUdpAddress();
787  }
788  if (channelSettingsKeys.contains("udpPort")) {
789  settings.m_udpPort = response.getUdpSinkSettings()->getUdpPort();
790  }
791  if (channelSettingsKeys.contains("audioPort")) {
792  settings.m_audioPort = response.getUdpSinkSettings()->getAudioPort();
793  }
794  if (channelSettingsKeys.contains("rgbColor")) {
795  settings.m_rgbColor = response.getUdpSinkSettings()->getRgbColor();
796  }
797  if (channelSettingsKeys.contains("title")) {
798  settings.m_title = *response.getUdpSinkSettings()->getTitle();
799  }
800  if (channelSettingsKeys.contains("useReverseAPI")) {
801  settings.m_useReverseAPI = response.getUdpSinkSettings()->getUseReverseApi() != 0;
802  }
803  if (channelSettingsKeys.contains("reverseAPIAddress")) {
805  }
806  if (channelSettingsKeys.contains("reverseAPIPort")) {
807  settings.m_reverseAPIPort = response.getUdpSinkSettings()->getReverseApiPort();
808  }
809  if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
811  }
812  if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
814  }
815 
816  if (frequencyOffsetChanged)
817  {
819  (int) settings.m_outputSampleRate,
820  (int) settings.m_inputFrequencyOffset);
821  m_inputMessageQueue.push(msgChan);
822  }
823 
826 
827  qDebug("getUdpSinkSettings::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
828  if (m_guiMessageQueue) // forward to GUI if any
829  {
830  MsgConfigureUDPSource *msgToGUI = MsgConfigureUDPSource::create(settings, force);
831  m_guiMessageQueue->push(msgToGUI);
832  }
833 
834  webapiFormatChannelSettings(response, settings);
835 
836  return 200;
837 }
838 
841  QString& errorMessage)
842 {
843  (void) errorMessage;
845  response.getUdpSinkReport()->init();
846  webapiFormatChannelReport(response);
847  return 200;
848 }
849 
851 {
853  response.getUdpSinkSettings()->setSampleFormat((int) settings.m_sampleFormat);
855  response.getUdpSinkSettings()->setRfBandwidth(settings.m_rfBandwidth);
856  response.getUdpSinkSettings()->setFmDeviation(settings.m_fmDeviation);
857  response.getUdpSinkSettings()->setChannelMute(settings.m_channelMute ? 1 : 0);
858  response.getUdpSinkSettings()->setGain(settings.m_gain);
859  response.getUdpSinkSettings()->setSquelchDb(settings.m_squelchdB);
860  response.getUdpSinkSettings()->setSquelchGate(settings.m_squelchGate);
861  response.getUdpSinkSettings()->setSquelchEnabled(settings.m_squelchEnabled ? 1 : 0);
862  response.getUdpSinkSettings()->setAgc(settings.m_agc ? 1 : 0);
863  response.getUdpSinkSettings()->setAudioActive(settings.m_audioActive ? 1 : 0);
864  response.getUdpSinkSettings()->setAudioStereo(settings.m_audioStereo ? 1 : 0);
865  response.getUdpSinkSettings()->setVolume(settings.m_volume);
866 
867  if (response.getUdpSinkSettings()->getUdpAddress()) {
868  *response.getUdpSinkSettings()->getUdpAddress() = settings.m_udpAddress;
869  } else {
870  response.getUdpSinkSettings()->setUdpAddress(new QString(settings.m_udpAddress));
871  }
872 
873  response.getUdpSinkSettings()->setUdpPort(settings.m_udpPort);
874  response.getUdpSinkSettings()->setAudioPort(settings.m_audioPort);
875  response.getUdpSinkSettings()->setRgbColor(settings.m_rgbColor);
876 
877  if (response.getUdpSinkSettings()->getTitle()) {
878  *response.getUdpSinkSettings()->getTitle() = settings.m_title;
879  } else {
880  response.getUdpSinkSettings()->setTitle(new QString(settings.m_title));
881  }
882 
883  response.getUdpSinkSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
884 
885  if (response.getUdpSinkSettings()->getReverseApiAddress()) {
887  } else {
888  response.getUdpSinkSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
889  }
890 
894 }
895 
897 {
900  response.getUdpSinkReport()->setSquelch(m_squelchOpen ? 1 : 0);
902 }
903 
904 void UDPSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSinkSettings& settings, bool force)
905 {
907  swgChannelSettings->setDirection(0); // single sink (Rx)
908  swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
909  swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
910  swgChannelSettings->setChannelType(new QString("UDPSink"));
911  swgChannelSettings->setUdpSinkSettings(new SWGSDRangel::SWGUDPSinkSettings());
912  SWGSDRangel::SWGUDPSinkSettings *swgUDPSinkSettings = swgChannelSettings->getUdpSinkSettings();
913 
914  // transfer data that has been modified. When force is on transfer all data except reverse API data
915 
916  if (channelSettingsKeys.contains("outputSampleRate") || force) {
917  swgUDPSinkSettings->setOutputSampleRate(settings.m_outputSampleRate);
918  }
919  if (channelSettingsKeys.contains("sampleFormat") || force) {
920  swgUDPSinkSettings->setSampleFormat((int) settings.m_sampleFormat);
921  }
922  if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
923  swgUDPSinkSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
924  }
925  if (channelSettingsKeys.contains("rfBandwidth") || force) {
926  swgUDPSinkSettings->setRfBandwidth(settings.m_rfBandwidth);
927  }
928  if (channelSettingsKeys.contains("fmDeviation") || force) {
929  swgUDPSinkSettings->setFmDeviation(settings.m_fmDeviation);
930  }
931  if (channelSettingsKeys.contains("channelMute") || force) {
932  swgUDPSinkSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
933  }
934  if (channelSettingsKeys.contains("gain") || force) {
935  swgUDPSinkSettings->setGain(settings.m_gain);
936  }
937  if (channelSettingsKeys.contains("squelchDB") || force) {
938  swgUDPSinkSettings->setSquelchDb(settings.m_squelchdB);
939  }
940  if (channelSettingsKeys.contains("squelchGate") || force) {
941  swgUDPSinkSettings->setSquelchGate(settings.m_squelchGate);
942  }
943  if (channelSettingsKeys.contains("squelchEnabled") || force) {
944  swgUDPSinkSettings->setSquelchEnabled(settings.m_squelchEnabled ? 1 : 0);
945  }
946  if (channelSettingsKeys.contains("agc") || force) {
947  swgUDPSinkSettings->setAgc(settings.m_agc ? 1 : 0);
948  }
949  if (channelSettingsKeys.contains("audioActive") || force) {
950  swgUDPSinkSettings->setAudioActive(settings.m_audioActive ? 1 : 0);
951  }
952  if (channelSettingsKeys.contains("audioStereo") || force) {
953  swgUDPSinkSettings->setAudioStereo(settings.m_audioStereo ? 1 : 0);
954  }
955  if (channelSettingsKeys.contains("volume") || force) {
956  swgUDPSinkSettings->setVolume(settings.m_volume);
957  }
958  if (channelSettingsKeys.contains("udpAddress") || force) {
959  swgUDPSinkSettings->setUdpAddress(new QString(settings.m_udpAddress));
960  }
961  if (channelSettingsKeys.contains("udpPort") || force) {
962  swgUDPSinkSettings->setUdpPort(settings.m_udpPort);
963  }
964  if (channelSettingsKeys.contains("audioPort") || force) {
965  swgUDPSinkSettings->setAudioPort(settings.m_audioPort);
966  }
967  if (channelSettingsKeys.contains("rgbColor") || force) {
968  swgUDPSinkSettings->setRgbColor(settings.m_rgbColor);
969  }
970  if (channelSettingsKeys.contains("title") || force) {
971  swgUDPSinkSettings->setTitle(new QString(settings.m_title));
972  }
973 
974  QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
975  .arg(settings.m_reverseAPIAddress)
976  .arg(settings.m_reverseAPIPort)
977  .arg(settings.m_reverseAPIDeviceIndex)
978  .arg(settings.m_reverseAPIChannelIndex);
979  m_networkRequest.setUrl(QUrl(channelSettingsURL));
980  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
981 
982  QBuffer *buffer=new QBuffer();
983  buffer->open((QBuffer::ReadWrite));
984  buffer->write(swgChannelSettings->asJson().toUtf8());
985  buffer->seek(0);
986 
987  // Always use PATCH to avoid passing reverse API settings
988  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
989 
990  delete swgChannelSettings;
991 }
992 
993 void UDPSink::networkManagerFinished(QNetworkReply *reply)
994 {
995  QNetworkReply::NetworkError replyError = reply->error();
996 
997  if (replyError)
998  {
999  qWarning() << "UDPSink::networkManagerFinished:"
1000  << " error(" << (int) replyError
1001  << "): " << replyError
1002  << ": " << reply->errorString();
1003  return;
1004  }
1005 
1006  QString answer = reply->readAll();
1007  answer.chop(1); // remove last \n
1008  qDebug("UDPSink::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
1009 }
static MsgConfigureChannelizer * create(int sampleRate, int centerFrequency)
Definition: udpsink.h:83
uint m_audioBufferFill
Definition: udpsink.h:222
void setSquelchGate(qint32 squelch_gate)
void setOriginatorChannelIndex(qint32 originator_channel_index)
void addAudioSink(AudioFifo *audioFifo, MessageQueue *sampleSinkMessageQueue, int outputDeviceIndex=-1)
Add the audio sink.
int m_squelchdB
power dB
static const QString m_channelId
Definition: udpsink.h:146
const UDPSinkSettings & getSettings() const
Definition: udpsink.h:56
Complex nextIQ()
Return next complex sample.
Definition: nco.cpp:61
bool decimate(Real *distance, const Complex &next, Complex *result)
Definition: interpolator.h:38
void configure(MessageQueue *messageQueue, int sampleRate, int centerFrequency)
void setSampleFormat(qint32 sample_format)
bool deserialize(const QByteArray &data)
void push(Message *message, bool emitSignal=true)
Push message onto queue.
DownChannelizer * m_channelizer
Definition: udpsink.h:194
void feed(Type value)
Definition: movingaverage.h:24
void removeChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:163
void create(int nTaps, double sampleRate, double lowCutoff, double highCutoff)
Definition: bandpass.h:15
static double dbPower(double magsq, double floor=1e-12)
Definition: db.cpp:22
void addChannelSinkAPI(ChannelAPI *channelAPI, int streamIndex=0)
Definition: deviceapi.cpp:156
void setPort(unsigned int port)
Definition: udpsinkutil.h:81
void setChannelMute(qint32 channel_mute)
void create(int phaseSteps, double sampleRate, double cutoff, double nbTapsPerPhase=4.5)
MessageQueue * getInputMessageQueue()
Get the queue for asynchronous inbound communication.
void setFMScaling(Real fmScaling)
Definition: phasediscri.h:42
Complex m_last
Definition: udpsink.h:209
void setFmDeviation(qint32 fm_deviation)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
int getDeviceSetIndex() const
Definition: channelapi.h:89
virtual bool deserialize(const QByteArray &data)
Definition: udpsink.cpp:703
double m_inMagsq
Definition: udpsink.h:203
void setReverseApiPort(qint32 reverse_api_port)
void udpWriteNorm(Real real, Real imag)
Definition: udpsink.h:353
Real m_scale
Definition: udpsink.h:208
virtual int webapiSettingsPutPatch(bool force, const QStringList &channelSettingsKeys, SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: udpsink.cpp:731
void setAddress(QString &address)
Definition: udpsinkutil.h:80
void removeAudioSink(AudioFifo *audioFifo)
Remove the audio sink.
void udpWrite(FixReal real, FixReal imag)
Definition: udpsink.h:317
void setSquelchDb(qint32 squelch_db)
Type filter(Type sample)
Definition: bandpass.h:77
virtual bool handleMessage(const Message &cmd)
Processing of a message. Returns true if message has actually been processed.
Definition: udpsink.cpp:342
uint16_t m_reverseAPIPort
quint32 m_nextSSBId
Definition: udpsink.h:228
bool m_spectrumEnabled
Definition: udpsink.h:226
void calculateSquelch(double value)
Definition: udpsink.h:259
UDPSinkSettings m_settings
Definition: udpsink.h:198
Type average() const
Definition: movingaverage.h:43
void setChannelType(QString *channel_type)
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)=0
MovingAverage< double > m_amMovingAverage
Definition: udpsink.h:206
void setOriginatorDeviceSetIndex(qint32 originator_device_set_index)
void setRfBandwidth(float rf_bandwidth)
SampleVector m_sampleBuffer
Definition: udpsink.h:216
void setSpectrum(BasebandSampleSink *spectrum)
Definition: udpsink.h:102
double getInMagSq() const
Definition: udpsink.h:106
MessageQueue m_inputMessageQueue
Queue for asynchronous inbound communication.
double feedAndGetValue(const Complex &ci)
Definition: agc.cpp:108
bool getEnabled() const
Definition: udpsink.h:160
std::complex< float > cmplx
Definition: fftfilt.h:21
static const int m_udpAudioPayloadSize
UDP audio samples buffer. No UDP block on Earth is larger than this.
Definition: udpsink.h:232
int m_squelchGate
100ths seconds
void setUdpSinkReport(SWGUDPSinkReport *udp_sink_report)
MagAGC m_agc
Definition: udpsink.h:244
static const Real m_agcTarget
Definition: udpsink.h:233
AudioVector m_audioBuffer
Definition: udpsink.h:221
#define SDR_RX_SCALEF
Definition: dsptypes.h:33
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force=true)
Definition: udpsink.cpp:472
double m_magsq
Definition: udpsink.h:202
void setInputFrequencyOffset(qint64 input_frequency_offset)
QByteArray serialize() const
void setReverseApiChannelIndex(qint32 reverse_api_channel_index)
BasebandSampleSink * m_spectrum
Definition: udpsink.h:225
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
virtual int webapiReportGet(SWGSDRangel::SWGChannelReport &response, QString &errorMessage)
Definition: udpsink.cpp:839
virtual bool handleMessage(const Message &cmd)=0
Processing of a message. Returns true if message has actually been processed.
void resize(int historySize, int stepLength, Real R)
Definition: agc.cpp:65
MovingAverage< double > m_outMovingAverage
Definition: udpsink.h:204
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings &response, const UDPSinkSettings &settings)
Definition: udpsink.cpp:850
void networkManagerFinished(QNetworkReply *reply)
Definition: udpsink.cpp:993
void setUdpAddress(QString *udp_address)
double getMagSq() const
Definition: udpsink.h:105
AudioFifo m_audioFifo
Definition: udpsink.h:223
void udpWriteMono(FixReal sample)
Definition: udpsink.h:341
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
virtual QByteArray serialize() const
Definition: udpsink.cpp:698
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport &response)
Definition: udpsink.cpp:896
uint16_t m_reverseAPIDeviceIndex
QNetworkAccessManager * m_networkManager
Definition: udpsink.h:247
NCO m_nco
Definition: udpsink.h:211
static DSPEngine * instance()
Definition: dspengine.cpp:51
UDPSinkUtil< int16_t > * m_udpBufferMono16
Definition: udpsink.h:218
ThreadedBasebandSampleSink * m_threadedChannelizer
Definition: udpsink.h:193
Bandpass< double > m_bandpass
Definition: udpsink.h:245
QUdpSocket * m_audioSocket
Definition: udpsink.h:200
void setInputSampleRate(qint32 input_sample_rate)
void setAudioPort(qint32 audio_port)
void setClampMax(double clampMax)
Definition: agc.h:52
int32_t i
Definition: decimators.h:244
virtual void stop()
Definition: udpsink.cpp:338
virtual void feed(const SampleVector::const_iterator &begin, const SampleVector::const_iterator &end, bool positiveOnly)
Definition: udpsink.cpp:145
void setUdpSinkSettings(SWGUDPSinkSettings *udp_sink_settings)
void setAudioStereo(qint32 audio_stereo)
Real phaseDiscriminator(const Complex &sample)
Definition: phasediscri.h:51
static bool match(const Message *message)
Definition: message.cpp:45
void setFreq(Real freq, Real sampleRate)
Definition: nco.cpp:49
int m_inputFrequencyOffset
Definition: udpsink.h:197
Interpolator m_interpolator
Definition: udpsink.h:212
int m_squelchGate
number of samples computed from given gate
Definition: udpsink.h:241
void setSquelchEnabled(qint32 squelch_enabled)
void udpWriteNormMono(Real sample)
Definition: udpsink.h:358
void removeChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Remove a channel sink (Rx)
Definition: deviceapi.cpp:127
void setOutputPowerDb(float output_power_db)
int m_squelchRelease
Definition: udpsink.h:242
Fixed< IntType, IntBits > sqrt(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2283
SWGUDPSinkReport * getUdpSinkReport()
virtual QString asJson() override
void setChannelPowerDb(float channel_power_db)
virtual int webapiSettingsGet(SWGSDRangel::SWGChannelSettings &response, QString &errorMessage)
Definition: udpsink.cpp:720
fftfilt * UDPFilter
Definition: udpsink.h:214
static const int udpBlockSize
Definition: udpsink.h:147
UDPSinkUtil< Sample16 > * m_udpBuffer16
Definition: udpsink.h:217
uint16_t m_reverseAPIChannelIndex
SampleFormat m_sampleFormat
QMutex m_settingsMutex
Definition: udpsink.h:250
void setAudioActive(qint32 audio_active)
AudioDeviceManager * getAudioDeviceManager()
Definition: dspengine.h:55
UDPSink(DeviceAPI *deviceAPI)
Definition: udpsink.cpp:48
void webapiReverseSendSettings(QList< QString > &channelSettingsKeys, const UDPSinkSettings &settings, bool force)
Definition: udpsink.cpp:904
void addChannelSink(ThreadedBasebandSampleSink *sink, int streamIndex=0)
Add a channel sink (Rx)
Definition: deviceapi.cpp:118
virtual ~UDPSink()
Definition: udpsink.cpp:122
QNetworkRequest m_networkRequest
Definition: udpsink.h:248
Real m_sampleDistanceRemain
Definition: udpsink.h:213
void setUseReverseApi(qint32 use_reverse_api)
int runSSB(const cmplx &in, cmplx **out, bool usb, bool getDC=true)
Definition: fftfilt.cpp:284
UDPSinkUtil< Sample24 > * m_udpBuffer24
Definition: udpsink.h:219
PhaseDiscriminators m_phaseDiscri
Definition: udpsink.h:235
char * m_udpAudioBuf
Definition: udpsink.h:231
void applySettings(const UDPSinkSettings &settings, bool force=false)
Definition: udpsink.cpp:496
double getMagSq() const
Definition: agc.h:46
void setClamping(bool clamping)
Definition: agc.h:51
virtual void start()
Definition: udpsink.cpp:332
void setThreshold(double threshold)
Definition: agc.h:47
uint16_t m_audioPort
void setStepDownDelay(int stepDownDelay)
Definition: agc.h:50
int64_t m_inputFrequencyOffset
void setGate(int gate)
Definition: agc.h:49
MovingAverage< double > m_inMovingAverage
Definition: udpsink.h:205
void setOutputSampleRate(float output_sample_rate)
void setReverseApiAddress(QString *reverse_api_address)
SWGUDPSinkSettings * getUdpSinkSettings()
static MsgUDPSinkSpectrum * create(bool enabled)
Definition: udpsink.h:162
int m_inputSampleRate
Definition: udpsink.h:196
int getIndexInDeviceSet() const
Definition: channelapi.h:87
static const QString m_channelIdURI
Definition: udpsink.h:145
std::complex< Real > Complex
Definition: dsptypes.h:43
quint32 m_nextS16leId
Definition: udpsink.h:229
static MsgConfigureUDPSource * create(const UDPSinkSettings &settings, bool force)
Definition: udpsink.h:59
bool m_squelchOpen
Definition: udpsink.h:238
#define SDR_RX_SCALED
Definition: dsptypes.h:34
float Real
Definition: dsptypes.h:42
void audioReadyRead()
Definition: udpsink.cpp:404
void resize(int historySize, Type initial)
Definition: movingaverage.h:16
static double powerFromdB(double powerdB)
Definition: db.cpp:36
qint16 FixReal
Definition: dsptypes.h:35
QString m_reverseAPIAddress
uint32_t write(const quint8 *data, uint32_t numSamples)
Definition: audiofifo.cpp:66
void initSquelch(bool open)
Definition: udpsink.h:301
Complex m_this
Definition: udpsink.h:209
double m_squelch
Definition: udpsink.h:237
DeviceAPI * m_deviceAPI
Definition: udpsink.h:192