diff --git a/plugins/channeltx/moddatv/datvmod.cpp b/plugins/channeltx/moddatv/datvmod.cpp
index a0a75e5e1..9ec7d1e71 100644
--- a/plugins/channeltx/moddatv/datvmod.cpp
+++ b/plugins/channeltx/moddatv/datvmod.cpp
@@ -52,6 +52,7 @@ MESSAGE_CLASS_DEFINITION(DATVMod::MsgConfigureTsFileName, Message)
MESSAGE_CLASS_DEFINITION(DATVMod::MsgConfigureTsFileSourceSeek, Message)
MESSAGE_CLASS_DEFINITION(DATVMod::MsgConfigureTsFileSourceStreamTiming, Message)
MESSAGE_CLASS_DEFINITION(DATVMod::MsgGetUDPBitrate, Message)
+MESSAGE_CLASS_DEFINITION(DATVMod::MsgGetUDPBufferUtilization, Message)
const char* const DATVMod::m_channelIdURI = "sdrangel.channeltx.moddatv";
const char* const DATVMod::m_channelId = "DATVMod";
@@ -185,6 +186,12 @@ bool DATVMod::handleMessage(const Message& cmd)
return true;
}
+ else if (MsgGetUDPBufferUtilization::match(cmd))
+ {
+ m_basebandSource->getInputMessageQueue()->push(DATVMod::MsgGetUDPBufferUtilization::create());
+
+ return true;
+ }
else
{
return false;
diff --git a/plugins/channeltx/moddatv/datvmod.h b/plugins/channeltx/moddatv/datvmod.h
index 9b7fb86e8..7c36b0e2c 100644
--- a/plugins/channeltx/moddatv/datvmod.h
+++ b/plugins/channeltx/moddatv/datvmod.h
@@ -181,6 +181,23 @@ public:
{ }
};
+ class MsgGetUDPBufferUtilization : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+
+ static MsgGetUDPBufferUtilization* create()
+ {
+ return new MsgGetUDPBufferUtilization();
+ }
+
+ private:
+
+ MsgGetUDPBufferUtilization() :
+ Message()
+ { }
+ };
+
//=================================================================
DATVMod(DeviceAPI *deviceAPI);
diff --git a/plugins/channeltx/moddatv/datvmodbaseband.cpp b/plugins/channeltx/moddatv/datvmodbaseband.cpp
index b4e3af124..d1dfe5c0b 100644
--- a/plugins/channeltx/moddatv/datvmodbaseband.cpp
+++ b/plugins/channeltx/moddatv/datvmodbaseband.cpp
@@ -192,6 +192,11 @@ bool DATVModBaseband::handleMessage(const Message& cmd)
m_source.reportUDPBitrate();
return true;
}
+ else if (DATVMod::MsgGetUDPBufferUtilization::match(cmd))
+ {
+ m_source.reportUDPBufferUtilization();
+ return true;
+ }
else
{
return false;
diff --git a/plugins/channeltx/moddatv/datvmodgui.cpp b/plugins/channeltx/moddatv/datvmodgui.cpp
index 2acbf2129..643de1006 100644
--- a/plugins/channeltx/moddatv/datvmodgui.cpp
+++ b/plugins/channeltx/moddatv/datvmodgui.cpp
@@ -98,6 +98,12 @@ DATVModGUI::DATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
+#ifndef _WIN32
+ // Only currently works on Windows, so hide on other OSes
+ ui->udpBufferUtilization->setVisible(false);
+ ui->udpBufferUtilizationLine->setVisible(false);
+#endif
+
displaySettings();
applySettings(true);
if (!m_settings.m_tsFileName.isEmpty())
@@ -174,6 +180,13 @@ bool DATVModGUI::handleMessage(const Message& message)
m_tickMsgOutstanding = false;
return true;
}
+ else if (DATVModReport::MsgReportUDPBufferUtilization::match(message))
+ {
+ DATVModReport::MsgReportUDPBufferUtilization& report = (DATVModReport::MsgReportUDPBufferUtilization&)message;
+ ui->udpBufferUtilization->setText(tr("%1%").arg(report.getUtilization(), 0, 'f', 1));
+ m_tickMsgOutstanding = false;
+ return true;
+ }
else if (DATVMod::MsgConfigureDATVMod::match(message))
{
const DATVMod::MsgConfigureDATVMod& cfg = (DATVMod::MsgConfigureDATVMod&) message;
@@ -602,6 +615,7 @@ void DATVModGUI::tick()
{
m_tickMsgOutstanding = true;
m_datvMod->getInputMessageQueue()->push(DATVMod::MsgGetUDPBitrate::create());
+ m_datvMod->getInputMessageQueue()->push(DATVMod::MsgGetUDPBufferUtilization::create());
}
}
}
diff --git a/plugins/channeltx/moddatv/datvmodgui.ui b/plugins/channeltx/moddatv/datvmodgui.ui
index 2eff43ce1..f33e011ab 100644
--- a/plugins/channeltx/moddatv/datvmodgui.ui
+++ b/plugins/channeltx/moddatv/datvmodgui.ui
@@ -568,6 +568,23 @@
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ Indicates how full the UDP receive buffer is. If this reaches 100%, packets will likely be dropped.
+
+
+ 0%
+
+
+
-
diff --git a/plugins/channeltx/moddatv/datvmodreport.cpp b/plugins/channeltx/moddatv/datvmodreport.cpp
index 91dd081b2..fc2cb340a 100644
--- a/plugins/channeltx/moddatv/datvmodreport.cpp
+++ b/plugins/channeltx/moddatv/datvmodreport.cpp
@@ -22,6 +22,7 @@ MESSAGE_CLASS_DEFINITION(DATVModReport::MsgReportTsFileSourceStreamTiming, Messa
MESSAGE_CLASS_DEFINITION(DATVModReport::MsgReportTsFileSourceStreamData, Message)
MESSAGE_CLASS_DEFINITION(DATVModReport::MsgReportRates, Message)
MESSAGE_CLASS_DEFINITION(DATVModReport::MsgReportUDPBitrate, Message)
+MESSAGE_CLASS_DEFINITION(DATVModReport::MsgReportUDPBufferUtilization, Message)
DATVModReport::DATVModReport()
{ }
diff --git a/plugins/channeltx/moddatv/datvmodreport.h b/plugins/channeltx/moddatv/datvmodreport.h
index 368ce5b1a..7589cc76f 100644
--- a/plugins/channeltx/moddatv/datvmodreport.h
+++ b/plugins/channeltx/moddatv/datvmodreport.h
@@ -125,6 +125,27 @@ public:
{ }
};
+ class MsgReportUDPBufferUtilization : public Message
+ {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ float getUtilization() const { return m_utilization; }
+
+ static MsgReportUDPBufferUtilization* create(int utilization)
+ {
+ return new MsgReportUDPBufferUtilization(utilization);
+ }
+
+ protected:
+ float m_utilization;
+
+ MsgReportUDPBufferUtilization(int utilization) :
+ Message(),
+ m_utilization(utilization)
+ { }
+ };
+
public:
DATVModReport();
~DATVModReport();
diff --git a/plugins/channeltx/moddatv/datvmodsettings.h b/plugins/channeltx/moddatv/datvmodsettings.h
index 63490de7e..25a2c5289 100644
--- a/plugins/channeltx/moddatv/datvmodsettings.h
+++ b/plugins/channeltx/moddatv/datvmodsettings.h
@@ -108,6 +108,8 @@ struct DATVModSettings
static DATVModulation mapModulation(const QString& string);
static QString mapModulation(DATVModulation modulation);
+ static const int m_udpBufferSize = 5000000;
+
};
#endif /* PLUGINS_CHANNELTX_MODDATV_DATVMODSETTINGS_H_ */
diff --git a/plugins/channeltx/moddatv/datvmodsource.cpp b/plugins/channeltx/moddatv/datvmodsource.cpp
index 70917e498..bfbb4b4dd 100644
--- a/plugins/channeltx/moddatv/datvmodsource.cpp
+++ b/plugins/channeltx/moddatv/datvmodsource.cpp
@@ -43,6 +43,11 @@ extern "C"
#include "datvmodreport.h"
#include "datvmodsource.h"
+#ifdef _WIN32
+#include
+#pragma comment(lib, "Ws2_32.lib")
+#endif
+
const int DATVModSource::m_levelNbSamples = 10000; // every 10ms
// Get transport stream bitrate from file
@@ -223,6 +228,7 @@ DATVModSource::DATVModSource() :
m_udpByteCount(0),
m_udpBufferIdx(0),
m_udpBufferCount(0),
+ m_udpMaxBufferUtilization(0),
m_sampleRate(0),
m_channelSampleRate(1000000),
m_channelFrequencyOffset(0),
@@ -337,6 +343,8 @@ void DATVModSource::modulateSample()
&& ((m_udpSocket != nullptr) && m_udpSocket->hasPendingDatagrams())
)
{
+ updateUDPBufferUtilization();
+
// Get transport stream packets from UDP - buffer if more than one
QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
QByteArray ba = datagram.data();
@@ -577,6 +585,28 @@ void DATVModSource::reportUDPBitrate()
m_udpByteCount = 0;
}
+void DATVModSource::updateUDPBufferUtilization()
+{
+#ifdef _WIN32
+ u_long count;
+ ioctlsocket(m_udpSocket->socketDescriptor(), FIONREAD, &count);
+ if (count > m_udpMaxBufferUtilization) {
+ m_udpMaxBufferUtilization = count;
+ }
+#else
+ // On linux, ioctl(s, SIOCINQ, &count); only returns length of first datagram, so we can't support this
+#endif
+}
+
+void DATVModSource::reportUDPBufferUtilization()
+{
+ // Report maximum utilization since last call
+ updateUDPBufferUtilization();
+ if (getMessageQueueToGUI())
+ getMessageQueueToGUI()->push(DATVModReport::MsgReportUDPBufferUtilization::create(m_udpMaxBufferUtilization / (float)DATVModSettings::m_udpBufferSize * 100.0));
+ m_udpMaxBufferUtilization = 0;
+}
+
void DATVModSource::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
{
qDebug() << "DATVModSource::applyChannelSettings:"
@@ -680,7 +710,7 @@ void DATVModSource::applySettings(const DATVModSettings& settings, bool force)
{
m_udpSocket = new QUdpSocket();
m_udpSocket->bind(QHostAddress(settings.m_udpAddress), settings.m_udpPort);
- m_udpSocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 1000000);
+ m_udpSocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, DATVModSettings::m_udpBufferSize);
m_udpTimingStart = boost::chrono::steady_clock::now();
m_udpByteCount = 0;
}
diff --git a/plugins/channeltx/moddatv/datvmodsource.h b/plugins/channeltx/moddatv/datvmodsource.h
index 6e35c8d4a..95ccc4052 100644
--- a/plugins/channeltx/moddatv/datvmodsource.h
+++ b/plugins/channeltx/moddatv/datvmodsource.h
@@ -70,6 +70,7 @@ public:
void seekTsFileStream(int seekPercentage);
void reportTsFileSourceStreamTiming();
void reportUDPBitrate();
+ void reportUDPBufferUtilization();
private:
uint8_t m_mpegTS[188]; //!< MPEG transport stream packet
@@ -99,6 +100,7 @@ private:
uint8_t m_udpBuffer[188*10];
int m_udpBufferIdx; //!< TS frame index into buffer
int m_udpBufferCount; //!< Number of TS frames in buffer
+ int m_udpMaxBufferUtilization;
int m_sampleRate;
int m_channelSampleRate;
@@ -131,6 +133,7 @@ private:
int getTSBitrate(const QString& filename);
int getDVBSDataBitrate(const DATVModSettings& settings);
void checkBitrates();
+ void updateUDPBufferUtilization();
MessageQueue *getMessageQueueToGUI() { return m_messageQueueToGUI; }