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.
remoteoutput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2017 Edouard Griffiths, F4EXB //
3 // //
4 // This program is free software; you can redistribute it and/or modify //
5 // it under the terms of the GNU General Public License as published by //
6 // the Free Software Foundation as version 3 of the License, or //
7 // (at your option) any later version. //
8 // //
9 // This program is distributed in the hope that it will be useful, //
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
12 // GNU General Public License V3 for more details. //
13 // //
14 // You should have received a copy of the GNU General Public License //
15 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
17 
18 #include <string.h>
19 #include <errno.h>
20 #include <QDebug>
21 #include <QNetworkAccessManager>
22 #include <QNetworkReply>
23 #include <QJsonParseError>
24 #include <QBuffer>
25 
26 #include "SWGDeviceSettings.h"
27 #include "SWGDeviceState.h"
28 #include "SWGDeviceReport.h"
29 #include "SWGRemoteOutputReport.h"
30 
31 #include "util/simpleserializer.h"
32 #include "dsp/dspcommands.h"
33 #include "dsp/dspengine.h"
34 #include "dsp/filerecord.h"
35 
36 #include "device/deviceapi.h"
37 
38 #include "remoteoutput.h"
39 #include "remoteoutputthread.h"
40 
45 
47 
49  m_deviceAPI(deviceAPI),
50  m_settings(),
51  m_centerFrequency(0),
52  m_remoteOutputThread(0),
53  m_deviceDescription("RemoteOutput"),
54  m_startingTimeStamp(0),
55  m_masterTimer(deviceAPI->getMasterTimer()),
56  m_tickCount(0),
57  m_tickMultiplier(20),
58  m_lastRemoteSampleCount(0),
59  m_lastSampleCount(0),
60  m_lastRemoteTimestampRateCorrection(0),
61  m_lastTimestampRateCorrection(0),
62  m_lastQueueLength(-2),
63  m_nbRemoteSamplesSinceRateCorrection(0),
64  m_nbSamplesSinceRateCorrection(0),
65  m_chunkSizeCorrection(0)
66 {
68  m_networkManager = new QNetworkAccessManager();
69  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
70  connect(&m_masterTimer, SIGNAL(timeout()), this, SLOT(tick()));
71 }
72 
74 {
75  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
76  stop();
77  delete m_networkManager;
78 }
79 
81 {
82  delete this;
83 }
84 
86 {
87  QMutexLocker mutexLocker(&m_mutex);
88  qDebug() << "RemoteOutput::start";
89 
96 
97  // restart auto rate correction
100  m_lastQueueLength = -2; // set first value out of bounds
102 
104 
105  mutexLocker.unlock();
106  //applySettings(m_generalSettings, m_settings, true);
107  qDebug("RemoteOutput::start: started");
108 
109  return true;
110 }
111 
113 {
114  applySettings(m_settings, true);
115 }
116 
118 {
119  qDebug() << "RemoteOutput::stop";
120  QMutexLocker mutexLocker(&m_mutex);
121 
122  if(m_remoteOutputThread != 0)
123  {
125  delete m_remoteOutputThread;
127  }
128 }
129 
130 QByteArray RemoteOutput::serialize() const
131 {
132  return m_settings.serialize();
133 }
134 
135 bool RemoteOutput::deserialize(const QByteArray& data)
136 {
137  bool success = true;
138 
139  if (!m_settings.deserialize(data))
140  {
142  success = false;
143  }
144 
146  m_inputMessageQueue.push(message);
147 
148  if (m_guiMessageQueue)
149  {
151  m_guiMessageQueue->push(messageToGUI);
152  }
153 
154  return success;
155 }
156 
158 {
159  return m_deviceDescription;
160 }
161 
163 {
164  return m_settings.m_sampleRate;
165 }
166 
168 {
169  return m_centerFrequency;
170 }
171 
173 {
174  return m_startingTimeStamp;
175 }
176 
178 {
179 
180  if (MsgConfigureRemoteOutput::match(message))
181  {
182  qDebug() << "RemoteOutput::handleMessage:" << message.getIdentifier();
184  applySettings(conf.getSettings(), conf.getForce());
185  return true;
186  }
187  else if (MsgConfigureRemoteOutputWork::match(message))
188  {
190  bool working = conf.isWorking();
191 
192  if (m_remoteOutputThread != 0)
193  {
194  if (working)
195  {
197  }
198  else
199  {
201  }
202  }
203 
204  return true;
205  }
206  else if (MsgStartStop::match(message))
207  {
208  MsgStartStop& cmd = (MsgStartStop&) message;
209  qDebug() << "RemoteOutput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
210 
211  if (cmd.getStartStop())
212  {
214  {
216  }
217  }
218  else
219  {
221  }
222 
225  }
226 
227  return true;
228  }
230  {
232 
233  if (m_remoteOutputThread != 0)
234  {
236  }
237 
238  return true;
239  }
240  else
241  {
242  return false;
243  }
244 }
245 
246 void RemoteOutput::applySettings(const RemoteOutputSettings& settings, bool force)
247 {
248  QMutexLocker mutexLocker(&m_mutex);
249  bool forwardChange = false;
250  bool changeTxDelay = false;
251  QList<QString> reverseAPIKeys;
252 
253  if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) {
254  reverseAPIKeys.append("dataAddress");
255  }
256  if ((m_settings.m_dataPort != settings.m_dataPort) || force) {
257  reverseAPIKeys.append("dataPort");
258  }
259  if ((m_settings.m_apiAddress != settings.m_apiAddress) || force) {
260  reverseAPIKeys.append("apiAddress");
261  }
262  if ((m_settings.m_apiPort != settings.m_apiPort) || force) {
263  reverseAPIKeys.append("apiPort");
264  }
265 
266  if (force || (m_settings.m_dataAddress != settings.m_dataAddress) || (m_settings.m_dataPort != settings.m_dataPort))
267  {
268  if (m_remoteOutputThread != 0) {
270  }
271  }
272 
273  if (force || (m_settings.m_sampleRate != settings.m_sampleRate))
274  {
275  reverseAPIKeys.append("sampleRate");
276 
277  if (m_remoteOutputThread != 0) {
279  }
280 
281  m_tickMultiplier = (21*NbSamplesForRateCorrection) / (2*settings.m_sampleRate); // two times per sample filling period plus small extension
282  m_tickMultiplier = m_tickMultiplier < 20 ? 20 : m_tickMultiplier; // not below half a second
283 
284  forwardChange = true;
285  changeTxDelay = true;
286  }
287 
288  if (force || (m_settings.m_nbFECBlocks != settings.m_nbFECBlocks))
289  {
290  reverseAPIKeys.append("nbFECBlocks");
291 
292  if (m_remoteOutputThread != 0) {
294  }
295 
296  changeTxDelay = true;
297  }
298 
299  if (force || (m_settings.m_txDelay != settings.m_txDelay))
300  {
301  reverseAPIKeys.append("txDelay");
302  changeTxDelay = true;
303  }
304 
305  if (changeTxDelay)
306  {
307  if (m_remoteOutputThread != 0) {
309  }
310  }
311 
312  mutexLocker.unlock();
313 
314  qDebug() << "RemoteOutput::applySettings:"
315  << " m_sampleRate: " << settings.m_sampleRate
316  << " m_txDelay: " << settings.m_txDelay
317  << " m_nbFECBlocks: " << settings.m_nbFECBlocks
318  << " m_apiAddress: " << settings.m_apiAddress
319  << " m_apiPort: " << settings.m_apiPort
320  << " m_dataAddress: " << settings.m_dataAddress
321  << " m_dataPort: " << settings.m_dataPort;
322 
323  if (forwardChange)
324  {
327  }
328 
329  if (settings.m_useReverseAPI)
330  {
331  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
335  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
336  }
337 
338  m_settings = settings;
339 }
340 
342  SWGSDRangel::SWGDeviceState& response,
343  QString& errorMessage)
344 {
345  (void) errorMessage;
347  return 200;
348 }
349 
351  bool run,
352  SWGSDRangel::SWGDeviceState& response,
353  QString& errorMessage)
354 {
355  (void) errorMessage;
357  MsgStartStop *message = MsgStartStop::create(run);
358  m_inputMessageQueue.push(message);
359 
360  if (m_guiMessageQueue)
361  {
362  MsgStartStop *messagetoGui = MsgStartStop::create(run);
363  m_guiMessageQueue->push(messagetoGui);
364  }
365 
366  return 200;
367 }
368 
371  QString& errorMessage)
372 {
373  (void) errorMessage;
375  response.getRemoteOutputSettings()->init();
377  return 200;
378 }
379 
381  bool force,
382  const QStringList& deviceSettingsKeys,
383  SWGSDRangel::SWGDeviceSettings& response, // query + response
384  QString& errorMessage)
385 {
386  (void) errorMessage;
387  RemoteOutputSettings settings = m_settings;
388 
389  if (deviceSettingsKeys.contains("sampleRate")) {
390  settings.m_sampleRate = response.getRemoteOutputSettings()->getSampleRate();
391  }
392  if (deviceSettingsKeys.contains("txDelay")) {
393  settings.m_txDelay = response.getRemoteOutputSettings()->getTxDelay();
394  }
395  if (deviceSettingsKeys.contains("nbFECBlocks")) {
396  settings.m_nbFECBlocks = response.getRemoteOutputSettings()->getNbFecBlocks();
397  }
398  if (deviceSettingsKeys.contains("apiAddress")) {
399  settings.m_apiAddress = *response.getRemoteOutputSettings()->getApiAddress();
400  }
401  if (deviceSettingsKeys.contains("apiPort")) {
402  settings.m_apiPort = response.getRemoteOutputSettings()->getApiPort();
403  }
404  if (deviceSettingsKeys.contains("dataAddress")) {
405  settings.m_dataAddress = *response.getRemoteOutputSettings()->getDataAddress();
406  }
407  if (deviceSettingsKeys.contains("dataPort")) {
408  settings.m_dataPort = response.getRemoteOutputSettings()->getDataPort();
409  }
410  if (deviceSettingsKeys.contains("deviceIndex")) {
411  settings.m_deviceIndex = response.getRemoteOutputSettings()->getDeviceIndex();
412  }
413  if (deviceSettingsKeys.contains("channelIndex")) {
414  settings.m_channelIndex = response.getRemoteOutputSettings()->getChannelIndex();
415  }
416  if (deviceSettingsKeys.contains("useReverseAPI")) {
417  settings.m_useReverseAPI = response.getRemoteOutputSettings()->getUseReverseApi() != 0;
418  }
419  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
421  }
422  if (deviceSettingsKeys.contains("reverseAPIPort")) {
424  }
425  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
427  }
428 
431 
432  if (m_guiMessageQueue) // forward to GUI if any
433  {
434  MsgConfigureRemoteOutput *msgToGUI = MsgConfigureRemoteOutput::create(settings, force);
435  m_guiMessageQueue->push(msgToGUI);
436  }
437 
438  webapiFormatDeviceSettings(response, settings);
439  return 200;
440 }
441 
444  QString& errorMessage)
445 {
446  (void) errorMessage;
448  response.getRemoteOutputReport()->init();
449  webapiFormatDeviceReport(response);
450  return 200;
451 }
452 
454 {
456  response.getRemoteOutputSettings()->setSampleRate(settings.m_sampleRate);
457  response.getRemoteOutputSettings()->setTxDelay(settings.m_txDelay);
459  response.getRemoteOutputSettings()->setApiAddress(new QString(settings.m_apiAddress));
460  response.getRemoteOutputSettings()->setApiPort(settings.m_apiPort);
461  response.getRemoteOutputSettings()->setDataAddress(new QString(settings.m_dataAddress));
462  response.getRemoteOutputSettings()->setDataPort(settings.m_dataPort);
465  response.getRemoteOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
466 
467  if (response.getRemoteOutputSettings()->getReverseApiAddress()) {
469  } else {
470  response.getRemoteOutputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
471  }
472 
475 }
476 
478 {
479  uint64_t ts_usecs;
482 }
483 
485 {
486  if (++m_tickCount == m_tickMultiplier)
487  {
488  QString reportURL;
489 
490  reportURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/report")
492  .arg(m_settings.m_apiPort)
495 
496  m_networkRequest.setUrl(QUrl(reportURL));
498 
499  m_tickCount = 0;
500  }
501 }
502 
503 void RemoteOutput::networkManagerFinished(QNetworkReply *reply)
504 {
505  if (reply->error())
506  {
507  qInfo("RemoteOutput::networkManagerFinished: error: %s", qPrintable(reply->errorString()));
508  return;
509  }
510 
511  QString answer = reply->readAll();
512 
513  try
514  {
515  QByteArray jsonBytes(answer.toStdString().c_str());
516  QJsonParseError error;
517  QJsonDocument doc = QJsonDocument::fromJson(jsonBytes, &error);
518 
519  if (error.error == QJsonParseError::NoError)
520  {
521  analyzeApiReply(doc.object(), answer);
522  }
523  else
524  {
525  QString errorMsg = QString("Reply JSON error: ") + error.errorString() + QString(" at offset ") + QString::number(error.offset);
526  qInfo().noquote() << "RemoteOutput::networkManagerFinished" << errorMsg;
527  }
528  }
529  catch (const std::exception& ex)
530  {
531  QString errorMsg = QString("Error parsing request: ") + ex.what();
532  qInfo().noquote() << "RemoteOutput::networkManagerFinished" << errorMsg;
533  }
534 }
535 
536 void RemoteOutput::analyzeApiReply(const QJsonObject& jsonObject, const QString& answer)
537 {
538  if (jsonObject.contains("RemoteSourceReport"))
539  {
540  QJsonObject report = jsonObject["RemoteSourceReport"].toObject();
541  m_centerFrequency = report["deviceCenterFreq"].toInt() * 1000;
542 
543  if (!m_remoteOutputThread) {
544  return;
545  }
546 
547  int queueSize = report["queueSize"].toInt();
548  queueSize = queueSize == 0 ? 10 : queueSize;
549  int queueLength = report["queueLength"].toInt();
550  int queueLengthPercent = (queueLength*100)/queueSize;
551  uint64_t remoteTimestampUs = report["tvSec"].toInt()*1000000ULL + report["tvUSec"].toInt();
552 
553  uint32_t remoteSampleCountDelta, remoteSampleCount;
554  remoteSampleCount = report["samplesCount"].toInt();
555 
556  if (remoteSampleCount < m_lastRemoteSampleCount) {
557  remoteSampleCountDelta = (0xFFFFFFFFU - m_lastRemoteSampleCount) + remoteSampleCount + 1;
558  } else {
559  remoteSampleCountDelta = remoteSampleCount - m_lastRemoteSampleCount;
560  }
561 
562  uint32_t sampleCountDelta, sampleCount;
563  uint64_t timestampUs;
564  sampleCount = m_remoteOutputThread->getSamplesCount(timestampUs);
565 
566  if (sampleCount < m_lastSampleCount) {
567  sampleCountDelta = (0xFFFFFFFFU - m_lastSampleCount) + sampleCount + 1;
568  } else {
569  sampleCountDelta = sampleCount - m_lastSampleCount;
570  }
571 
572  // on initial state wait for queue stabilization
573  if ((m_lastRemoteTimestampRateCorrection == 0) && (queueLength >= m_lastQueueLength-1) && (queueLength <= m_lastQueueLength+1))
574  {
575  m_lastRemoteTimestampRateCorrection = remoteTimestampUs;
576  m_lastTimestampRateCorrection = timestampUs;
579  }
580  else
581  {
582  m_nbRemoteSamplesSinceRateCorrection += remoteSampleCountDelta;
583  m_nbSamplesSinceRateCorrection += sampleCountDelta;
584 
585  qDebug("RemoteOutput::analyzeApiReply: queueLengthPercent: %d m_nbSamplesSinceRateCorrection: %u",
586  queueLengthPercent,
588 
590  {
592  timestampUs - m_lastTimestampRateCorrection,
595  m_lastRemoteTimestampRateCorrection = remoteTimestampUs;
596  m_lastTimestampRateCorrection = timestampUs;
599  }
600  }
601 
602  m_lastRemoteSampleCount = remoteSampleCount;
603  m_lastSampleCount = sampleCount;
604  m_lastQueueLength = queueLength;
605  }
606  else if (jsonObject.contains("remoteOutputSettings"))
607  {
608  qDebug("RemoteOutput::analyzeApiReply: reply:\n%s", answer.toStdString().c_str());
609  }
610 }
611 
612 void RemoteOutput::sampleRateCorrection(double remoteTimeDeltaUs, double timeDeltaUs, uint32_t remoteSampleCount, uint32_t sampleCount)
613 {
614  double deltaSR = (remoteSampleCount/remoteTimeDeltaUs) - (sampleCount/timeDeltaUs);
615  double chunkCorr = 50000 * deltaSR; // for 50ms chunk intervals (50000us)
616  m_chunkSizeCorrection += roundf(chunkCorr);
617 
618  qDebug("RemoteOutput::sampleRateCorrection: %d (%f) samples", m_chunkSizeCorrection, chunkCorr);
619 
621  getInputMessageQueue()->push(message);
622 }
623 
624 void RemoteOutput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const RemoteOutputSettings& settings, bool force)
625 {
627  swgDeviceSettings->setDirection(1); // single Tx
628  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
629  swgDeviceSettings->setDeviceHwType(new QString("RemoteOutput"));
631  SWGSDRangel::SWGRemoteOutputSettings *swgRemoteOutputSettings = swgDeviceSettings->getRemoteOutputSettings();
632 
633  // transfer data that has been modified. When force is on transfer all data except reverse API data
634 
635  if (deviceSettingsKeys.contains("sampleRate") || force) {
636  swgRemoteOutputSettings->setSampleRate(settings.m_sampleRate);
637  }
638  if (deviceSettingsKeys.contains("txDelay") || force) {
639  swgRemoteOutputSettings->setTxDelay(settings.m_txDelay);
640  }
641  if (deviceSettingsKeys.contains("nbFECBlocks") || force) {
642  swgRemoteOutputSettings->setNbFecBlocks(settings.m_nbFECBlocks);
643  }
644  if (deviceSettingsKeys.contains("apiAddress") || force) {
645  swgRemoteOutputSettings->setApiAddress(new QString(settings.m_apiAddress));
646  }
647  if (deviceSettingsKeys.contains("apiPort") || force) {
648  swgRemoteOutputSettings->setApiPort(settings.m_apiPort);
649  }
650  if (deviceSettingsKeys.contains("dataAddress") || force) {
651  swgRemoteOutputSettings->setDataAddress(new QString(settings.m_dataAddress));
652  }
653  if (deviceSettingsKeys.contains("dataPort") || force) {
654  swgRemoteOutputSettings->setDataPort(settings.m_dataPort);
655  }
656  if (deviceSettingsKeys.contains("deviceIndex") || force) {
657  swgRemoteOutputSettings->setDeviceIndex(settings.m_deviceIndex);
658  }
659  if (deviceSettingsKeys.contains("channelIndex") || force) {
660  swgRemoteOutputSettings->setChannelIndex(settings.m_channelIndex);
661  }
662 
663  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
664  .arg(settings.m_reverseAPIAddress)
665  .arg(settings.m_reverseAPIPort)
666  .arg(settings.m_reverseAPIDeviceIndex);
667  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
668  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
669 
670  QBuffer *buffer=new QBuffer();
671  buffer->open((QBuffer::ReadWrite));
672  buffer->write(swgDeviceSettings->asJson().toUtf8());
673  buffer->seek(0);
674 
675  // Always use PATCH to avoid passing reverse API settings
676  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
677 
678  delete swgDeviceSettings;
679 }
680 
682 {
684  swgDeviceSettings->setDirection(1); // single Tx
685  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
686  swgDeviceSettings->setDeviceHwType(new QString("RemoteOutput"));
687 
688  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
692  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
693  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
694 
695  QBuffer *buffer=new QBuffer();
696  buffer->open((QBuffer::ReadWrite));
697  buffer->write(swgDeviceSettings->asJson().toUtf8());
698  buffer->seek(0);
699 
700  if (start) {
701  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
702  } else {
703  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
704  }
705 
706  delete swgDeviceSettings;
707 }
QMutex m_mutex
Definition: remoteoutput.h:171
virtual QByteArray serialize() const
RemoteOutputThread * m_remoteOutputThread
Definition: remoteoutput.h:174
void setReverseApiPort(qint32 reverse_api_port)
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
QNetworkRequest m_networkRequest
Definition: remoteoutput.h:182
RemoteOutput(DeviceAPI *deviceAPI)
std::time_t m_startingTimeStamp
Definition: remoteoutput.h:176
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
Definition: deviceapi.cpp:266
void setBufferRwBalance(float buffer_rw_balance)
uint32_t m_nbRemoteSamplesSinceRateCorrection
Definition: remoteoutput.h:189
uint32_t m_tickCount
Definition: remoteoutput.h:178
virtual bool deserialize(const QByteArray &data)
std::time_t getStartingTimeStamp() const
virtual QString asJson() override
uint32_t getSamplesCount(uint64_t &ts_usecs) const
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
const QTimer & m_masterTimer
Definition: remoteoutput.h:177
void setSamplerate(int samplerate)
virtual int getSampleRate() const
Sample rate exposed by the sink.
const RemoteOutputSettings & getSettings() const
Definition: remoteoutput.h:47
void setNbSinkStreams(uint32_t nbSinkStreams)
Definition: deviceapi.h:169
float getRWBalance() const
uint64_t m_centerFrequency
Definition: remoteoutput.h:173
virtual bool handleMessage(const Message &message)
void setCenterFrequency(qint32 center_frequency)
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
static MsgConfigureRemoteOutput * create(const RemoteOutputSettings &settings, bool force=false)
Definition: remoteoutput.h:50
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
int m_lastQueueLength
Definition: remoteoutput.h:188
static const uint32_t NbSamplesForRateCorrection
Definition: remoteoutput.h:192
void setTxDelay(float txDelay)
void setChunkCorrection(int chunkCorrection)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
RemoteOutputSettings m_settings
Definition: remoteoutput.h:172
void setOriginatorIndex(qint32 originator_index)
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
unsigned int uint32_t
Definition: rtptypes_win.h:46
uint32_t m_lastSampleCount
Definition: remoteoutput.h:185
void applySettings(const RemoteOutputSettings &settings, bool force=false)
QString m_deviceDescription
Definition: remoteoutput.h:175
void analyzeApiReply(const QJsonObject &jsonObject, const QString &answer)
MessageQueue m_inputMessageQueue
Input queue to the sink.
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const RemoteOutputSettings &settings, bool force)
int getDeviceSetIndex() const
Definition: deviceapi.h:131
MessageQueue * getInputMessageQueue()
void setReverseApiAddress(QString *reverse_api_address)
uint64_t m_lastTimestampRateCorrection
Definition: remoteoutput.h:187
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
static MsgStartStop * create(bool startStop)
Definition: remoteoutput.h:92
uint32_t m_nbSamplesSinceRateCorrection
Definition: remoteoutput.h:190
void setNbBlocksFEC(uint32_t nbBlocksFEC)
virtual ~RemoteOutput()
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
virtual void destroy()
virtual const QString & getDeviceDescription() const
void setRemoteOutputReport(SWGRemoteOutputReport *remote_output_report)
static bool match(const Message *message)
Definition: message.cpp:45
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
virtual bool start()
uint32_t m_lastRemoteSampleCount
Definition: remoteoutput.h:184
virtual void stop()
uint64_t m_lastRemoteTimestampRateCorrection
Definition: remoteoutput.h:186
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const RemoteOutputSettings &settings)
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
void setRemoteOutputSettings(SWGRemoteOutputSettings *remote_output_settings)
void sampleRateCorrection(double remoteTimeDeltaUs, double timeDeltaUs, uint32_t remoteSampleCount, uint32_t sampleCount)
void webapiReverseSendStartStop(bool start)
static MsgConfigureRemoteOutputChunkCorrection * create(int chunkCorrection)
Definition: remoteoutput.h:111
uint32_t m_tickMultiplier
Definition: remoteoutput.h:179
void networkManagerFinished(QNetworkReply *reply)
QByteArray serialize() const
virtual const char * getIdentifier() const
Definition: message.cpp:35
SampleSourceFifo m_sampleSourceFifo
SWGRemoteOutputSettings * getRemoteOutputSettings()
virtual quint64 getCenterFrequency() const
Center frequency exposed by the sink.
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
int m_chunkSizeCorrection
Definition: remoteoutput.h:191
void setDataAddress(const QString &address, uint16_t port)
void setUseReverseApi(qint32 use_reverse_api)
void setDirection(qint32 direction)
bool deserialize(const QByteArray &data)
SWGRemoteOutputReport * getRemoteOutputReport()
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
void connectTimer(const QTimer &timer)
QNetworkAccessManager * m_networkManager
Definition: remoteoutput.h:181
DeviceAPI * m_deviceAPI
Definition: remoteoutput.h:170
void setDeviceHwType(QString *device_hw_type)
unsigned __int64 uint64_t
Definition: rtptypes_win.h:48