21 #include <QNetworkAccessManager> 22 #include <QNetworkReply> 23 #include <QJsonParseError> 49 m_deviceAPI(deviceAPI),
52 m_remoteOutputThread(0),
53 m_deviceDescription(
"RemoteOutput"),
54 m_startingTimeStamp(0),
55 m_masterTimer(deviceAPI->getMasterTimer()),
58 m_lastRemoteSampleCount(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)
87 QMutexLocker mutexLocker(&
m_mutex);
88 qDebug() <<
"RemoteOutput::start";
105 mutexLocker.unlock();
107 qDebug(
"RemoteOutput::start: started");
119 qDebug() <<
"RemoteOutput::stop";
120 QMutexLocker mutexLocker(&
m_mutex);
182 qDebug() <<
"RemoteOutput::handleMessage:" << message.
getIdentifier();
209 qDebug() <<
"RemoteOutput::handleMessage: MsgStartStop: " << (cmd.
getStartStop() ?
"start" :
"stop");
248 QMutexLocker mutexLocker(&
m_mutex);
249 bool forwardChange =
false;
250 bool changeTxDelay =
false;
251 QList<QString> reverseAPIKeys;
254 reverseAPIKeys.append(
"dataAddress");
257 reverseAPIKeys.append(
"dataPort");
260 reverseAPIKeys.append(
"apiAddress");
263 reverseAPIKeys.append(
"apiPort");
275 reverseAPIKeys.append(
"sampleRate");
284 forwardChange =
true;
285 changeTxDelay =
true;
290 reverseAPIKeys.append(
"nbFECBlocks");
296 changeTxDelay =
true;
301 reverseAPIKeys.append(
"txDelay");
302 changeTxDelay =
true;
312 mutexLocker.unlock();
314 qDebug() <<
"RemoteOutput::applySettings:" 343 QString& errorMessage)
353 QString& errorMessage)
371 QString& errorMessage)
382 const QStringList& deviceSettingsKeys,
384 QString& errorMessage)
389 if (deviceSettingsKeys.contains(
"sampleRate")) {
392 if (deviceSettingsKeys.contains(
"txDelay")) {
395 if (deviceSettingsKeys.contains(
"nbFECBlocks")) {
398 if (deviceSettingsKeys.contains(
"apiAddress")) {
401 if (deviceSettingsKeys.contains(
"apiPort")) {
404 if (deviceSettingsKeys.contains(
"dataAddress")) {
407 if (deviceSettingsKeys.contains(
"dataPort")) {
410 if (deviceSettingsKeys.contains(
"deviceIndex")) {
413 if (deviceSettingsKeys.contains(
"channelIndex")) {
416 if (deviceSettingsKeys.contains(
"useReverseAPI")) {
419 if (deviceSettingsKeys.contains(
"reverseAPIAddress")) {
422 if (deviceSettingsKeys.contains(
"reverseAPIPort")) {
425 if (deviceSettingsKeys.contains(
"reverseAPIDeviceIndex")) {
444 QString& errorMessage)
490 reportURL = QString(
"http://%1:%2/sdrangel/deviceset/%3/channel/%4/report")
507 qInfo(
"RemoteOutput::networkManagerFinished: error: %s", qPrintable(reply->errorString()));
511 QString answer = reply->readAll();
515 QByteArray jsonBytes(answer.toStdString().c_str());
516 QJsonParseError error;
517 QJsonDocument doc = QJsonDocument::fromJson(jsonBytes, &error);
519 if (error.error == QJsonParseError::NoError)
525 QString errorMsg = QString(
"Reply JSON error: ") + error.errorString() + QString(
" at offset ") + QString::number(error.offset);
526 qInfo().noquote() <<
"RemoteOutput::networkManagerFinished" << errorMsg;
529 catch (
const std::exception& ex)
531 QString errorMsg = QString(
"Error parsing request: ") + ex.what();
532 qInfo().noquote() <<
"RemoteOutput::networkManagerFinished" << errorMsg;
538 if (jsonObject.contains(
"RemoteSourceReport"))
540 QJsonObject report = jsonObject[
"RemoteSourceReport"].toObject();
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();
553 uint32_t remoteSampleCountDelta, remoteSampleCount;
554 remoteSampleCount = report[
"samplesCount"].toInt();
562 uint32_t sampleCountDelta, sampleCount;
585 qDebug(
"RemoteOutput::analyzeApiReply: queueLengthPercent: %d m_nbSamplesSinceRateCorrection: %u",
606 else if (jsonObject.contains(
"remoteOutputSettings"))
608 qDebug(
"RemoteOutput::analyzeApiReply: reply:\n%s", answer.toStdString().c_str());
614 double deltaSR = (remoteSampleCount/remoteTimeDeltaUs) - (sampleCount/timeDeltaUs);
615 double chunkCorr = 50000 * deltaSR;
635 if (deviceSettingsKeys.contains(
"sampleRate") || force) {
638 if (deviceSettingsKeys.contains(
"txDelay") || force) {
641 if (deviceSettingsKeys.contains(
"nbFECBlocks") || force) {
644 if (deviceSettingsKeys.contains(
"apiAddress") || force) {
647 if (deviceSettingsKeys.contains(
"apiPort") || force) {
650 if (deviceSettingsKeys.contains(
"dataAddress") || force) {
653 if (deviceSettingsKeys.contains(
"dataPort") || force) {
656 if (deviceSettingsKeys.contains(
"deviceIndex") || force) {
659 if (deviceSettingsKeys.contains(
"channelIndex") || force) {
663 QString deviceSettingsURL = QString(
"http://%1:%2/sdrangel/deviceset/%3/device/settings")
668 m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader,
"application/json");
670 QBuffer *buffer=
new QBuffer();
671 buffer->open((QBuffer::ReadWrite));
672 buffer->write(swgDeviceSettings->
asJson().toUtf8());
678 delete swgDeviceSettings;
688 QString deviceSettingsURL = QString(
"http://%1:%2/sdrangel/deviceset/%3/device/run")
693 m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader,
"application/json");
695 QBuffer *buffer=
new QBuffer();
696 buffer->open((QBuffer::ReadWrite));
697 buffer->write(swgDeviceSettings->
asJson().toUtf8());
706 delete swgDeviceSettings;
virtual QByteArray serialize() const
RemoteOutputThread * m_remoteOutputThread
void setReverseApiPort(qint32 reverse_api_port)
bool startDeviceEngine()
Start the device engine corresponding to the stream type.
QNetworkRequest m_networkRequest
qint32 getReverseApiDeviceIndex()
RemoteOutput(DeviceAPI *deviceAPI)
std::time_t m_startingTimeStamp
void push(Message *message, bool emitSignal=true)
Push message onto queue.
void stopDeviceEngine()
Stop the device engine corresponding to the stream type.
void setBufferRwBalance(float buffer_rw_balance)
uint32_t m_nbRemoteSamplesSinceRateCorrection
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.
QString * getDataAddress()
virtual int webapiReportGet(SWGSDRangel::SWGDeviceReport &response, QString &errorMessage)
const QTimer & m_masterTimer
void setSamplerate(int samplerate)
virtual int getSampleRate() const
Sample rate exposed by the sink.
void setNbSinkStreams(uint32_t nbSinkStreams)
void setSampleRate(qint32 sample_rate)
float getRWBalance() const
uint64_t m_centerFrequency
virtual bool handleMessage(const Message &message)
void setCenterFrequency(qint32 center_frequency)
bool initDeviceEngine()
Init the device engine corresponding to the stream type.
virtual int webapiRunGet(SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
static const uint32_t NbSamplesForRateCorrection
void setTxDelay(float txDelay)
void setChunkCorrection(int chunkCorrection)
void setReverseApiDeviceIndex(qint32 reverse_api_device_index)
RemoteOutputSettings m_settings
void setOriginatorIndex(qint32 originator_index)
void setApiPort(qint32 api_port)
virtual void init()
initializations to be done when all collaborating objects are created and possibly connected ...
uint32_t m_lastSampleCount
void applySettings(const RemoteOutputSettings &settings, bool force=false)
QString m_deviceDescription
void analyzeApiReply(const QJsonObject &jsonObject, const QString &answer)
uint16_t m_reverseAPIDeviceIndex
MessageQueue m_inputMessageQueue
Input queue to the sink.
void setDeviceIndex(qint32 device_index)
void webapiReverseSendSettings(QList< QString > &deviceSettingsKeys, const RemoteOutputSettings &settings, bool force)
QString m_reverseAPIAddress
int getDeviceSetIndex() const
MessageQueue * getInputMessageQueue()
void setReverseApiAddress(QString *reverse_api_address)
uint64_t m_lastTimestampRateCorrection
virtual int webapiSettingsPutPatch(bool force, const QStringList &deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass)
static MsgStartStop * create(bool startStop)
uint32_t m_nbSamplesSinceRateCorrection
void setNbBlocksFEC(uint32_t nbBlocksFEC)
virtual int webapiRun(bool run, SWGSDRangel::SWGDeviceState &response, QString &errorMessage)
void setApiAddress(QString *api_address)
void setChannelIndex(qint32 channel_index)
virtual const QString & getDeviceDescription() const
void setRemoteOutputReport(SWGRemoteOutputReport *remote_output_report)
uint16_t m_reverseAPIPort
static bool match(const Message *message)
virtual int webapiSettingsGet(SWGSDRangel::SWGDeviceSettings &response, QString &errorMessage)
void setSampleCount(qint32 sample_count)
QString * getReverseApiAddress()
uint32_t m_lastRemoteSampleCount
void setTxDelay(float tx_delay)
uint64_t m_lastRemoteTimestampRateCorrection
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings &response, const RemoteOutputSettings &settings)
void getDeviceEngineStateStr(QString &state)
qint32 getUseReverseApi()
void setRemoteOutputSettings(SWGRemoteOutputSettings *remote_output_settings)
void sampleRateCorrection(double remoteTimeDeltaUs, double timeDeltaUs, uint32_t remoteSampleCount, uint32_t sampleCount)
bool getStartStop() const
void webapiReverseSendStartStop(bool start)
uint32_t m_tickMultiplier
void networkManagerFinished(QNetworkReply *reply)
QByteArray serialize() const
virtual const char * getIdentifier() const
SampleSourceFifo m_sampleSourceFifo
SWGRemoteOutputSettings * getRemoteOutputSettings()
qint32 getReverseApiPort()
void setNbFecBlocks(qint32 nb_fec_blocks)
virtual quint64 getCenterFrequency() const
Center frequency exposed by the sink.
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport &response)
int m_chunkSizeCorrection
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
QString * getApiAddress()
void setDeviceHwType(QString *device_hw_type)
void setDataPort(qint32 data_port)
void setDataAddress(QString *data_address)
unsigned __int64 uint64_t