More multi-radio support (nearly working!)

merge-requests/9/merge
Phil Taylor 2022-01-22 15:12:36 +00:00
rodzic 96de9c55fa
commit 39540612c7
15 zmienionych plików z 241 dodań i 77 usunięć

Wyświetl plik

@ -664,6 +664,7 @@ void audioHandler::incomingAudio(audioPacket inPacket)
//qDebug(logAudio()) << "Got" << setup.bits << "bits, length" << livePacket.data.length();
// Incoming data is 8bits?
int tempAmplitude=0;
if (setup.bits == 8)
{
// Current packet is 8bit so need to create a new buffer that is 16bit
@ -672,12 +673,15 @@ void audioHandler::incomingAudio(audioPacket inPacket)
for (int f = 0; f < livePacket.data.length(); f++)
{
int samp = (quint8)livePacket.data[f];
tempAmplitude = qMax(tempAmplitude, abs(samp));
for (int g = setup.radioChan; g <= devChannels; g++)
{
if (setup.ulaw)
if (setup.ulaw) {
*out++ = ulaw_decode[samp] * this->volume;
else
}
else {
*out++ = (qint16)((samp - 128) << 8) * this->volume;
}
}
}
livePacket.data.clear();
@ -693,6 +697,7 @@ void audioHandler::incomingAudio(audioPacket inPacket)
qint16* out = (qint16*)outPacket.data();
for (int f = 0; f < livePacket.data.length() / 2; f++)
{
tempAmplitude = qMax(tempAmplitude, (int)(abs(*in) / 256));
*out++ = (qint16)*in * this->volume;
*out++ = (qint16)*in++ * this->volume;
}
@ -705,13 +710,14 @@ void audioHandler::incomingAudio(audioPacket inPacket)
qint16* in = (qint16*)livePacket.data.data();
for (int f = 0; f < livePacket.data.length() / 2; f++)
{
*in = *in * this->volume;
tempAmplitude = qMax(tempAmplitude, (int)(abs(*in) / 256));
*in = *in * this->volume;
in++;
}
}
}
amplitude = tempAmplitude;
/* We now have an array of 16bit samples in the NATIVE samplerate of the radio
If the radio sample rate is below 48000, we need to resample.
*/
@ -810,6 +816,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
//qDebug(logAudio()) << "Now resampled, length" << packet.data.length();
int tempAmplitude = 0;
// Do we need to convert mono to stereo?
if (setup.radioChan == 1 && devChannels > 1)
{
@ -819,6 +826,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
qint16* out = (qint16*)outPacket.data();
for (int f = 0; f < outPacket.length()/2; f++)
{
tempAmplitude = qMax(tempAmplitude, (int)(abs(*in) / 256));
*out++ = *in++;
in++; // Skip each even channel.
}
@ -852,6 +860,7 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
}
else if (setup.bits == 8)
{
// Do we need to convert 16-bit to 8-bit?
QByteArray outPacket((int)packet.data.length() / 2, (char)0xff);
qint16* in = (qint16*)packet.data.data();
@ -874,10 +883,12 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
int compressedByte = (((sample + 32768) >> 8) & 0xff);
outPacket[f] = (quint8)compressedByte;
}
tempAmplitude = qMax(tempAmplitude, abs(outPacket[f]));
}
packet.data.clear();
packet.data = outPacket; // Copy output packet back to input buffer.
}
amplitude = tempAmplitude;
ret = packet.data;
//qDebug(logAudio()) << "Now radio format, length" << packet.data.length();
@ -890,7 +901,6 @@ void audioHandler::getNextAudioChunk(QByteArray& ret)
}
return;
}
@ -973,4 +983,8 @@ void audioHandler::stop()
#endif
quint16 audioHandler::getAmplitude()
{
return amplitude;
}

Wyświetl plik

@ -107,6 +107,7 @@ public:
#endif
void getNextAudioChunk(QByteArray &data);
quint16 getAmplitude();
public slots:
bool init(audioSetup setup);
@ -206,6 +207,7 @@ private:
volatile bool ready = false;
audioPacket tempBuf;
quint16 currentLatency;
quint16 amplitude = 0;
qreal volume=1.0;
int devChannels;
audioSetup setup;

Wyświetl plik

@ -5,6 +5,15 @@
#pragma pack(push, 1)
#ifndef Q_OS_WIN
typedef struct _GUID {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;
#endif
// Various settings used by both client and server
#define PURGE_SECONDS 10
#define TOKEN_RENEWAL 60000

Wyświetl plik

@ -131,7 +131,7 @@ void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, aud
// Connect for errors/alerts
connect(udp, SIGNAL(haveNetworkError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString)));
connect(udp, SIGNAL(haveNetworkStatus(QString)), this, SLOT(handleStatusUpdate(QString)));
connect(udp, SIGNAL(haveNetworkStatus(networkStatus)), this, SLOT(handleStatusUpdate(networkStatus)));
connect(ptty, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString)));
connect(this, SIGNAL(getMoreDebug()), ptty, SLOT(debugThis()));
@ -206,9 +206,9 @@ void rigCommander::handleSerialPortError(const QString port, const QString error
emit haveSerialPortError(port, errorText);
}
void rigCommander::handleStatusUpdate(const QString text)
void rigCommander::handleStatusUpdate(const networkStatus status)
{
emit haveStatusUpdate(text);
emit haveStatusUpdate(status);
}
bool rigCommander::usingLAN()
@ -4278,10 +4278,6 @@ void rigCommander::sendState()
void rigCommander::radioSelection(QList<radio_cap_packet> radios)
{
for (const radio_cap_packet radio : radios)
{
qInfo(logSystem()) << "Radio Name" << radio.name;
}
emit requestRadioSelection(radios);
}

Wyświetl plik

@ -272,7 +272,7 @@ public slots:
void sayAll();
// Housekeeping:
void handleStatusUpdate(const QString text);
void handleStatusUpdate(const networkStatus status);
void radioSelection(QList<radio_cap_packet> radios);
void radioUsage(int radio, bool busy, QString name, QString ip);
void setCurrentRadio(int radio);
@ -283,7 +283,7 @@ signals:
// Communication:
void commReady();
void haveSerialPortError(const QString port, const QString errorText);
void haveStatusUpdate(const QString text);
void haveStatusUpdate(const networkStatus status);
void dataForComm(const QByteArray &outData);
void toggleRTS(bool rtsOn);

Wyświetl plik

@ -51,3 +51,11 @@ void selectRadio::on_table_cellClicked(int row, int col) {
void selectRadio::on_cancelButton_clicked() {
this->setVisible(false);
}
void selectRadio::audioOutputLevel(quint16 level) {
ui->afLevel->setValue(level);
}
void selectRadio::audioInputLevel(quint16 level) {
ui->modLevel->setValue(level);
}

Wyświetl plik

@ -19,6 +19,8 @@ public:
explicit selectRadio(QWidget* parent = 0);
~selectRadio();
void populate(QList<radio_cap_packet> radios);
void audioOutputLevel(quint16 level);
void audioInputLevel(quint16 level);
public slots:
void on_table_cellClicked(int row, int col);

Wyświetl plik

@ -78,6 +78,76 @@
</column>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>AF</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="afLevel">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>MOD</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="modLevel">
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>

Wyświetl plik

@ -170,20 +170,21 @@ void udpHandler::dataReceived()
if (in->type == 0x07 && in->reply == 0x01 && streamOpened)
{
// This is a response to our ping request so measure latency
latency += lastPingSentTime.msecsTo(QDateTime::currentDateTime());
latency /= 2;
quint32 totalsent = packetsSent;
quint32 totallost = packetsLost;
status.networkLatency += lastPingSentTime.msecsTo(QDateTime::currentDateTime());
status.networkLatency /= 2;
status.packetsSent = packetsSent;
status.packetsLost = packetsLost;
if (audio != Q_NULLPTR) {
totalsent = totalsent + audio->packetsSent;
totallost = totallost + audio->packetsLost;
status.packetsSent = status.packetsSent + audio->packetsSent;
status.packetsLost = status.packetsLost + audio->packetsLost;
}
if (civ != Q_NULLPTR) {
totalsent = totalsent + civ->packetsSent;
totallost = totallost + civ->packetsLost;
status.packetsSent = status.packetsSent + civ->packetsSent;
status.packetsLost = status.packetsLost + civ->packetsLost;
}
QString tempLatency;
status.rxLatency = audio->audioLatency;
if (rxSetup.latency > audio->audioLatency)
{
tempLatency = QString("%1 ms").arg(audio->audioLatency,3);
@ -195,7 +196,14 @@ void udpHandler::dataReceived()
if (txSetup.codec == 0) {
txString = "(no tx)";
}
emit haveNetworkStatus(QString("<pre>%1 rx latency: %2 / rtt: %3 ms / loss: %4/%5</pre>").arg(txString).arg(tempLatency).arg(latency, 3).arg(totallost, 3).arg(totalsent, 3));
status.message = QString("<pre>%1 rx latency: %2 / rtt: %3 ms / loss: %4/%5</pre>").arg(txString).arg(tempLatency).arg(latency, 3).arg(status.packetsLost, 3).arg(status.packetsSent, 3);
if (audio != Q_NULLPTR) {
status.rxAudioLevel = audio->getRxAmplitude();
status.txAudioLevel = audio->getTxAmplitude();
}
emit haveNetworkStatus(status);
}
break;
}
@ -295,7 +303,7 @@ void udpHandler::dataReceived()
if (in->error == 0xfeffffff)
{
emit haveNetworkStatus("Invalid Username/Password");
status.message = "Invalid Username/Password";
qInfo(logUdp()) << this->metaObject()->className() << ": Invalid Username/Password";
}
else if (!isAuthenticated)
@ -303,7 +311,7 @@ void udpHandler::dataReceived()
if (in->tokrequest == tokRequest)
{
emit haveNetworkStatus("Radio Login OK!");
status.message="Radio Login OK!";
qInfo(logUdp()) << this->metaObject()->className() << ": Received matching token response to our request";
token = in->token;
sendToken(0x02);
@ -346,32 +354,49 @@ void udpHandler::dataReceived()
}
if (in->type != 0x01 && !streamOpened) {
if (!streamOpened && in->busy && numRadios == 1 )
if (in->busy && numRadios == 1)
{
if (in->ipaddress != 0x00 && strcmp(in->computer, compName.toLocal8Bit()))
{
emit haveNetworkStatus(devName + " in use by: " + in->computer + " (" + ip.toString() + ")");
status.message = devName + " in use by: " + in->computer + " (" + ip.toString() + ")";
sendControl(false, 0x00, in->seq); // Respond with an idle
}
else {
setCurrentRadio(0);
}
}
else if (!streamOpened && !in->busy)
else if (!in->busy && numRadios == 1)
{
emit haveNetworkStatus(devName + " available");
status.message = devName + " available";
memcpy(macaddress, in->macaddress, 6);
sendRequestStream();
}
else if (streamOpened)
/* If another client connects/disconnects from the server, the server will emit
a CONNINFO packet, send our details to confirm we still want the stream */
{
// Received while stream is open.
sendRequestStream();
if (civPort == 0) {
qInfo(logUdp()) << this->metaObject()->className() << "civPort not yet configured!";
}
if (radios[0].commoncap == 0x8010) {
memcpy(macaddress, radios[0].macaddress, 6);
useGuid = false;
}
else {
useGuid = true;
guid = radios[0].guid;
}
devName = radios[0].name;
audioType = radios[0].audio;
civId = radios[0].civ;
rxSampleRates = radios[0].rxsample;
txSampleRates = radios[0].txsample;
sendRequestStream(); // Send initial stream request.
}
}
else if (streamOpened)
/* If another client connects/disconnects from the server, the server will emit
a CONNINFO packet, send our details to confirm we still want the stream */
{
// Received while stream is open.
sendRequestStream();
}
break;
}
@ -393,7 +418,7 @@ void udpHandler::dataReceived()
memcpy(&rad, tmpRad+f, RADIO_CAP_SIZE);
radios.append(rad);
}
for(const radio_cap_packet radio : radios)
for(const radio_cap_packet &radio : radios)
{
qInfo(logUdp()) << this->metaObject()->className() << "Received radio capabilities, Name:" <<
radio.name << " Audio:" <<
@ -417,32 +442,32 @@ void udpHandler::dataReceived()
udpBase::dataReceived(r); // Call parent function to process the rest.
r.clear();
datagram.clear();
}
return;
}
void udpHandler::setCurrentRadio(int radio) {
qInfo(logUdp()) << "Got Radio" << radio;
int baudrate = qFromBigEndian(radios[radio].baudrate);
emit haveBaudRate(baudrate);
if (radios[radio].commoncap == 0x8010) {
memcpy(macaddress, radios[radio].macaddress, 6);
useGuid = false;
}
else {
useGuid = true;
guid = radios[radio].guid;
}
devName =radios[radio].name;
audioType = radios[radio].audio;
civId = radios[radio].civ;
rxSampleRates = radios[radio].rxsample;
txSampleRates = radios[radio].txsample;
if (!streamOpened) {
qInfo(logUdp()) << "Got Radio" << radio;
int baudrate = qFromBigEndian(radios[radio].baudrate);
emit haveBaudRate(baudrate);
if (radios[radio].commoncap == 0x8010) {
memcpy(macaddress, radios[radio].macaddress, 6);
useGuid = false;
}
else {
useGuid = true;
guid = radios[radio].guid;
}
devName =radios[radio].name;
audioType = radios[radio].audio;
civId = radios[radio].civ;
rxSampleRates = radios[radio].rxsample;
txSampleRates = radios[radio].txsample;
civ = new udpCivData(localIP, radioIP, civPort);
@ -451,21 +476,17 @@ void udpHandler::setCurrentRadio(int radio) {
txSetup.samplerate = 0;
txSetup.codec = 0;
}
audio = new udpAudio(localIP, radioIP, audioPort, rxSetup, txSetup);
QObject::connect(civ, SIGNAL(receive(QByteArray)), this, SLOT(receiveFromCivStream(QByteArray)));
QObject::connect(audio, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket)));
QObject::connect(this, SIGNAL(haveChangeLatency(quint16)), audio, SLOT(changeLatency(quint16)));
QObject::connect(this, SIGNAL(haveSetVolume(unsigned char)), audio, SLOT(setVolume(unsigned char)));
streamOpened = true;
emit haveNetworkStatus(devName);
qInfo(logUdp()) << this->metaObject()->className() << "Got serial and audio request success, device name: " << devName;
sendRequestStream();
}
qInfo(logUdp()) << this->metaObject()->className() << "Got serial and audio request success, device name: " << devName;
sendRequestStream();
}
@ -515,7 +536,7 @@ void udpHandler::sendAreYouThere()
if (areYouThereCounter == 20)
{
qInfo(logUdp()) << this->metaObject()->className() << ": Radio not responding.";
emit haveNetworkStatus("Radio not responding!");
status.message = "Radio not responding!";
}
qInfo(logUdp()) << this->metaObject()->className() << ": Sending Are You There...";
@ -961,6 +982,24 @@ void udpAudio::setVolume(unsigned char value)
emit haveSetVolume(value);
}
quint16 udpAudio::getRxAmplitude() {
if (rxaudio != Q_NULLPTR) {
return rxaudio->getAmplitude();
}
else {
return 0;
}
}
quint16 udpAudio::getTxAmplitude() {
if (txaudio != Q_NULLPTR) {
return txaudio->getAmplitude();
}
else {
return 0;
}
}
void udpAudio::dataReceived()
{
while (udp->hasPendingDatagrams()) {

Wyświetl plik

@ -35,6 +35,20 @@ struct udpPreferences {
QString clientName;
};
struct networkStatus {
quint8 rxAudioBufferPercent;
quint8 txAudioBufferPercent;
quint8 rxAudioLevel;
quint8 txAudioLevel;
quint16 rxLatency;
quint16 txLatency;
quint32 packetsSent;
quint32 packetsLost;
quint16 rtt;
quint32 networkLatency;
QString message;
};
void passcode(QString in, QByteArray& out);
QByteArray parseNullTerminatedString(QByteArray c, int s);
@ -158,6 +172,8 @@ public:
~udpAudio();
int audioLatency = 0;
quint16 getRxAmplitude();
quint16 getTxAmplitude();
signals:
void haveAudioData(audioPacket data);
@ -228,7 +244,7 @@ signals:
void haveNetworkError(QString, QString);
void haveChangeLatency(quint16 value);
void haveSetVolume(unsigned char value);
void haveNetworkStatus(QString);
void haveNetworkStatus(networkStatus);
void haveBaudRate(quint32 baudrate);
void requestRadioSelection(QList<radio_cap_packet> radios);
void setRadioUsage(int, bool busy, QString name, QString mac);
@ -279,6 +295,7 @@ private:
quint8 civId = 0;
quint16 rxSampleRates = 0;
quint16 txSampleRates = 0;
networkStatus status;
};

Wyświetl plik

@ -105,7 +105,7 @@ udpServer::~udpServer()
delete udpAudio;
}
emit haveNetworkStatus(QString(""));
//emit haveNetworkStatus(QString(""));
}
@ -1329,7 +1329,7 @@ void udpServer::watchdog()
}
}
emit haveNetworkStatus(QString("<pre>Server connections: Control:%1 CI-V:%2 Audio:%3</pre>").arg(controlClients.size()).arg(civClients.size()).arg(audioClients.size()));
//emit haveNetworkStatus(QString("<pre>Server connections: Control:%1 CI-V:%2 Audio:%3</pre>").arg(controlClients.size()).arg(civClients.size()).arg(audioClients.size()));
}
void udpServer::sendStatus(CLIENT* c)

Wyświetl plik

@ -21,6 +21,7 @@
#include "packettypes.h"
#include "rigidentities.h"
#include "udphandler.h"
#include "audiohandler.h"
extern void passcode(QString in,QByteArray& out);
@ -72,7 +73,7 @@ public slots:
signals:
void haveDataFromServer(QByteArray);
void haveAudioData(audioPacket data);
void haveNetworkStatus(QString);
void haveNetworkStatus(networkStatus);
void setupTxAudio(audioSetup);
void setupRxAudio(audioSetup);

Wyświetl plik

@ -46,6 +46,7 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s
qRegisterMetaType <datekind>();
qRegisterMetaType<rigstate*>();
qRegisterMetaType<QList<radio_cap_packet>>();
qRegisterMetaType<networkStatus>();
haveRigCaps = false;
@ -420,7 +421,7 @@ void wfmain::makeRig()
// Rig status and Errors:
connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString)));
connect(rig, SIGNAL(haveStatusUpdate(QString)), this, SLOT(receiveStatusUpdate(QString)));
connect(rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus)));
connect(rig, SIGNAL(requestRadioSelection(QList<radio_cap_packet>)), this, SLOT(radioSelection(QList<radio_cap_packet>)));
connect(rig, SIGNAL(setRadioUsage(int, bool, QString, QString)), selRad, SLOT(setInUse(int, bool, QString, QString)));
connect(selRad, SIGNAL(selectedRadio(int)), rig, SLOT(setCurrentRadio(int)));
@ -579,9 +580,13 @@ void wfmain::receiveSerialPortError(QString port, QString errorText)
// TODO: Dialog box, exit, etc
}
void wfmain::receiveStatusUpdate(QString text)
void wfmain::receiveStatusUpdate(networkStatus status)
{
this->rigStatus->setText(text);
this->rigStatus->setText(status.message);
selRad->audioOutputLevel(status.rxAudioLevel);
selRad->audioInputLevel(status.txAudioLevel);
//qInfo(logSystem()) << "Got Status Update" << status.rxAudioLevel;
}
void wfmain::setupPlots()
@ -985,7 +990,7 @@ void wfmain::setServerToPrefs()
}
if (!prefs.enableLAN) {
connect(udp, SIGNAL(haveNetworkStatus(QString)), this, SLOT(receiveStatusUpdate(QString)));
connect(udp, SIGNAL(haveNetworkStatus(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus)));
}
serverThread->start();

Wyświetl plik

@ -263,7 +263,7 @@ private slots:
void receiveRigID(rigCapabilities rigCaps);
void receiveFoundRigID(rigCapabilities rigCaps);
void receiveSerialPortError(QString port, QString errorText);
void receiveStatusUpdate(QString errorText);
void receiveStatusUpdate(networkStatus status);
void handlePlotClick(QMouseEvent *);
void handlePlotDoubleClick(QMouseEvent *);
void handleWFClick(QMouseEvent *);
@ -895,6 +895,7 @@ Q_DECLARE_METATYPE(enum meterKind)
Q_DECLARE_METATYPE(enum spectrumMode)
Q_DECLARE_METATYPE(rigstate*)
Q_DECLARE_METATYPE(QList<radio_cap_packet>)
Q_DECLARE_METATYPE(struct networkStatus)
#endif // WFMAIN_H

Wyświetl plik

@ -7,9 +7,9 @@
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(QTDIR)\bin%3bC:\QT\5.15.2\MSVC2019\bin%3b$(PATH)</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<QtLastBackgroundBuild>2022-01-21T23:07:22.7167866Z</QtLastBackgroundBuild>
<QtLastBackgroundBuild>2022-01-22T12:48:05.0658578Z</QtLastBackgroundBuild>
</PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<QtLastBackgroundBuild>2022-01-21T23:07:24.1030588Z</QtLastBackgroundBuild>
<QtLastBackgroundBuild>2022-01-22T12:48:06.5160626Z</QtLastBackgroundBuild>
</PropertyGroup>
</Project>