1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 09:18:54 -05:00

RemoteTCPSink: Report server init errors via GUI. Send protocol to public list.

RemoteTCPInput: Add wss protocol support.
This commit is contained in:
srcejon 2024-10-08 17:20:18 +01:00
parent 04524505dd
commit 96422ff19f
21 changed files with 356 additions and 191 deletions

View File

@ -7,7 +7,6 @@ set(remotetcpsink_SOURCES
remotetcpsinksettings.cpp
remotetcpsinkwebapiadapter.cpp
remotetcpsinkplugin.cpp
socket.cpp
)
set(remotetcpsink_HEADERS
@ -18,7 +17,6 @@ set(remotetcpsink_HEADERS
remotetcpsinkwebapiadapter.h
remotetcpsinkplugin.h
remotetcpprotocol.h
socket.h
)
include_directories(

View File

@ -6,7 +6,7 @@ The Remote TCP Sink Channel plugin sends I/Q samples from the baseband via TCP/I
The client application could be SDRangel using the [Remote TCP Input](../../samplesource/remotetcpinput/readme.md) plugin or an rtl_tcp compatible application.
This means that applications using rtl_tcp protocol can connect to the wide variety of SDRs supported by SDRangel.
While the plugin supports the RTL0 protocol for compatibility with older applications, the newer SDRA protocol supports the following additional features:
While the plugin supports rtl_tcp's RTL0 protocol for compatibility with older applications, the newer SDRA protocol supports the following additional features:
- Different bit depths (8, 16, 24 or 32),
- Additional settings, such as decimation, frequency offset and channel gain,
@ -14,7 +14,8 @@ While the plugin supports the RTL0 protocol for compatibility with older applica
- IQ compression, using FLAC or zlib, to reduce network bandwidth,
- IQ squelch, to reduce network bandwidth when no signal is being received,
- Real-time forwarding of device/antenna position and direction to client,
- Text messaging between clients and server.
- Text messaging between clients and server,
- Use of either TCP or WSS (WebSocket Secure Protocol).
The Remote TCP Sink can support multiple clients connected simultaneously, with a user-defined maximum client limit. Clients can also have a time limit applied.

View File

@ -45,6 +45,7 @@ MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgReportConnection, Message)
MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgReportDisconnect, Message)
MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgReportBW, Message)
MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgSendMessage, Message)
MESSAGE_CLASS_DEFINITION(RemoteTCPSink::MsgError, Message)
const char* const RemoteTCPSink::m_channelIdURI = "sdrangel.channel.remotetcpsink";
const char* const RemoteTCPSink::m_channelId = "RemoteTCPSink";
@ -713,9 +714,17 @@ void RemoteTCPSink::updatePublicListing()
QString device = MainCore::instance()->getDevice(getDeviceSetIndex())->getHardwareId();
QString protocol;
if (m_settings.m_protocol == RemoteTCPSinkSettings::SDRA_WSS) {
protocol = "SDRangel wss";
} else {
protocol = "SDRangel";
}
QJsonObject json;
json.insert("address", m_settings.m_publicAddress);
json.insert("port", m_settings.m_publicPort);
json.insert("protocol", protocol);
json.insert("minFrequency", m_settings.m_minFrequency);
json.insert("maxFrequency", m_settings.m_maxFrequency);
json.insert("maxSampleRate", m_settings.m_maxSampleRate);

View File

@ -183,6 +183,27 @@ public:
{ }
};
class MsgError : public Message {
MESSAGE_CLASS_DECLARATION
public:
const QString& getError() const { return m_error; }
static MsgError *create(const QString& error)
{
return new MsgError(error);
}
private:
QString m_error;
MsgError(const QString& error) :
Message(),
m_error(error)
{ }
};
RemoteTCPSink(DeviceAPI *deviceAPI);
virtual ~RemoteTCPSink();
virtual void destroy() { delete this; }

View File

@ -18,6 +18,7 @@
#include <QHostAddress>
#include <QNetworkInterface>
#include <QTableWidgetItem>
#include <QMessageBox>
#include "device/deviceuiset.h"
#include "gui/basicchannelsettingsdialog.h"
@ -276,6 +277,13 @@ bool RemoteTCPSinkGUI::handleMessage(const Message& message)
return true;
}
else if (RemoteTCPSink::MsgError::match(message))
{
RemoteTCPSink::MsgError& msg = (RemoteTCPSink::MsgError&) message;
QString error = msg.getError();
QMessageBox::warning(this, "RemoteTCPSink", error, QMessageBox::Ok);
return true;
}
else
{
return false;

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -108,7 +108,7 @@
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Channel frequency shift from center in Hz</string>
@ -125,7 +125,7 @@
<item>
<spacer name="channelSettingsHorizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -177,7 +177,7 @@
<item>
<widget class="Line" name="line_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -193,13 +193,13 @@
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
<enum>Qt::LayoutDirection::RightToLeft</enum>
</property>
<property name="text">
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
@ -263,7 +263,7 @@
<item>
<widget class="Line" name="line_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -301,7 +301,7 @@
<string>-150</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
@ -315,7 +315,7 @@
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -335,7 +335,7 @@
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -366,7 +366,7 @@
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -381,7 +381,7 @@
<item>
<widget class="Line" name="line_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -435,7 +435,7 @@
<item>
<spacer name="samplesSettingsHorizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -497,7 +497,7 @@
<item>
<widget class="Line" name="line_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -549,7 +549,7 @@
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -587,12 +587,12 @@
</item>
<item>
<property name="text">
<string>SDRA</string>
<string>SDRangel</string>
</property>
</item>
<item>
<property name="text">
<string>SDRA wss</string>
<string>SDRangel wss</string>
</property>
</item>
</widget>
@ -628,7 +628,7 @@
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -658,7 +658,7 @@
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -696,6 +696,12 @@ Values are averaged over the last 10 seconds</string>
<height>191</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Messages</string>
</property>
@ -759,6 +765,12 @@ Values are averaged over the last 10 seconds</string>
<height>191</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Connection Log</string>
</property>

View File

@ -380,10 +380,10 @@ void RemoteTCPSinkSink::processOneSample(Complex &ci)
if (ret == Z_STREAM_END) {
deflateReset(&m_zStream);
} else if (ret != Z_OK) {
qDebug() << "Failed to deflate" << ret;
qDebug() << "RemoteTCPSinkSink::processOneSample: Failed to deflate" << ret;
}
if (m_zStream.avail_in != 0) {
qDebug() << "Warning: Data still in input buffer";
qDebug() << "RemoteTCPSinkSink::processOneSample: Data still in input buffer";
}
int compressedBytes = m_zOutBuf.size() - m_zStream.avail_out;
@ -497,6 +497,7 @@ void RemoteTCPSinkSink::applySettings(const RemoteTCPSinkSettings& settings, con
}
if ((settingsKeys.contains("compressionLevel") && (settings.m_compressionLevel != m_settings.m_compressionLevel))
|| (settingsKeys.contains("compression") && (settings.m_compression != m_settings.m_compression))
|| (settingsKeys.contains("sampleBits") && (settings.m_sampleBits != m_settings.m_sampleBits))
|| (settingsKeys.contains("blockSize") && (settings.m_blockSize != m_settings.m_blockSize))
|| (settingsKeys.contains("channelSampleRate") && (settings.m_channelSampleRate != m_settings.m_channelSampleRate))
@ -506,6 +507,7 @@ void RemoteTCPSinkSink::applySettings(const RemoteTCPSinkSettings& settings, con
}
if ((settingsKeys.contains("compressionLevel") && (settings.m_compressionLevel != m_settings.m_compressionLevel))
|| (settingsKeys.contains("compression") && (settings.m_compression != m_settings.m_compression))
|| force)
{
initZLib = true;
@ -670,15 +672,46 @@ void RemoteTCPSinkSink::startServer()
if (m_settings.m_protocol == RemoteTCPSinkSettings::SDRA_WSS)
{
#ifndef QT_NO_OPENSSL
m_webSocketServer = new QWebSocketServer(QStringLiteral("Remote TCP Sink"),
QWebSocketServer::SecureMode,
this);
QSslConfiguration sslConfiguration;
qDebug() << "RemoteTCPSinkSink::startServer: SSL config: " << m_settings.m_certificate << m_settings.m_key;
if (m_settings.m_certificate.isEmpty())
{
QString msg = "RemoteTCPSink requires an SSL certificate in order to use wss protocol";
qWarning() << msg;
if (m_messageQueueToGUI) {
m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg));
}
return;
}
if (m_settings.m_certificate.isEmpty())
{
QString msg = "RemoteTCPSink requires an SSL key in order to use wss protocol";
qWarning() << msg;
if (m_messageQueueToGUI) {
m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg));
}
return;
}
QFile certFile(m_settings.m_certificate);
if (!certFile.open(QIODevice::ReadOnly))
{
QString msg = QString("RemoteTCPSink failed to open certificate %1: %2").arg(m_settings.m_certificate).arg(certFile.errorString());
qWarning() << msg;
if (m_messageQueueToGUI) {
m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg));
}
return;
}
QFile keyFile(m_settings.m_key);
certFile.open(QIODevice::ReadOnly);
keyFile.open(QIODevice::ReadOnly);
if (!keyFile.open(QIODevice::ReadOnly))
{
QString msg = QString("RemoteTCPSink failed to open key %1: %2").arg(m_settings.m_key).arg(keyFile.errorString());
qWarning() << msg;
if (m_messageQueueToGUI) {
m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg));
}
return;
}
QSslCertificate certificate(&certFile, QSsl::Pem);
QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
certFile.close();
@ -686,6 +719,10 @@ void RemoteTCPSinkSink::startServer()
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
sslConfiguration.setLocalCertificate(certificate);
sslConfiguration.setPrivateKey(sslKey);
m_webSocketServer = new QWebSocketServer(QStringLiteral("Remote TCP Sink"),
QWebSocketServer::SecureMode,
this);
m_webSocketServer->setSslConfiguration(sslConfiguration);
QHostAddress address(m_settings.m_dataAddress);
@ -695,8 +732,11 @@ void RemoteTCPSinkSink::startServer()
#endif
if (!m_webSocketServer->listen(address, m_settings.m_dataPort))
{
qCritical() << "RemoteTCPSink failed to listen on" << m_settings.m_dataAddress << "port" << m_settings.m_dataPort;
// FIXME: Report to GUI?
QString msg = QString("RemoteTCPSink failed to listen on %1 port %2: %3").arg(m_settings.m_dataAddress).arg(m_settings.m_dataPort).arg(m_webSocketServer->errorString());
qWarning() << msg;
if (m_messageQueueToGUI) {
m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg));
}
}
else
{
@ -705,7 +745,11 @@ void RemoteTCPSinkSink::startServer()
connect(m_webSocketServer, &QWebSocketServer::sslErrors, this, &RemoteTCPSinkSink::onSslErrors);
}
#else
qWarning("RemoteTCPSinkSink::startServer: SSL is not supported");
QString msg = "RemoteTCPSink unable to use wss protocol as SSL is not supported";
qWarning() << msg;
if (m_messageQueueToGUI) {
m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg));
}
#endif
}
else
@ -713,8 +757,11 @@ void RemoteTCPSinkSink::startServer()
m_server = new QTcpServer(this);
if (!m_server->listen(QHostAddress(m_settings.m_dataAddress), m_settings.m_dataPort))
{
qCritical() << "RemoteTCPSink failed to listen on" << m_settings.m_dataAddress << "port" << m_settings.m_dataPort;
// FIXME: Report to GUI?
QString msg = QString("RemoteTCPSink failed to listen on %1 port %2: %3").arg(m_settings.m_dataAddress).arg(m_settings.m_dataPort).arg(m_webSocketServer->errorString());
qWarning() << msg;
if (m_messageQueueToGUI) {
m_messageQueueToGUI->push(RemoteTCPSink::MsgError::create(msg));
}
}
else
{

View File

@ -40,7 +40,7 @@
#include "remotetcpsinksettings.h"
#include "remotetcpprotocol.h"
#include "socket.h"
#include "util/socket.h"
class DeviceSampleSource;

View File

@ -57,6 +57,7 @@ endif()
target_link_libraries(${TARGET_NAME} PRIVATE
Qt::Core
Qt::WebSockets
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}

View File

@ -93,7 +93,7 @@ When unchecked, the channel sample rate can be set to any value.
Specifies number of bits per I/Q sample transmitted via TCP/IP.
When the protocol is RTL0, only 8-bits are supported. SDRA and Spy Server protocol supports 8, 16, 24 and 32-bit samples.
When the protocol is RTL0, only 8-bits are supported. SDRangel and Spy Server protocol supports 8, 16, 24 and 32-bit samples.
<h3>19: Server IP address</h3>
@ -105,14 +105,16 @@ TCP port on the server to connect to.
<h3>21: Protocol</h3>
Selects protocol to use. Set to SDRangel for rtl_tcp, rsp_tcp or SDRangel's own protocol. Alternative, Spy Server can be selected to connect to Spy Servers.
Selects protocol to use. Set to SDRangel for rtl_tcp, rsp_tcp or SDRangel's own protocol.
Set to SDRangel wss to use SDRangel's protocol over WebSocket Secure.
Alternatively, Spy Server can be selected to connect to Spy Servers.
<h3>23: Connection settings</h3>
Determines which settings are used when connecting.
When checked, settings in the RemoteTCPInput GUI are written to the remote device upon connection.
When unchecked, if the remote server is using the SDRA protocol, the RemoteTCPInput GUI will be updated with the current settings from the remote device.
When unchecked, if the remote server is using the SDRangel protocol, the RemoteTCPInput GUI will be updated with the current settings from the remote device.
If the remote server is using the RTL0 protocol, the GUI will not be updated, which may mean the two are inconsistent.
<h3>24: Pre-fill</h3>

View File

@ -96,7 +96,7 @@ void RemoteTCPInput::destroy()
void RemoteTCPInput::init()
{
qDebug() << "*************** RemoteTCPInput::init";
qDebug() << "RemoteTCPInput::init";
applySettings(m_settings, QList<QString>(), true);
}
@ -109,7 +109,6 @@ bool RemoteTCPInput::start()
}
m_remoteInputTCPPHandler->reset();
m_remoteInputTCPPHandler->start();
qDebug() << "************ RemoteTCPInput::start" << m_settings.m_dataAddress;
m_remoteInputTCPPHandler->getInputMessageQueue()->push(RemoteTCPInputTCPHandler::MsgConfigureTcpHandler::create(m_settings, QList<QString>(), true));
m_thread.start();
m_running = true;
@ -122,19 +121,14 @@ void RemoteTCPInput::stop()
if (!m_running) {
// For wasm, important not to call m_remoteInputTCPPHandler->stop() twice
// as mutex can deadlock when this object is being deleted
qDebug() << "RemoteTCPInput::stop - Not running";
return;
}
m_remoteInputTCPPHandler->stop();
qDebug() << "RemoteTCPInput::stop1";
m_thread.quit();
qDebug() << "RemoteTCPInput::stop2";
#ifndef __EMSCRIPTEN__
qDebug() << "RemoteTCPInput::stop3";
m_thread.wait();
#endif
m_running = false;
qDebug() << "RemoteTCPInput::stopped";
}
QByteArray RemoteTCPInput::serialize() const
@ -151,9 +145,6 @@ bool RemoteTCPInput::deserialize(const QByteArray& data)
m_settings.resetToDefaults();
success = false;
}
qDebug() << "************** RemoteTCPInput::deserialize" << m_settings.m_dataAddress;
MsgConfigureRemoteTCPInput* message = MsgConfigureRemoteTCPInput::create(m_settings, QList<QString>(), true);
m_inputMessageQueue.push(message);
@ -230,7 +221,6 @@ bool RemoteTCPInput::handleMessage(const Message& message)
{
qDebug() << "RemoteTCPInput::handleMessage:" << message.getIdentifier();
MsgConfigureRemoteTCPInput& conf = (MsgConfigureRemoteTCPInput&) message;
qDebug() << "*********** RemoteTCPInput::handleMessage MsgConfigureRemoteTCPInput" << m_settings.m_dataAddress;
applySettings(conf.getSettings(), conf.getSettingsKeys(), conf.getForce());
return true;
}

View File

@ -117,7 +117,7 @@ void RemoteTCPInputGui::destroy()
void RemoteTCPInputGui::resetToDefaults()
{
qDebug() << "*************** RemoteTCPInputGui::resetToDefaults";
qDebug() << "RemoteTCPInputGui::resetToDefaults";
m_settings.resetToDefaults();
displaySettings();
m_forceSettings = true;
@ -158,7 +158,6 @@ bool RemoteTCPInputGui::handleMessage(const Message& message)
} else {
m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings());
}
qDebug() << "********* RemoteTCPInputGui::handleMessage MsgConfigureRemoteTCPInput" << m_settings.m_dataAddress;
blockApplySettings(true);
displaySettings();
@ -304,16 +303,7 @@ bool RemoteTCPInputGui::handleMessage(const Message& message)
{
const RemoteTCPInputTCPHandler::MsgReportConnection& report = (RemoteTCPInputTCPHandler::MsgReportConnection&) message;
qDebug() << "RemoteTCPInputGui::handleMessage: MsgReportConnection connected: " << report.getConnected();
if (report.getConnected())
{
m_connectionError = false;
//ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
}
else
{
m_connectionError = true;
//ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
}
m_connectionError = !report.getConnected();
updateStatus();
return true;
}
@ -921,14 +911,18 @@ void RemoteTCPInputGui::on_squelchGate_valueChanged(double value)
void RemoteTCPInputGui::on_dataAddress_editingFinished()
{
m_settings.m_dataAddress = ui->dataAddress->currentText();
m_settingsKeys.append("dataAddress");
m_settings.m_addressList.clear();
for (int i = 0; i < ui->dataAddress->count(); i++) {
m_settings.m_addressList.append(ui->dataAddress->itemText(i));
QString text = ui->dataAddress->currentText();
if (text != m_settings.m_dataAddress)
{
m_settings.m_dataAddress = text;
m_settingsKeys.append("dataAddress");
m_settings.m_addressList.clear();
for (int i = 0; i < ui->dataAddress->count(); i++) {
m_settings.m_addressList.append(ui->dataAddress->itemText(i));
}
m_settingsKeys.append("addressList");
sendSettings();
}
m_settingsKeys.append("addressList");
sendSettings();
}
void RemoteTCPInputGui::on_dataAddress_currentIndexChanged(int index)

View File

@ -89,7 +89,7 @@
<string>00000k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
@ -100,7 +100,7 @@
<item>
<spacer name="freqLeftSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -134,7 +134,7 @@
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Center frequency in kHz</string>
@ -153,14 +153,14 @@
<string> kHz</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -199,7 +199,7 @@
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -215,7 +215,7 @@
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
@ -224,7 +224,7 @@
<item>
<widget class="Line" name="line_rateTime">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -253,7 +253,7 @@
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -288,7 +288,7 @@
<item>
<widget class="Line" name="line_address">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -342,7 +342,7 @@
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -415,7 +415,7 @@
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -459,14 +459,14 @@
<string>40.0dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="gainLine1">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -500,7 +500,7 @@
<item>
<widget class="Line" name="gainLine2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -534,7 +534,7 @@
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -559,7 +559,7 @@
<item>
<widget class="Line" name="line_rfBW">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -609,7 +609,7 @@
<item>
<spacer name="rfBWSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -624,7 +624,7 @@
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -669,7 +669,7 @@
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
<enum>Qt::FocusPolicy::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Channel shift frequency from center in Hz</string>
@ -686,7 +686,7 @@
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -804,7 +804,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -866,7 +866,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<item>
<widget class="Line" name="line_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -921,7 +921,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<item>
<widget class="Line" name="line_12">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -959,7 +959,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<string>-150</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
@ -973,7 +973,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<item>
<widget class="Line" name="line_13">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -993,14 +993,14 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<item>
<widget class="Line" name="line_14">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -1022,13 +1022,13 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
<enum>Qt::LayoutDirection::RightToLeft</enum>
</property>
<property name="text">
<string>0.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
@ -1044,7 +1044,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<item>
<widget class="Line" name="line_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -1065,6 +1065,12 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
</item>
<item>
<widget class="QComboBox" name="dataAddress">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
@ -1110,7 +1116,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -1124,7 +1130,7 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<widget class="QComboBox" name="protocol">
<property name="minimumSize">
<size>
<width>92</width>
<width>110</width>
<height>0</height>
</size>
</property>
@ -1136,6 +1142,11 @@ Use to ensure full dynamic range of 8-bit data is used.</string>
<string>SDRangel</string>
</property>
</item>
<item>
<property name="text">
<string>SDRangel wss</string>
</property>
</item>
<item>
<property name="text">
<string>Spy Server</string>
@ -1200,7 +1211,7 @@ When unchecked, if remote device is using SDRA protocol, local settings are upda
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -1263,14 +1274,14 @@ When unchecked, if remote device is using SDRA protocol, local settings are upda
<string>10.00s</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="buferLine">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -1328,7 +1339,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<item>
<widget class="Line" name="line_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -1390,7 +1401,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<string>Messages</string>
</property>
<property name="movement">
<enum>QListView::Static</enum>
<enum>QListView::Movement::Static</enum>
</property>
</widget>
</item>
@ -1399,7 +1410,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<item>
<widget class="Line" name="line_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -1427,7 +1438,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<number>500</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -1504,7 +1515,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<item>
<widget class="Line" name="line_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
@ -1520,7 +1531,7 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
@ -1547,18 +1558,18 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<header>gui/valuedialz.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LevelMeterSignalDB</class>
<extends>QWidget</extends>
<header>gui/levelmeter.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>PeriodDial</class>
<extends>QWidget</extends>
@ -1583,10 +1594,23 @@ This should typically be empty. If full, your CPU cannot keep up and data will b
<tabstop>channelGain</tabstop>
<tabstop>decimation</tabstop>
<tabstop>sampleBits</tabstop>
<tabstop>squelchEnabled</tabstop>
<tabstop>squelch</tabstop>
<tabstop>dataAddress</tabstop>
<tabstop>dataPort</tabstop>
<tabstop>protocol</tabstop>
<tabstop>overrideRemoteSettings</tabstop>
<tabstop>preFill</tabstop>
<tabstop>sendMessage</tabstop>
<tabstop>txAddress</tabstop>
<tabstop>txMessage</tabstop>
<tabstop>messages</tabstop>
<tabstop>replayOffset</tabstop>
<tabstop>replayNow</tabstop>
<tabstop>replayPlus</tabstop>
<tabstop>replayMinus</tabstop>
<tabstop>replayLoop</tabstop>
<tabstop>replaySave</tabstop>
</tabstops>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>

View File

@ -53,7 +53,7 @@ struct RemoteTCPInputSettings
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
QStringList m_addressList; // List of dataAddresses that have been used in the past
QString m_protocol; // "SDRangel" or "Spy Server"
QString m_protocol; // "SDRangel", "SDRangel wss" or "Spy Server"
float m_replayOffset; //!< Replay offset in seconds
float m_replayLength; //!< Replay buffer size in seconds
float m_replayStep; //!< Replay forward/back step size in seconds

View File

@ -18,6 +18,7 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QMessageBox>
#include <cstring>
#include "device/deviceapi.h"
@ -36,6 +37,8 @@ RemoteTCPInputTCPHandler::RemoteTCPInputTCPHandler(SampleSinkFifo *sampleFifo, D
m_deviceAPI(deviceAPI),
m_running(false),
m_dataSocket(nullptr),
m_tcpSocket(nullptr),
m_webSocket(nullptr),
m_tcpBuf(nullptr),
m_sampleFifo(sampleFifo),
m_replayBuffer(replayBuffer),
@ -82,9 +85,7 @@ RemoteTCPInputTCPHandler::~RemoteTCPInputTCPHandler()
if (m_converterBuffer) {
delete[] m_converterBuffer;
}
qDebug() << "RemoteTCPInputTCPHandler::~RemoteTCPInputTCPHandler cleanup";
cleanup();
qDebug() << "RemoteTCPInputTCPHandler::~RemoteTCPInputTCPHandler done";
}
void RemoteTCPInputTCPHandler::reset()
@ -114,7 +115,6 @@ void RemoteTCPInputTCPHandler::start()
void RemoteTCPInputTCPHandler::stop()
{
qDebug("RemoteTCPInputTCPHandler::stop locking");
QMutexLocker mutexLocker(&m_mutex);
qDebug("RemoteTCPInputTCPHandler::stop");
@ -142,24 +142,40 @@ void RemoteTCPInputTCPHandler::finished()
cleanup();
disconnect(thread(), SIGNAL(finished()), this, SLOT(finished()));
m_running = false;
qDebug("RemoteTCPInputTCPHandler::finished done");
}
void RemoteTCPInputTCPHandler::connectToHost(const QString& address, quint16 port)
void RemoteTCPInputTCPHandler::connectToHost(const QString& address, quint16 port, const QString& protocol)
{
qDebug("RemoteTCPInputTCPHandler::connectToHost: connect to %s:%d", address.toStdString().c_str(), port);
m_dataSocket = new QTcpSocket(this);
qDebug("RemoteTCPInputTCPHandler::connectToHost: connect to %s %s:%d", protocol.toStdString().c_str(), address.toStdString().c_str(), port);
m_fillBuffer = true;
m_readMetaData = false;
connect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()));
connect(m_dataSocket, SIGNAL(connected()), this, SLOT(connected()));
connect(m_dataSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
connect(m_dataSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred);
#else
connect(m_dataSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred);
if (protocol == "SDRangel wss")
{
m_webSocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
connect(m_webSocket, &QWebSocket::binaryFrameReceived, this, &RemoteTCPInputTCPHandler::dataReadyRead);
connect(m_webSocket, &QWebSocket::connected, this, &RemoteTCPInputTCPHandler::connected);
connect(m_webSocket, &QWebSocket::disconnected, this, &RemoteTCPInputTCPHandler::disconnected);
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
connect(m_webSocket, &QWebSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred);
#endif
m_dataSocket->connectToHost(address, port);
connect(m_webSocket, &QWebSocket::sslErrors, this, &RemoteTCPInputTCPHandler::sslErrors);
m_webSocket->open(QUrl(QString("wss://%1:%2").arg(address).arg(port)));
m_dataSocket = new WebSocket(m_webSocket);
}
else
{
m_tcpSocket = new QTcpSocket(this);
connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()));
connect(m_tcpSocket, SIGNAL(connected()), this, SLOT(connected()));
connect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
connect(m_tcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred);
#else
connect(m_tcpSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred);
#endif
m_tcpSocket->connectToHost(address, port);
m_dataSocket = new TCPSocket(m_tcpSocket);
}
}
/*void RemoteTCPInputTCPHandler::disconnectFromHost()
@ -187,22 +203,45 @@ void RemoteTCPInputTCPHandler::cleanup()
FLAC__stream_decoder_delete(m_decoder);
m_decoder = nullptr;
}
if (m_webSocket)
{
qDebug() << "RemoteTCPInputTCPHandler::cleanup: Closing and deleting web socket";
disconnect(m_webSocket, &QWebSocket::binaryFrameReceived, this, &RemoteTCPInputTCPHandler::dataReadyRead);
disconnect(m_webSocket, &QWebSocket::connected, this, &RemoteTCPInputTCPHandler::connected);
disconnect(m_webSocket, &QWebSocket::disconnected, this, &RemoteTCPInputTCPHandler::disconnected);
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
disconnect(m_webSocket, &QWebSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred);
#endif
}
if (m_tcpSocket)
{
qDebug() << "RemoteTCPInputTCPHandler::cleanup: Closing and deleting TCP socket";
// Disconnect disconnected, so don't get called recursively
disconnect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()));
disconnect(m_tcpSocket, SIGNAL(connected()), this, SLOT(connected()));
disconnect(m_tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
disconnect(m_tcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred);
#else
disconnect(m_tcpSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred);
#endif
}
if (m_dataSocket)
{
qDebug() << "RemoteTCPInputTCPHandler::cleanup: Closing and deleting socket";
// Disconnect disconnected, so don't get called recursively
disconnect(m_dataSocket, SIGNAL(readyRead()), this, SLOT(dataReadyRead()));
disconnect(m_dataSocket, SIGNAL(connected()), this, SLOT(connected()));
disconnect(m_dataSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
disconnect(m_dataSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &RemoteTCPInputTCPHandler::errorOccurred);
#else
disconnect(m_dataSocket, &QAbstractSocket::errorOccurred, this, &RemoteTCPInputTCPHandler::errorOccurred);
#endif
m_dataSocket->close();
m_dataSocket->deleteLater();
m_dataSocket = nullptr;
}
if (m_webSocket)
{
m_webSocket->deleteLater();
m_webSocket = nullptr;
}
if (m_tcpSocket)
{
m_tcpSocket->deleteLater();
m_tcpSocket = nullptr;
}
}
// Clear input buffer when settings change that invalidate the data in it
@ -620,7 +659,7 @@ void RemoteTCPInputTCPHandler::applySettings(const RemoteTCPInputSettings& setti
{
//disconnectFromHost();
cleanup();
connectToHost(settings.m_dataAddress, settings.m_dataPort);
connectToHost(settings.m_dataAddress, settings.m_dataPort, settings.m_protocol);
}
if (force) {
@ -651,35 +690,6 @@ static void flacErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDe
return handler->flacError(decoder, status);
}
/*FLAC__StreamDecoderReadStatus RemoteTCPInputTCPHandler::flacRead(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes)
{
if (m_dataSocket)
{
qint64 bytesRequested = *bytes;
qint64 bytesRead = std::min(bytesRequested, m_compressedData.size());
//bytesRead = m_dataSocket->read((char *) buffer, bytesRequested);
memcpy(buffer, m_compressedData.constData(), bytesRead);
qDebug() << "flacRead" << bytesRequested << bytesRead;
if (bytesRead != -1)
{
*bytes = (size_t) bytesRead;
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
else
{
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
}
else
{
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
}*/
FLAC__StreamDecoderReadStatus RemoteTCPInputTCPHandler::flacRead(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes)
{
(void) decoder;
@ -690,7 +700,6 @@ FLAC__StreamDecoderReadStatus RemoteTCPInputTCPHandler::flacRead(const FLAC__Str
memcpy(buffer, m_compressedData.constData(), bytesRead);
m_compressedData.remove(0, bytesRead);
//qDebug() << "RemoteTCPInputTCPHandler::flacRead bytesRequested" << bytesRequested << "bytesRead" << bytesRead;
if (bytesRead == 0)
{
qDebug() << "RemoteTCPInputTCPHandler::flacRead: Decoder will hang if we can't return data";
@ -821,7 +830,6 @@ FLAC__StreamDecoderWriteStatus RemoteTCPInputTCPHandler::flacWrite(const FLAC__S
m_uncompressedFrames++;
int nbSamples = frame->header.blocksize;
//qDebug() << "RemoteTCPInputTCPHandler::flacWrite m_uncompressedFrames" << m_uncompressedFrames << "nbSamples" << nbSamples;
if (nbSamples > (int) m_converterBufferNbSamples)
{
if (m_converterBuffer) {
@ -1011,20 +1019,13 @@ void RemoteTCPInputTCPHandler::connected()
}
// Start calls to processData
m_timer.start();
/*if (m_dataSocket->bytesAvailable()) {
qDebug() << "Data is already available";
dataReadyRead();
} else {
qDebug() << "No data available";
}*/
}
void RemoteTCPInputTCPHandler::reconnect()
{
QMutexLocker mutexLocker(&m_mutex);
if (!m_dataSocket) {
connectToHost(m_settings.m_dataAddress, m_settings.m_dataPort);
connectToHost(m_settings.m_dataAddress, m_settings.m_dataPort, m_settings.m_protocol);
}
}
@ -1071,6 +1072,12 @@ void RemoteTCPInputTCPHandler::errorOccurred(QAbstractSocket::SocketError socket
}
}
void RemoteTCPInputTCPHandler::sslErrors(const QList<QSslError> &errors)
{
qDebug() << "RemoteTCPInputTCPHandler::sslErrors: " << errors;
m_webSocket->ignoreSslErrors(); // FIXME: Add a setting whether to do this?
}
void RemoteTCPInputTCPHandler::dataReadyRead()
{
QMutexLocker mutexLocker(&m_mutex);
@ -1753,7 +1760,6 @@ void RemoteTCPInputTCPHandler::processCommands()
m_compressedData.resize(s + m_commandLength);
qint64 bytesRead = m_dataSocket->read(&m_compressedData.data()[s], m_commandLength);
m_compressedFrames++;
//qDebug() << "*************************** RemoteTCPProtocol::dataIQFLAC m_compressedData.size()" << m_compressedData.size() << "m_compressedFrames" << m_compressedFrames << "m_uncompressedFrames" << m_uncompressedFrames;
if (bytesRead == m_commandLength)
{
// FLAC encoder writes out 4 (fLaC), 38 (STREAMINFO), 51 (?) byte headers, that are transmitted as one command block,
@ -1940,7 +1946,7 @@ void RemoteTCPInputTCPHandler::processData()
{
QMutexLocker mutexLocker(&m_mutex);
if (m_dataSocket && (m_dataSocket->state() == QAbstractSocket::ConnectedState))
if (m_dataSocket && m_dataSocket->isConnected())
{
int sampleRate = m_settings.m_channelSampleRate;
int bytesPerIQPair = m_iqOnly ? (2 * m_settings.m_sampleBits / 8) : (2 * sizeof(Sample));

View File

@ -22,6 +22,7 @@
#include <QObject>
#include <QTcpSocket>
#include <QWebSocket>
#include <QHostAddress>
#include <QRecursiveMutex>
#include <QDateTime>
@ -31,6 +32,7 @@
#include "util/messagequeue.h"
#include "util/movingaverage.h"
#include "util/socket.h"
#include "dsp/replaybuffer.h"
#include "remotetcpinputsettings.h"
#include "../../channelrx/remotetcpsink/remotetcpprotocol.h"
@ -185,6 +187,7 @@ public slots:
void connected();
void disconnected();
void errorOccurred(QAbstractSocket::SocketError socketError);
void sslErrors(const QList<QSslError> &errors);
private:
@ -200,7 +203,9 @@ private:
DeviceAPI *m_deviceAPI;
bool m_running;
QTcpSocket *m_dataSocket;
Socket *m_dataSocket;
QTcpSocket *m_tcpSocket;
QWebSocket *m_webSocket;
char *m_tcpBuf;
SampleSinkFifo *m_sampleFifo;
ReplayBuffer<FixReal> *m_replayBuffer;
@ -253,7 +258,7 @@ private:
MovingAverageUtil<Real, double, 16> m_movingAverage;
bool handleMessage(const Message& message);
void connectToHost(const QString& address, quint16 port);
void connectToHost(const QString& address, quint16 port, const QString& protocol);
//void disconnectFromHost();
void cleanup();
void clearBuffer();

View File

@ -269,6 +269,7 @@ set(sdrbase_SOURCES
util/sdrangelserverlist.cpp
util/simpleserializer.cpp
util/serialutil.cpp
util/socket.cpp
util/solardynamicsobservatory.cpp
util/sondehub.cpp
#util/spinlock.cpp
@ -530,6 +531,7 @@ set(sdrbase_HEADERS
util/sdrangelserverlist.h
util/simpleserializer.h
util/serialutil.h
util/socket.h
util/solardynamicsobservatory.h
util/sondehub.h
#util/spinlock.h

View File

@ -114,6 +114,9 @@ void SDRangelServerList::handleJSON(const QString& url, const QByteArray& bytes)
if (serverObj.contains(QStringLiteral("port"))) {
sdr.m_port = serverObj.value(QStringLiteral("port")).toInt();
}
if (serverObj.contains(QStringLiteral("protocol"))) {
sdr.m_protocol = serverObj.value(QStringLiteral("protocol")).toString();
}
if (serverObj.contains(QStringLiteral("minFrequency"))) {
sdr.m_minFrequency = serverObj.value(QStringLiteral("minFrequency")).toInt();
}

View File

@ -37,6 +37,7 @@ public:
struct SDRangelServer {
QString m_address;
quint16 m_port;
QString m_protocol;
qint64 m_minFrequency;
qint64 m_maxFrequency;
int m_maxSampleRate;

View File

@ -49,6 +49,13 @@ qint64 TCPSocket::read(char *data, qint64 length)
return socket->read(data, length);
}
QByteArray TCPSocket::readAll()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(m_socket);
return socket->readAll();
}
void TCPSocket::close()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(m_socket);
@ -84,6 +91,13 @@ quint16 TCPSocket::peerPort()
return socket->peerPort();
}
bool TCPSocket::isConnected()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(m_socket);
return socket->state() == QAbstractSocket::ConnectedState;
}
WebSocket::WebSocket(QWebSocket *socket) :
Socket(socket)
{
@ -126,11 +140,23 @@ qint64 WebSocket::read(char *data, qint64 length)
return length;
}
QByteArray WebSocket::readAll()
{
QByteArray b = m_rxBuffer;
m_rxBuffer.clear();
return b;
}
void WebSocket::close()
{
QWebSocket *socket = qobject_cast<QWebSocket *>(m_socket);
socket->close();
// Will crash if we call close on unopened socket
if (socket->state() != QAbstractSocket::UnconnectedState) {
socket->close();
}
}
qint64 WebSocket::bytesAvailable()
@ -158,3 +184,10 @@ quint16 WebSocket::peerPort()
return socket->peerPort();
}
bool WebSocket::isConnected()
{
QWebSocket *socket = qobject_cast<QWebSocket *>(m_socket);
return socket->state() == QAbstractSocket::ConnectedState;
}

View File

@ -21,8 +21,10 @@
#include <QTcpSocket>
#include <QWebSocket>
#include "export.h"
// Class to allow easy use of either QTCPSocket or QWebSocket
class Socket : public QObject {
class SDRBASE_API Socket : public QObject {
Q_OBJECT
protected:
Socket(QObject *socket, QObject *parent=nullptr);
@ -33,9 +35,11 @@ public:
virtual void flush() = 0;
virtual qint64 read(char *data, qint64 length) = 0;
virtual qint64 bytesAvailable() = 0;
virtual QByteArray readAll() = 0;
virtual void close() = 0;
virtual QHostAddress peerAddress() = 0;
virtual quint16 peerPort() = 0;
virtual bool isConnected() = 0;
QObject *socket() { return m_socket; }
@ -45,7 +49,7 @@ protected:
};
class TCPSocket : public Socket {
class SDRBASE_API TCPSocket : public Socket {
Q_OBJECT
public:
@ -55,13 +59,15 @@ public:
void flush() override;
qint64 read(char *data, qint64 length) override;
qint64 bytesAvailable() override;
QByteArray readAll() override;
void close() override;
QHostAddress peerAddress() override;
quint16 peerPort() override;
bool isConnected() override;
};
class WebSocket : public Socket {
class SDRBASE_API WebSocket : public Socket {
Q_OBJECT
public:
@ -71,9 +77,11 @@ public:
void flush() override;
qint64 read(char *data, qint64 length) override;
qint64 bytesAvailable() override;
QByteArray readAll() override;
void close() override;
QHostAddress peerAddress() override;
quint16 peerPort() override;
bool isConnected() override;
private slots: