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.
localoutput.cpp
Go to the documentation of this file.
1 // Copyright (C) 2019 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 
21 #include <QDebug>
22 #include <QNetworkReply>
23 #include <QBuffer>
24 
25 #include "SWGDeviceSettings.h"
26 #include "SWGDeviceState.h"
27 #include "SWGDeviceReport.h"
28 #include "SWGLocalOutputReport.h"
29 
30 #include "util/simpleserializer.h"
31 #include "dsp/dspcommands.h"
32 #include "dsp/dspengine.h"
33 #include "device/deviceapi.h"
34 
35 #include "localoutput.h"
36 
40 
42  m_deviceAPI(deviceAPI),
43  m_settings(),
44  m_centerFrequency(0),
45  m_sampleRate(48000),
46  m_fileSink(nullptr),
47  m_deviceDescription("LocalOutput")
48 {
49  m_sampleSourceFifo.resize(96000 * 4);
50  m_deviceAPI->setNbSinkStreams(1);
51  m_networkManager = new QNetworkAccessManager();
52  connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
53 }
54 
56 {
57  disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
58  delete m_networkManager;
59  stop();
60 }
61 
63 {
64  delete this;
65 }
66 
68 {
70 }
71 
73 {
74  qDebug() << "LocalOutput::start";
75  return true;
76 }
77 
79 {
80  qDebug() << "LocalOutput::stop";
81 }
82 
83 QByteArray LocalOutput::serialize() const
84 {
85  return m_settings.serialize();
86 }
87 
88 bool LocalOutput::deserialize(const QByteArray& data)
89 {
90  bool success = true;
91 
92  if (!m_settings.deserialize(data))
93  {
95  success = false;
96  }
97 
99  m_inputMessageQueue.push(message);
100 
101  if (m_guiMessageQueue)
102  {
104  m_guiMessageQueue->push(messageToGUI);
105  }
106 
107  return success;
108 }
109 
111 {
112  m_guiMessageQueue = queue;
113 }
114 
115 const QString& LocalOutput::getDeviceDescription() const
116 {
117  return m_deviceDescription;
118 }
119 
121 {
122  return m_sampleRate;
123 }
124 
125 void LocalOutput::setSampleRate(int sampleRate)
126 {
127  m_sampleRate = sampleRate;
128 
129  DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency); // Frequency in Hz for the DSP engine
131 
132  if (getMessageQueueToGUI())
133  {
135  getMessageQueueToGUI()->push(msg);
136  }
137 }
138 
140 {
141  return m_centerFrequency;
142 }
143 
144 void LocalOutput::setCenterFrequency(qint64 centerFrequency)
145 {
146  m_centerFrequency = centerFrequency;
147 
148  DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency); // Frequency in Hz for the DSP engine
150 
151  if (getMessageQueueToGUI())
152  {
154  getMessageQueueToGUI()->push(msg);
155  }
156 }
157 
159 {
160  if (DSPSignalNotification::match(message))
161  {
162  return false;
163  }
164  else if (MsgStartStop::match(message))
165  {
166  MsgStartStop& cmd = (MsgStartStop&) message;
167  qDebug() << "LocalOutput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
168 
169  if (cmd.getStartStop())
170  {
172  {
174  }
175  }
176  else
177  {
179  }
180 
183  }
184 
185  return true;
186  }
187  else if (MsgConfigureLocalOutput::match(message))
188  {
189  qDebug() << "LocalOutput::handleMessage:" << message.getIdentifier();
191  applySettings(conf.getSettings(), conf.getForce());
192  return true;
193  }
194  else
195  {
196  return false;
197  }
198 }
199 
200 void LocalOutput::applySettings(const LocalOutputSettings& settings, bool force)
201 {
202  QMutexLocker mutexLocker(&m_mutex);
203  std::ostringstream os;
204  QString remoteAddress;
205  QList<QString> reverseAPIKeys;
206 
207  if (settings.m_useReverseAPI)
208  {
209  bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
213  webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
214  }
215 
216  m_settings = settings;
217  m_remoteAddress = remoteAddress;
218 
219  qDebug() << "LocalOutput::applySettings: "
220  << " m_remoteAddress: " << m_remoteAddress;
221 }
222 
224  SWGSDRangel::SWGDeviceState& response,
225  QString& errorMessage)
226 {
227  (void) errorMessage;
229  return 200;
230 }
231 
233  bool run,
234  SWGSDRangel::SWGDeviceState& response,
235  QString& errorMessage)
236 {
237  (void) errorMessage;
239  MsgStartStop *message = MsgStartStop::create(run);
240  m_inputMessageQueue.push(message);
241 
242  if (m_guiMessageQueue) // forward to GUI if any
243  {
244  MsgStartStop *msgToGUI = MsgStartStop::create(run);
245  m_guiMessageQueue->push(msgToGUI);
246  }
247 
248  return 200;
249 }
250 
253  QString& errorMessage)
254 {
255  (void) errorMessage;
257  response.getLocalOutputSettings()->init();
259  return 200;
260 }
261 
263  bool force,
264  const QStringList& deviceSettingsKeys,
265  SWGSDRangel::SWGDeviceSettings& response, // query + response
266  QString& errorMessage)
267 {
268  (void) errorMessage;
269  LocalOutputSettings settings = m_settings;
270 
271  if (deviceSettingsKeys.contains("useReverseAPI")) {
272  settings.m_useReverseAPI = response.getLocalOutputSettings()->getUseReverseApi() != 0;
273  }
274  if (deviceSettingsKeys.contains("reverseAPIAddress")) {
276  }
277  if (deviceSettingsKeys.contains("reverseAPIPort")) {
279  }
280  if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
282  }
283 
286 
287  if (m_guiMessageQueue) // forward to GUI if any
288  {
289  MsgConfigureLocalOutput *msgToGUI = MsgConfigureLocalOutput::create(settings, force);
290  m_guiMessageQueue->push(msgToGUI);
291  }
292 
293  webapiFormatDeviceSettings(response, settings);
294  return 200;
295 }
296 
298 {
299  response.getLocalOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
300 
301  if (response.getLocalOutputSettings()->getReverseApiAddress()) {
303  } else {
304  response.getLocalOutputSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
305  }
306 
309 }
310 
313  QString& errorMessage)
314 {
315  (void) errorMessage;
317  response.getLocalOutputReport()->init();
318  webapiFormatDeviceReport(response);
319  return 200;
320 }
321 
323 {
326 }
327 
328 void LocalOutput::webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const LocalOutputSettings& settings, bool force)
329 {
330  (void) deviceSettingsKeys;
331  (void) force;
333  swgDeviceSettings->setDirection(1); // single Tx
334  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
335  swgDeviceSettings->setDeviceHwType(new QString("LocalOutput"));
337 
338  // transfer data that has been modified. When force is on transfer all data except reverse API data
339 
340  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
341  .arg(settings.m_reverseAPIAddress)
342  .arg(settings.m_reverseAPIPort)
343  .arg(settings.m_reverseAPIDeviceIndex);
344  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
345  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
346 
347  QBuffer *buffer=new QBuffer();
348  buffer->open((QBuffer::ReadWrite));
349  buffer->write(swgDeviceSettings->asJson().toUtf8());
350  buffer->seek(0);
351 
352  // Always use PATCH to avoid passing reverse API settings
353  m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
354 
355  delete swgDeviceSettings;
356 }
357 
359 {
361  swgDeviceSettings->setDirection(0); // single Rx
362  swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
363  swgDeviceSettings->setDeviceHwType(new QString("LocalInput"));
364 
365  QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
369  m_networkRequest.setUrl(QUrl(deviceSettingsURL));
370  m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
371 
372  QBuffer *buffer=new QBuffer();
373  buffer->open((QBuffer::ReadWrite));
374  buffer->write(swgDeviceSettings->asJson().toUtf8());
375  buffer->seek(0);
376 
377  if (start) {
378  m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
379  } else {
380  m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
381  }
382 
383  delete swgDeviceSettings;
384 }
385 
386 void LocalOutput::networkManagerFinished(QNetworkReply *reply)
387 {
388  QNetworkReply::NetworkError replyError = reply->error();
389 
390  if (replyError)
391  {
392  qWarning() << "LocalOutput::networkManagerFinished:"
393  << " error(" << (int) replyError
394  << "): " << replyError
395  << ": " << reply->errorString();
396  return;
397  }
398 
399  QString answer = reply->readAll();
400  answer.chop(1); // remove last \n
401  qDebug("LocalOutput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
402 }
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
Definition: deviceapi.cpp:253
virtual void setMessageQueueToGUI(MessageQueue *queue)
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
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 applySettings(const LocalOutputSettings &settings, bool force=false)
static MsgStartStop * create(bool startStop)
Definition: localoutput.h:71
QByteArray serialize() const
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
virtual void setSampleRate(int sampleRate)
For when the sink sample rate is set externally.
virtual QString asJson() override
MessageQueue * getDeviceEngineInputMessageQueue()
Device engine message queue.
Definition: deviceapi.cpp:316
void setLocalOutputReport(SWGLocalOutputReport *local_output_report)
QNetworkRequest m_networkRequest
Definition: localoutput.h:160
virtual void destroy()
Definition: localoutput.cpp:62
virtual void setCenterFrequency(qint64 centerFrequency)
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
Definition: deviceapi.cpp:240
void setReverseApiPort(qint32 reverse_api_port)
void setReverseApiAddress(QString *reverse_api_address)
void setOriginatorIndex(qint32 originator_index)
QString m_deviceDescription
Definition: localoutput.h:157
void setCenterFrequency(qint32 center_frequency)
MessageQueue m_inputMessageQueue
Input queue to the sink.
bool getStartStop() const
Definition: localoutput.h:69
void webapiReverseSendStartStop(bool start)
SWGLocalOutputSettings * getLocalOutputSettings()
int getDeviceSetIndex() const
Definition: deviceapi.h:131
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
Definition: message.h:52
void setLocalOutputSettings(SWGLocalOutputSettings *local_output_settings)
QString m_remoteAddress
Definition: localoutput.h:156
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const LocalOutputSettings &settings)
virtual bool deserialize(const QByteArray &data)
Definition: localoutput.cpp:88
LocalOutputSettings m_settings
Definition: localoutput.h:153
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
static MsgReportSampleRateAndFrequency * create(int sampleRate, qint64 centerFrequency)
Definition: localoutput.h:91
static bool match(const Message *message)
Definition: message.cpp:45
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
bool deserialize(const QByteArray &data)
QMutex m_mutex
Definition: localoutput.h:152
virtual const QString & getDeviceDescription() const
const LocalOutputSettings & getSettings() const
Definition: localoutput.h:46
virtual int getSampleRate() const
Sample rate exposed by the sink.
qint64 m_centerFrequency
Definition: localoutput.h:154
void getDeviceEngineStateStr(QString &state)
Definition: deviceapi.cpp:389
QNetworkAccessManager * m_networkManager
Definition: localoutput.h:159
virtual void stop()
Definition: localoutput.cpp:78
virtual ~LocalOutput()
Definition: localoutput.cpp:55
void setUseReverseApi(qint32 use_reverse_api)
static MsgConfigureLocalOutput * create(const LocalOutputSettings &settings, bool force=false)
Definition: localoutput.h:49
virtual const char * getIdentifier() const
Definition: message.cpp:35
void networkManagerFinished(QNetworkReply *reply)
DeviceAPI * m_deviceAPI
Definition: localoutput.h:151
virtual quint64 getCenterFrequency() const
Center frequency exposed by the sink.
virtual bool start()
Definition: localoutput.cpp:72
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
int m_sampleRate
Definition: localoutput.h:155
MessageQueue * getMessageQueueToGUI()
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
Definition: localoutput.cpp:67
void setDirection(qint32 direction)
virtual QByteArray serialize() const
Definition: localoutput.cpp:83
MessageQueue * m_guiMessageQueue
Input message queue to the GUI.
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const LocalOutputSettings &settings, bool force)
SWGLocalOutputReport * getLocalOutputReport()
virtual bool handleMessage(const Message &message)
void setDeviceHwType(QString *device_hw_type)