Create rx audio packets with timestamp

Lots of other changes but if this works OK, I will update tx audio to use the same system.
merge-requests/2/head
Phil Taylor 2021-02-27 00:37:00 +00:00
rodzic 6d8d1df45e
commit 27eb855adb
9 zmienionych plików z 346 dodań i 215 usunięć

Wyświetl plik

@ -735,7 +735,7 @@ audioHandler::audioHandler(QObject* parent) :
audioOutput(Q_NULLPTR), audioOutput(Q_NULLPTR),
audioInput(Q_NULLPTR), audioInput(Q_NULLPTR),
isUlaw(false), isUlaw(false),
bufferSize(0), latency(0),
isInput(0), isInput(0),
volume(1.0f) volume(1.0f)
{ {
@ -752,7 +752,7 @@ audioHandler::~audioHandler()
} }
} }
bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 buffer, const bool ulaw, const bool isinput) bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool ulaw, const bool isinput)
{ {
if (isInitialized) { if (isInitialized) {
return false; return false;
@ -765,8 +765,8 @@ bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16
format.setByteOrder(QAudioFormat::LittleEndian); format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt); format.setSampleType(QAudioFormat::SignedInt);
this->bufferSize = buffer; this->latency = latency;
this->isUlaw = ulaw; this->isUlaw = ulaw;
this->isInput = isinput; this->isInput = isinput;
this->radioSampleBits = bits; this->radioSampleBits = bits;
this->radioSampleRate = samplerate; this->radioSampleRate = samplerate;
@ -831,7 +831,7 @@ void audioHandler::reinit()
if (audioInput != Q_NULLPTR) if (audioInput != Q_NULLPTR)
delete audioInput; delete audioInput;
audioInput = new QAudioInput(deviceInfo, format, this); audioInput = new QAudioInput(deviceInfo, format, this);
//audioInput->setBufferSize(audioBuffer); //audioInput->setLatency(audioBuffer);
//audioInput->setNotifyInterval(20); //audioInput->setNotifyInterval(20);
connect(audioInput, SIGNAL(notify()), SLOT(notified())); connect(audioInput, SIGNAL(notify()), SLOT(notified()));
@ -844,7 +844,7 @@ void audioHandler::reinit()
delete audioOutput; delete audioOutput;
audioOutput = Q_NULLPTR; audioOutput = Q_NULLPTR;
audioOutput = new QAudioOutput(deviceInfo, format, this); audioOutput = new QAudioOutput(deviceInfo, format, this);
//audioOutput->setBufferSize(audioBuffer); //audioOutput->setLatency(audioBuffer);
connect(audioOutput, SIGNAL(notify()), SLOT(notified())); connect(audioOutput, SIGNAL(notify()), SLOT(notified()));
connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
} }
@ -899,8 +899,8 @@ void audioHandler::stop()
// Stop audio output // Stop audio output
audioOutput->stop(); audioOutput->stop();
QByteArray ret; QByteArray ret;
audioBuffer.clear();
buffer.clear(); //buffer.clear();
this->close(); this->close();
} }
@ -915,47 +915,92 @@ void audioHandler::stop()
qint64 audioHandler::readData(char* data, qint64 maxlen) qint64 audioHandler::readData(char* data, qint64 maxlen)
{ {
// Calculate output length, always full samples // Calculate output length, always full samples
int outlen = 0; int sentlen = 0;
if (radioSampleBits == 8)
{ // Get next packet from buffer.
// Input buffer is 8bit and output buffer is 16bit if (!audioBuffer.isEmpty())
outlen = qMin(buffer.length(), (int)maxlen / 2); {
for (int f = 0; f < outlen; f++)
{ // Sort the buffer by seq number.
if (isUlaw) std::sort(audioBuffer.begin(), audioBuffer.end(),
qToLittleEndian<qint16>(ulaw_decode[(quint8)buffer.at(f)], data + (f * 2)); [](const AUDIOPACKET& a, const AUDIOPACKET& b) -> bool
else {
qToLittleEndian<qint16>((qint16)(buffer[f] << 8) - 32640, data + (f * 2)); return a.seq < b.seq;
} });
QMutexLocker locker(&mutex);
buffer.remove(0, outlen); // Output buffer is ALWAYS 16 bit.
outlen = outlen * 2; int divisor = 16 / radioSampleBits;
}
else if (radioSampleBits == 16) { auto packet = audioBuffer.begin();
// Just copy it while (packet != audioBuffer.end() && sentlen<maxlen)
outlen = qMin(buffer.length(), (int)maxlen); {
if (outlen % 2 != 0) { if (packet->time.msecsTo(QTime::currentTime()) > latency) {
outlen += 1; // Not sure if this is necessary as we should always have an even number! qDebug(logAudio()) << "Packet " << hex << packet->seq << "is too late, deleting" << dec << packet->time.msecsTo(QTime::currentTime()) << "ms";
} QMutexLocker locker(&mutex);
memcpy(data, buffer.data(), outlen); packet=audioBuffer.erase(packet); // returns next packet
QMutexLocker locker(&mutex); }
buffer.remove(0, outlen); else
} {
else { // Will this packet fit in the current buffer?
qDebug(logAudio()) << "Sample bits MUST be 8 or 16 - got: " << radioSampleBits; // Should never happen? int send = qMin((int)((maxlen/divisor) - (sentlen/divisor)), packet->data.length() - packet->sent);
}
return outlen; if (divisor == 2)
{
// Input buffer is 8bit and output buffer is 16bit
for (int f = 0; f < send; f++)
{
if (isUlaw)
qToLittleEndian<qint16>(ulaw_decode[(quint8)packet->data[f+packet->sent]], data + (f * 2 + sentlen));
else
qToLittleEndian<qint16>((qint16)(packet->data[f+packet->sent] << 8) - 32640, data + (f * 2 + sentlen));
}
sentlen = sentlen + (send*divisor);
}
else if (divisor == 1)
{
// 16 bit audio so just copy it in place.
//qDebug(logAudio()) << "Adding packet to buffer:" << (*packet).seq << ": " << (*packet).data.length()-(*packet).sent;
memcpy(data+sentlen, packet->data.constData()+packet->sent, send);
sentlen = sentlen + (send*divisor);
}
else
{
//qDebug(logAudio()) << "Invalid number of bits in audio " << radioSampleBits;
break;
}
if (send == packet->data.length())
{
QMutexLocker locker(&mutex);
packet = audioBuffer.erase(packet); // returns next packet
if (maxlen - sentlen == 0)
{
break;
}
}
else if (send == 0)
{
// We have no more space or no packets so just break.
break;
}
else
{
// We ended-up with a partial packet left so add it to the buffer and store where we left off.
packet->sent = send;
break;
}
}
}
}
//qDebug(logAudio()) << "Returning: " << sentlen << " max: " << maxlen;
return sentlen;
} }
qint64 audioHandler::writeData(const char* data, qint64 len) qint64 audioHandler::writeData(const char* data, qint64 len)
{ {
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
if (buffer.length() > bufferSize * 4)
{
qWarning() << "writeData() Buffer overflow";
buffer.clear(); // Will cause a click!
}
if (isUlaw) { if (isUlaw) {
for (int f = 0; f < len / 2; f++) for (int f = 0; f < len / 2; f++)
@ -1000,8 +1045,6 @@ void audioHandler::notified()
} }
void audioHandler::stateChanged(QAudio::State state) void audioHandler::stateChanged(QAudio::State state)
{ {
if (state == QAudio::IdleState && audioOutput->error() == QAudio::UnderrunError) { if (state == QAudio::IdleState && audioOutput->error() == QAudio::UnderrunError) {
@ -1016,12 +1059,11 @@ void audioHandler::stateChanged(QAudio::State state)
void audioHandler::incomingAudio(const QByteArray& data) void audioHandler::incomingAudio(const AUDIOPACKET data)
{ {
//qDebug(logAudio()) << "Got " << data.length() << " samples";
if (audioOutput != Q_NULLPTR && audioOutput->state() != QAudio::StoppedState) { if (audioOutput != Q_NULLPTR && audioOutput->state() != QAudio::StoppedState) {
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
buffer.append(data); audioBuffer.push_back(data);
// Restart playback // Restart playback
if (audioOutput->state() == QAudio::SuspendedState) if (audioOutput->state() == QAudio::SuspendedState)
{ {
@ -1031,15 +1073,15 @@ void audioHandler::incomingAudio(const QByteArray& data)
} }
} }
void audioHandler::changeBufferSize(const quint16 newSize) void audioHandler::changeLatency(const quint16 newSize)
{ {
qDebug(logAudio()) << this->metaObject()->className() << ": Changing buffer size to: " << newSize << " from " << bufferSize; qDebug(logAudio()) << this->metaObject()->className() << ": Changing latency to: " << newSize << " from " << latency;
bufferSize = newSize; latency = newSize;
} }
void audioHandler::getBufferSize() void audioHandler::getLatency()
{ {
emit sendBufferSize(audioOutput->bufferSize()); emit sendLatency(latency);
} }
bool audioHandler::isChunkAvailable() bool audioHandler::isChunkAvailable()

Wyświetl plik

@ -14,20 +14,31 @@
#include <QIODevice> #include <QIODevice>
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include <QTime>
#include <QDebug> #include <QDebug>
//#define BUFFER_SIZE (32*1024) //#define BUFFER_SIZE (32*1024)
struct AUDIOPACKET {
quint16 seq;
QTime time;
quint16 sent;
QByteArray data;
};
class audioHandler : public QIODevice class audioHandler : public QIODevice
{ {
Q_OBJECT Q_OBJECT
public: public:
audioHandler(QObject* parent = 0); audioHandler(QObject* parent = 0);
~audioHandler(); ~audioHandler();
void getBufferSize(); void getLatency();
bool setDevice(QAudioDeviceInfo deviceInfo); bool setDevice(QAudioDeviceInfo deviceInfo);
@ -43,9 +54,9 @@ public:
void getNextAudioChunk(QByteArray &data); void getNextAudioChunk(QByteArray &data);
bool isChunkAvailable(); bool isChunkAvailable();
public slots: public slots:
bool init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 bufferSize, const bool isulaw, const bool isinput); bool init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isulaw, const bool isinput);
void incomingAudio(const QByteArray& data); void incomingAudio(const AUDIOPACKET data);
void changeBufferSize(const quint16 newSize); void changeLatency(const quint16 newSize);
private slots: private slots:
void notified(); void notified();
@ -53,7 +64,7 @@ private slots:
signals: signals:
void audioMessage(QString message); void audioMessage(QString message);
void sendBufferSize(quint16 newSize); void sendLatency(quint16 newSize);
void haveAudioData(const QByteArray& data); void haveAudioData(const QByteArray& data);
@ -67,7 +78,7 @@ private:
QAudioOutput* audioOutput; QAudioOutput* audioOutput;
QAudioInput* audioInput; QAudioInput* audioInput;
bool isUlaw; bool isUlaw;
int bufferSize; quint16 latency;
bool isInput; // Used to determine whether input or output audio bool isInput; // Used to determine whether input or output audio
float volume; float volume;
@ -76,8 +87,7 @@ private:
QAudioDeviceInfo deviceInfo; QAudioDeviceInfo deviceInfo;
quint16 radioSampleRate; quint16 radioSampleRate;
quint8 radioSampleBits; quint8 radioSampleBits;
QVector<AUDIOPACKET> audioBuffer;
}; };
#endif // AUDIOHANDLER_H #endif // AUDIOHANDLER_H

Wyświetl plik

@ -64,7 +64,7 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString rigSerialPort, qu
} }
void rigCommander::commSetup(unsigned char rigCivAddr, QString ip, quint16 cport, quint16 sport, quint16 aport, void rigCommander::commSetup(unsigned char rigCivAddr, QString ip, quint16 cport, quint16 sport, quint16 aport,
QString username, QString password, quint16 buffer, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec) QString username, QString password, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec)
{ {
// construct // construct
// TODO: Bring this parameter and the comm port from the UI. // TODO: Bring this parameter and the comm port from the UI.
@ -88,7 +88,7 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString ip, quint16 cport
*/ */
if (udp == Q_NULLPTR) { if (udp == Q_NULLPTR) {
udp = new udpHandler(ip, cport, sport, aport, username, password, buffer, rxsample, rxcodec, txsample, txcodec); udp = new udpHandler(ip, cport, sport, aport, username, password, rxlatency, txlatency, rxsample, rxcodec, txsample, txcodec);
udpHandlerThread = new QThread(this); udpHandlerThread = new QThread(this);
@ -107,7 +107,7 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString ip, quint16 cport
// data from the program to the comm port: // data from the program to the comm port:
connect(this, SIGNAL(dataForComm(QByteArray)), udp, SLOT(receiveDataFromUserToRig(QByteArray))); connect(this, SIGNAL(dataForComm(QByteArray)), udp, SLOT(receiveDataFromUserToRig(QByteArray)));
connect(this, SIGNAL(haveChangeBufferSize(quint16)), udp, SLOT(changeBufferSize(quint16))); connect(this, SIGNAL(haveChangeLatency(quint16)), udp, SLOT(changeLatency(quint16)));
// Connect for errors/alerts // Connect for errors/alerts
connect(udp, SIGNAL(haveNetworkError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString))); connect(udp, SIGNAL(haveNetworkError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString)));
@ -2480,9 +2480,9 @@ void rigCommander::getRigID()
prepDataAndSend(payload); prepDataAndSend(payload);
} }
void rigCommander::changeBufferSize(const quint16 value) void rigCommander::changeLatency(const quint16 value)
{ {
emit haveChangeBufferSize(value); emit haveChangeLatency(value);
} }
void rigCommander::sayAll() void rigCommander::sayAll()

Wyświetl plik

@ -48,7 +48,7 @@ public slots:
void process(); void process();
void commSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate); void commSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate);
void commSetup(unsigned char rigCivAddr, QString ip, quint16 cport, quint16 sport, quint16 aport, void commSetup(unsigned char rigCivAddr, QString ip, quint16 cport, quint16 sport, quint16 aport,
QString username, QString password, quint16 buffer, quint16 rxsample, quint8 rxcodec,quint16 txsample, quint8 txcodec); QString username, QString password, quint16 rxlatency,quint16 txlatency, quint16 rxsample, quint8 rxcodec,quint16 txsample, quint8 txcodec);
void closeComm(); void closeComm();
void enableSpectOutput(); void enableSpectOutput();
@ -139,7 +139,7 @@ public slots:
void handleNewData(const QByteArray &data); void handleNewData(const QByteArray &data);
void handleSerialPortError(const QString port, const QString errorText); void handleSerialPortError(const QString port, const QString errorText);
void handleStatusUpdate(const QString text); void handleStatusUpdate(const QString text);
void changeBufferSize(const quint16 value); void changeLatency(const quint16 value);
void sayFrequency(); void sayFrequency();
void sayMode(); void sayMode();
void sayAll(); void sayAll();
@ -197,7 +197,7 @@ signals:
void finished(); void finished();
void havePTTStatus(bool pttOn); void havePTTStatus(bool pttOn);
void haveATUStatus(unsigned char status); void haveATUStatus(unsigned char status);
void haveChangeBufferSize(quint16 value); void haveChangeLatency(quint16 value);
void haveDataForServer(QByteArray outData); void haveDataForServer(QByteArray outData);
void initUdpHandler(); void initUdpHandler();

Wyświetl plik

@ -4,7 +4,7 @@
#include "udphandler.h" #include "udphandler.h"
#include "logcategories.h" #include "logcategories.h"
udpHandler::udpHandler(QString ip, quint16 controlPort, quint16 civPort, quint16 audioPort, QString username, QString password, udpHandler::udpHandler(QString ip, quint16 controlPort, quint16 civPort, quint16 audioPort, QString username, QString password,
quint16 buffer, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec) : quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec) :
controlPort(controlPort), controlPort(controlPort),
civPort(civPort), civPort(civPort),
audioPort(audioPort) audioPort(audioPort)
@ -13,13 +13,14 @@ udpHandler::udpHandler(QString ip, quint16 controlPort, quint16 civPort, quint16
this->port = this->controlPort; this->port = this->controlPort;
this->username = username; this->username = username;
this->password = password; this->password = password;
this->rxBufferSize = buffer; this->rxLatency = rxlatency;
this->txLatency = txlatency;
this->rxSampleRate = rxsample; this->rxSampleRate = rxsample;
this->txSampleRate = txsample; this->txSampleRate = txsample;
this->rxCodec = rxcodec; this->rxCodec = rxcodec;
this->txCodec = txcodec; this->txCodec = txcodec;
qDebug(logUdp()) << "Starting udpHandler user:" << username << " buffer:" << buffer << " rx sample rate: " << rxsample << qDebug(logUdp()) << "Starting udpHandler user:" << username << " rx latency:" << rxLatency << " tx latency:" << txLatency << " rx sample rate: " << rxsample <<
" rx codec: " << rxcodec << " tx sample rate: " << txsample << " tx codec: " << txcodec; " rx codec: " << rxcodec << " tx sample rate: " << txsample << " tx codec: " << txcodec;
// Try to set the IP address, if it is a hostname then perform a DNS lookup. // Try to set the IP address, if it is a hostname then perform a DNS lookup.
@ -110,9 +111,9 @@ udpHandler::~udpHandler()
} }
void udpHandler::changeBufferSize(quint16 value) void udpHandler::changeLatency(quint16 value)
{ {
emit haveChangeBufferSize(value); emit haveChangeLatency(value);
} }
void udpHandler::receiveFromCivStream(QByteArray data) void udpHandler::receiveFromCivStream(QByteArray data)
@ -291,10 +292,10 @@ void udpHandler::dataReceived()
} }
else { else {
civ = new udpCivData(localIP, radioIP, civPort); civ = new udpCivData(localIP, radioIP, civPort);
audio = new udpAudio(localIP, radioIP, audioPort, rxBufferSize, rxSampleRate, rxCodec, txSampleRate, txCodec); audio = new udpAudio(localIP, radioIP, audioPort, rxLatency, txLatency, rxSampleRate, rxCodec, txSampleRate, txCodec);
QObject::connect(civ, SIGNAL(receive(QByteArray)), this, SLOT(receiveFromCivStream(QByteArray))); QObject::connect(civ, SIGNAL(receive(QByteArray)), this, SLOT(receiveFromCivStream(QByteArray)));
QObject::connect(this, SIGNAL(haveChangeBufferSize(quint16)), audio, SLOT(changeBufferSize(quint16))); QObject::connect(this, SIGNAL(haveChangeLatency(quint16)), audio, SLOT(changeLatency(quint16)));
streamOpened = true; streamOpened = true;
@ -360,7 +361,6 @@ void udpHandler::sendRequestStream()
QByteArray usernameEncoded; QByteArray usernameEncoded;
passcode(username, usernameEncoded); passcode(username, usernameEncoded);
int txSeqBufLengthMs = 300;
conninfo_packet p; conninfo_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00! memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
@ -385,7 +385,7 @@ void udpHandler::sendRequestStream()
p.txsample = qToBigEndian((quint32)txSampleRate); p.txsample = qToBigEndian((quint32)txSampleRate);
p.civport = qToBigEndian((quint32)civPort); p.civport = qToBigEndian((quint32)civPort);
p.audioport = qToBigEndian((quint32)audioPort); p.audioport = qToBigEndian((quint32)audioPort);
p.txbuffer = qToBigEndian((quint32)txSeqBufLengthMs); p.txbuffer = qToBigEndian((quint32)txLatency);
authInnerSendSeq++; authInnerSendSeq++;
@ -631,13 +631,14 @@ void udpCivData::dataReceived()
// Audio stream // Audio stream
udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint16 buffer, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec) udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec)
{ {
qDebug(logUdp()) << "Starting udpAudio"; qDebug(logUdp()) << "Starting udpAudio";
this->localIP = local; this->localIP = local;
this->port = audioPort; this->port = audioPort;
this->radioIP = ip; this->radioIP = ip;
this->bufferSize = buffer; this->rxLatency = rxlatency;
this->txLatency = txlatency;
this->rxSampleRate = rxsample; this->rxSampleRate = rxsample;
this->txSampleRate = txsample; this->txSampleRate = txsample;
this->rxCodec = rxcodec; this->rxCodec = rxcodec;
@ -674,9 +675,10 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
rxaudio->moveToThread(rxAudioThread); rxaudio->moveToThread(rxAudioThread);
connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool))); connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool)));
connect(this, SIGNAL(haveAudioData(QByteArray)), rxaudio, SLOT(incomingAudio(QByteArray)));
connect(this, SIGNAL(haveChangeBufferSize(quint16)), rxaudio, SLOT(changeBufferSize(quint16))); qRegisterMetaType<AUDIOPACKET>();
connect(this, SIGNAL(haveChangeBufferSize(quint16)), rxaudio, SLOT(changeBufferSize(quint16))); connect(this, SIGNAL(haveAudioData(AUDIOPACKET)), rxaudio, SLOT(incomingAudio(AUDIOPACKET)));
connect(this, SIGNAL(haveChangeLatency(quint16)), rxaudio, SLOT(changeLatency(quint16)));
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater())); connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
if (txCodec == 0x01) if (txCodec == 0x01)
@ -692,7 +694,6 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
txaudio->moveToThread(txAudioThread); txaudio->moveToThread(txAudioThread);
connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool))); connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool)));
//connect(txaudio, SIGNAL(haveAudioData(QByteArray)), this, SLOT(sendTxAudio(QByteArray)));
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater())); connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
rxAudioThread->start(); rxAudioThread->start();
@ -705,8 +706,8 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing); connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing);
pingTimer->start(PING_PERIOD); // send ping packets every 100ms pingTimer->start(PING_PERIOD); // send ping packets every 100ms
emit setupTxAudio(txNumSamples, txChannelCount, txSampleRate, bufferSize, txIsUlawCodec, true); emit setupTxAudio(txNumSamples, txChannelCount, txSampleRate, txLatency, txIsUlawCodec, true);
emit setupRxAudio(rxNumSamples, rxChannelCount, rxSampleRate, bufferSize, rxIsUlawCodec, false); emit setupRxAudio(rxNumSamples, rxChannelCount, rxSampleRate, txLatency, rxIsUlawCodec, false);
watchdogTimer = new QTimer(); watchdogTimer = new QTimer();
connect(watchdogTimer, &QTimer::timeout, this, &udpAudio::watchdog); connect(watchdogTimer, &QTimer::timeout, this, &udpAudio::watchdog);
@ -719,9 +720,6 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
areYouThereTimer = new QTimer(); areYouThereTimer = new QTimer();
connect(areYouThereTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, false, 0x03, 0)); connect(areYouThereTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, false, 0x03, 0));
areYouThereTimer->start(AREYOUTHERE_PERIOD); areYouThereTimer->start(AREYOUTHERE_PERIOD);
} }
udpAudio::~udpAudio() udpAudio::~udpAudio()
@ -793,9 +791,9 @@ void udpAudio::sendTxAudio()
} }
} }
void udpAudio::changeBufferSize(quint16 value) void udpAudio::changeLatency(quint16 value)
{ {
emit haveChangeBufferSize(value); emit haveChangeLatency(value);
} }
@ -836,14 +834,20 @@ void udpAudio::dataReceived()
r.mid(0, 2) == QByteArrayLiteral("\x70\x04")) r.mid(0, 2) == QByteArrayLiteral("\x70\x04"))
{ {
lastReceived = QTime::currentTime(); lastReceived = QTime::currentTime();
emit haveAudioData(r.mid(24)); AUDIOPACKET tempAudio;
tempAudio.seq = in->seq;
tempAudio.time = lastReceived;
tempAudio.sent = 0;
tempAudio.data = r.mid(24);
emit haveAudioData(tempAudio);
//rxaudio->incomingAudio(tempAudio);
//rxaudio->incomingAudio(r.mid(24)); //rxaudio->incomingAudio(r.mid(24));
} }
} }
break; break;
} }
} }
udpBase::dataReceived(r); // Call parent function to process the rest. udpBase::dataReceived(r); // Call parent function to process the rest.
r.clear(); r.clear();
datagram.clear(); datagram.clear();
@ -861,6 +865,11 @@ void udpBase::init()
qDebug(logUdp()) << "UDP Stream bound to local port:" << localPort << " remote port:" << port; qDebug(logUdp()) << "UDP Stream bound to local port:" << localPort << " remote port:" << port;
uint32_t addr = localIP.toIPv4Address(); uint32_t addr = localIP.toIPv4Address();
myId = (addr >> 8 & 0xff) << 24 | (addr & 0xff) << 16 | (localPort & 0xffff); myId = (addr >> 8 & 0xff) << 24 | (addr & 0xff) << 16 | (localPort & 0xffff);
retransmitTimer = new QTimer();
connect(retransmitTimer, &QTimer::timeout, this, &udpBase::sendRetransmitRequest);
retransmitTimer->start(RETRANSMIT_PERIOD);
} }
udpBase::~udpBase() udpBase::~udpBase()
@ -887,10 +896,16 @@ udpBase::~udpBase()
idleTimer->stop(); idleTimer->stop();
delete idleTimer; delete idleTimer;
} }
if (retransmitTimer != Q_NULLPTR)
{
retransmitTimer->stop();
delete retransmitTimer;
}
pingTimer = Q_NULLPTR; pingTimer = Q_NULLPTR;
idleTimer = Q_NULLPTR; idleTimer = Q_NULLPTR;
areYouThereTimer = Q_NULLPTR; areYouThereTimer = Q_NULLPTR;
retransmitTimer = Q_NULLPTR;
} }
@ -1023,13 +1038,13 @@ void udpBase::dataReceived(QByteArray r)
packetsLost++; packetsLost++;
} }
} }
} else }
if (in->len != PING_SIZE && in->type == 0x00 && in->seq != 0x00) else if (in->len != PING_SIZE && in->type == 0x00 && in->seq != 0x00)
{ {
if (rxSeqBuf.isEmpty()) { if (rxSeqBuf.isEmpty()) {
rxSeqBuf.append(in->seq); rxSeqBuf.append(in->seq);
} }
else else
{ {
std::sort(rxSeqBuf.begin(), rxSeqBuf.end()); std::sort(rxSeqBuf.begin(), rxSeqBuf.end());
if (in->seq < rxSeqBuf.front()) if (in->seq < rxSeqBuf.front())
@ -1038,11 +1053,12 @@ void udpBase::dataReceived(QByteArray r)
// Looks like it has rolled over so clear buffer and start again. // Looks like it has rolled over so clear buffer and start again.
rxSeqBuf.clear(); rxSeqBuf.clear();
return;
} }
if (!rxSeqBuf.contains(in->seq)) if (!rxSeqBuf.contains(in->seq))
{ {
// Add incoming packet to the received buffer and if it is in the mising buffer, remove it. // Add incoming packet to the received buffer and if it is in the missing buffer, remove it.
rxSeqBuf.append(in->seq); rxSeqBuf.append(in->seq);
// Check whether this is one of our missing ones! // Check whether this is one of our missing ones!
auto s = std::find_if(rxMissing.begin(), rxMissing.end(), [&cs = in->seq](SEQBUFENTRY& s) { return s.seqNum == cs; }); auto s = std::find_if(rxMissing.begin(), rxMissing.end(), [&cs = in->seq](SEQBUFENTRY& s) { return s.seqNum == cs; });
@ -1051,95 +1067,104 @@ void udpBase::dataReceived(QByteArray r)
qDebug(logUdp()) << this->metaObject()->className() << ": Missing SEQ has been received! " << hex << in->seq; qDebug(logUdp()) << this->metaObject()->className() << ": Missing SEQ has been received! " << hex << in->seq;
s = rxMissing.erase(s); s = rxMissing.erase(s);
} }
std::sort(rxSeqBuf.begin(), rxSeqBuf.end());
}
// Find all gaps in received packets
QByteArray missingSeqs;
auto i = std::adjacent_find(rxSeqBuf.begin(), rxSeqBuf.end(), [](quint16 l, quint16 r) {return l + 1 < r; });
while (i != rxSeqBuf.end())
{
if (i + 1 != rxSeqBuf.end())
{
if (*(i + 1) - *i < 30)
{
for (quint16 j = *i + 1; j < *(i + 1); j++)
{
//qDebug(logUdp()) << this->metaObject()->className() << ": Found missing seq between " << *i << " : " << *(i + 1) << " (" << j << ")";
auto s = std::find_if(rxMissing.begin(), rxMissing.end(), [&cs = j](SEQBUFENTRY& s) { return s.seqNum == cs; });
if (s == rxMissing.end())
{
// We haven't seen this missing packet before
//qDebug(logUdp()) << this->metaObject()->className() << ": Adding to missing buffer (len="<< rxMissing.length() << "): " << j;
SEQBUFENTRY b;
b.seqNum = j;
b.retransmitCount = 0;
b.timeSent = QTime::currentTime();
rxMissing.append(b);
packetsLost++;
}
else {
if (s->retransmitCount == 10)
{
// We have tried 10 times to request this packet, time to give up!
s = rxMissing.erase(s);
rxSeqBuf.append(j); // Final thing is to add to received buffer!
}
}
}
}
else {
qDebug(logUdp()) << this->metaObject()->className() << ": Too many missing, flushing buffers";
rxSeqBuf.clear();
missingSeqs.clear();
break;
}
}
i++;
} }
for (auto it = rxMissing.begin(); it != rxMissing.end(); ++it)
{
if (it->retransmitCount < 10)
{
missingSeqs.append(it->seqNum & 0xff);
missingSeqs.append(it->seqNum >> 8 & 0xff);
missingSeqs.append(it->seqNum & 0xff);
missingSeqs.append(it->seqNum >> 8 & 0xff);
it->retransmitCount++;
}
}
if (missingSeqs.length() != 0)
{
control_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.type = 0x01;
p.seq = 0x0000;
p.sentid = myId;
p.rcvdid = remoteId;
if (missingSeqs.length() == 4) // This is just a single missing packet so send using a control.
{
p.seq = (missingSeqs[0] &0xff) |(quint16)(missingSeqs[1] << 8) ;
qDebug(logUdp()) << this->metaObject()->className() << ": sending request for missing packet : " << hex << p.seq;
QMutexLocker locker(&mutex);
udp->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), radioIP, port);
}
else
{
qDebug(logUdp()) << this->metaObject()->className() << ": sending request for multiple missing packets : " <<missingSeqs.toHex();
missingSeqs.insert(0, p.packet, sizeof(p.packet));
QMutexLocker locker(&mutex);
udp->writeDatagram(missingSeqs, radioIP, port);
}
}
} }
} }
} }
void udpBase::sendRetransmitRequest()
{
// Find all gaps in received packets and then send requests for them.
// This will run every 100ms so out-of-sequence packets will not trigger a retransmit request.
QByteArray missingSeqs;
auto i = std::adjacent_find(rxSeqBuf.begin(), rxSeqBuf.end(), [](quint16 l, quint16 r) {return l + 1 < r; });
while (i != rxSeqBuf.end())
{
if (i + 1 != rxSeqBuf.end())
{
if (*(i + 1) - *i < 30)
{
for (quint16 j = *i + 1; j < *(i + 1); j++)
{
//qDebug(logUdp()) << this->metaObject()->className() << ": Found missing seq between " << *i << " : " << *(i + 1) << " (" << j << ")";
auto s = std::find_if(rxMissing.begin(), rxMissing.end(), [&cs = j](SEQBUFENTRY& s) { return s.seqNum == cs; });
if (s == rxMissing.end())
{
// We haven't seen this missing packet before
//qDebug(logUdp()) << this->metaObject()->className() << ": Adding to missing buffer (len="<< rxMissing.length() << "): " << j;
SEQBUFENTRY b;
b.seqNum = j;
b.retransmitCount = 0;
b.timeSent = QTime::currentTime();
rxMissing.append(b);
packetsLost++;
}
else {
if (s->retransmitCount == 4)
{
// We have tried 4 times to request this packet, time to give up!
s = rxMissing.erase(s);
rxSeqBuf.append(j); // Final thing is to add to received buffer!
}
}
}
}
else {
qDebug(logUdp()) << this->metaObject()->className() << ": Too many missing, flushing buffers";
rxSeqBuf.clear();
missingSeqs.clear();
break;
}
}
i++;
}
for (auto it = rxMissing.begin(); it != rxMissing.end(); ++it)
{
if (it->retransmitCount < 10)
{
missingSeqs.append(it->seqNum & 0xff);
missingSeqs.append(it->seqNum >> 8 & 0xff);
missingSeqs.append(it->seqNum & 0xff);
missingSeqs.append(it->seqNum >> 8 & 0xff);
it->retransmitCount++;
}
}
if (missingSeqs.length() != 0)
{
control_packet p;
memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00!
p.type = 0x01;
p.seq = 0x0000;
p.sentid = myId;
p.rcvdid = remoteId;
if (missingSeqs.length() == 4) // This is just a single missing packet so send using a control.
{
p.seq = (missingSeqs[0] & 0xff) | (quint16)(missingSeqs[1] << 8);
qDebug(logUdp()) << this->metaObject()->className() << ": sending request for missing packet : " << hex << p.seq;
QMutexLocker locker(&mutex);
udp->writeDatagram(QByteArray::fromRawData((const char*)p.packet, sizeof(p)), radioIP, port);
}
else
{
qDebug(logUdp()) << this->metaObject()->className() << ": sending request for multiple missing packets : " << missingSeqs.toHex();
missingSeqs.insert(0, p.packet, sizeof(p.packet));
QMutexLocker locker(&mutex);
udp->writeDatagram(missingSeqs, radioIP, port);
}
}
}
// Used to send idle and other "control" style messages // Used to send idle and other "control" style messages
void udpBase::sendControl(bool tracked=true, quint8 type=0, quint16 seq=0) void udpBase::sendControl(bool tracked=true, quint8 type=0, quint16 seq=0)
{ {

Wyświetl plik

@ -31,7 +31,9 @@
#define TXAUDIO_PERIOD 10 #define TXAUDIO_PERIOD 10
#define AREYOUTHERE_PERIOD 500 #define AREYOUTHERE_PERIOD 500
#define WATCHDOG_PERIOD 500 #define WATCHDOG_PERIOD 500
#define RETRANSMIT_PERIOD 100
Q_DECLARE_METATYPE(AUDIOPACKET)
void passcode(QString in, QByteArray& out); void passcode(QString in, QByteArray& out);
QByteArray parseNullTerminatedString(QByteArray c, int s); QByteArray parseNullTerminatedString(QByteArray c, int s);
@ -40,6 +42,7 @@ QByteArray parseNullTerminatedString(QByteArray c, int s);
class udpBase : public QObject class udpBase : public QObject
{ {
public: public:
~udpBase(); ~udpBase();
@ -98,6 +101,7 @@ public:
QTimer* idleTimer = Q_NULLPTR; // Start watchdog once we are connected. QTimer* idleTimer = Q_NULLPTR; // Start watchdog once we are connected.
QTimer* watchdogTimer = Q_NULLPTR; QTimer* watchdogTimer = Q_NULLPTR;
QTimer* retransmitTimer = Q_NULLPTR;
QDateTime lastPingSentTime; QDateTime lastPingSentTime;
uint16_t pingSendSeq = 0; uint16_t pingSendSeq = 0;
@ -107,6 +111,9 @@ public:
quint32 packetsSent=0; quint32 packetsSent=0;
quint32 packetsLost=0; quint32 packetsLost=0;
private:
void sendRetransmitRequest();
}; };
@ -142,19 +149,19 @@ class udpAudio : public udpBase
Q_OBJECT Q_OBJECT
public: public:
udpAudio(QHostAddress local, QHostAddress ip, quint16 aport, quint16 buffer, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec); udpAudio(QHostAddress local, QHostAddress ip, quint16 aport, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec);
~udpAudio(); ~udpAudio();
signals: signals:
void haveAudioData(QByteArray data); void haveAudioData(AUDIOPACKET data);
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 bufferSize, const bool isUlaw, const bool isInput); void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput);
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 bufferSize, const bool isUlaw, const bool isInput); void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput);
void haveChangeBufferSize(quint16 value); void haveChangeLatency(quint16 value);
public slots: public slots:
void changeBufferSize(quint16 value); void changeLatency(quint16 value);
private: private:
@ -163,7 +170,8 @@ private:
void watchdog(); void watchdog();
QAudioFormat format; QAudioFormat format;
quint16 bufferSize; quint16 rxLatency;
quint16 txLatency;
quint16 rxSampleRate; quint16 rxSampleRate;
quint16 txSampleRate; quint16 txSampleRate;
quint8 rxCodec; quint8 rxCodec;
@ -197,7 +205,7 @@ class udpHandler: public udpBase
public: public:
udpHandler(QString ip, quint16 cport, quint16 sport, quint16 aport, QString username, QString password, udpHandler(QString ip, quint16 cport, quint16 sport, quint16 aport, QString username, QString password,
quint16 buffer, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec); quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec);
~udpHandler(); ~udpHandler();
bool streamOpened = false; bool streamOpened = false;
@ -209,14 +217,14 @@ public:
public slots: public slots:
void receiveDataFromUserToRig(QByteArray); // This slot will send data on to void receiveDataFromUserToRig(QByteArray); // This slot will send data on to
void receiveFromCivStream(QByteArray); void receiveFromCivStream(QByteArray);
void changeBufferSize(quint16 value); void changeLatency(quint16 value);
void init(); void init();
signals: signals:
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
void haveNetworkError(QString, QString); void haveNetworkError(QString, QString);
void haveNetworkStatus(QString); void haveNetworkStatus(QString);
void haveChangeBufferSize(quint16 value); void haveChangeLatency(quint16 value);
private: private:
@ -243,7 +251,8 @@ private:
quint16 rxSampleRate; quint16 rxSampleRate;
quint16 txSampleRate; quint16 txSampleRate;
quint16 rxBufferSize; quint16 rxLatency;
quint16 txLatency;
quint8 rxCodec; quint8 rxCodec;
quint8 txCodec; quint8 txCodec;

Wyświetl plik

@ -533,11 +533,11 @@ void wfmain::openRig()
connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); connect(rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString)));
connect(rig, SIGNAL(haveStatusUpdate(QString)), this, SLOT(receiveStatusUpdate(QString))); connect(rig, SIGNAL(haveStatusUpdate(QString)), this, SLOT(receiveStatusUpdate(QString)));
connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint16, quint16, quint16, QString, QString,quint16,quint16,quint8,quint16,quint8)), rig, SLOT(commSetup(unsigned char, QString, quint16, quint16, quint16, QString, QString,quint16,quint16,quint8,quint16,quint8))); connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint16, quint16, quint16, QString, QString,quint16,quint16,quint16,quint8,quint16,quint8)), rig, SLOT(commSetup(unsigned char, QString, quint16, quint16, quint16, QString, QString,quint16,quint16,quint16,quint8,quint16,quint8)));
connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32)), rig, SLOT(commSetup(unsigned char, QString, quint32))); connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32)), rig, SLOT(commSetup(unsigned char, QString, quint32)));
connect(this, SIGNAL(sendCloseComm()), rig, SLOT(closeComm())); connect(this, SIGNAL(sendCloseComm()), rig, SLOT(closeComm()));
connect(this, SIGNAL(sendChangeBufferSize(quint16)), rig, SLOT(changeBufferSize(quint16))); connect(this, SIGNAL(sendChangeLatency(quint16)), rig, SLOT(changeLatency(quint16)));
connect(this, SIGNAL(getRigCIV()), rig, SLOT(findRigs())); connect(this, SIGNAL(getRigCIV()), rig, SLOT(findRigs()));
connect(rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities))); connect(rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities)));
connect(rig, SIGNAL(commReady()), this, SLOT(receiveCommReady())); connect(rig, SIGNAL(commReady()), this, SLOT(receiveCommReady()));
@ -546,7 +546,7 @@ void wfmain::openRig()
if (prefs.enableLAN) if (prefs.enableLAN)
{ {
emit sendCommSetup(prefs.radioCIVAddr, prefs.ipAddress, prefs.controlLANPort, emit sendCommSetup(prefs.radioCIVAddr, prefs.ipAddress, prefs.controlLANPort,
prefs.serialLANPort, prefs.audioLANPort, prefs.username, prefs.password,prefs.audioRXBufferSize,prefs.audioRXSampleRate,prefs.audioRXCodec,prefs.audioTXSampleRate,prefs.audioTXCodec); prefs.serialLANPort, prefs.audioLANPort, prefs.username, prefs.password,prefs.audioRXLatency,prefs.audioTXLatency,prefs.audioRXSampleRate,prefs.audioRXCodec,prefs.audioTXSampleRate,prefs.audioTXCodec);
} else { } else {
if( (prefs.serialPortRadio == QString("auto")) && (serialPortCL.isEmpty())) if( (prefs.serialPortRadio == QString("auto")) && (serialPortCL.isEmpty()))
@ -699,7 +699,8 @@ void wfmain::setDefPrefs()
defPrefs.password = QString(""); defPrefs.password = QString("");
defPrefs.audioOutput = QAudioDeviceInfo::defaultOutputDevice().deviceName(); defPrefs.audioOutput = QAudioDeviceInfo::defaultOutputDevice().deviceName();
defPrefs.audioInput = QAudioDeviceInfo::defaultInputDevice().deviceName(); defPrefs.audioInput = QAudioDeviceInfo::defaultInputDevice().deviceName();
defPrefs.audioRXBufferSize = 12000; defPrefs.audioRXLatency = 150;
defPrefs.audioTXLatency = 150;
defPrefs.audioRXSampleRate = 48000; defPrefs.audioRXSampleRate = 48000;
defPrefs.audioRXCodec = 4; defPrefs.audioRXCodec = 4;
defPrefs.audioTXSampleRate = 48000; defPrefs.audioTXSampleRate = 48000;
@ -769,10 +770,15 @@ void wfmain::loadSettings()
ui->passwordTxt->setEnabled(ui->lanEnableChk->isChecked()); ui->passwordTxt->setEnabled(ui->lanEnableChk->isChecked());
ui->passwordTxt->setText(QString("%1").arg(prefs.password)); ui->passwordTxt->setText(QString("%1").arg(prefs.password));
prefs.audioRXBufferSize = settings.value("AudioRXBufferSize", defPrefs.audioRXBufferSize).toInt(); prefs.audioRXLatency = settings.value("AudioRXLatency", defPrefs.audioRXLatency).toInt();
ui->audioBufferSizeSlider->setEnabled(ui->lanEnableChk->isChecked()); ui->rxLatencySlider->setEnabled(ui->lanEnableChk->isChecked());
ui->audioBufferSizeSlider->setValue(prefs.audioRXBufferSize); ui->txLatencySlider->setValue(prefs.audioRXLatency);
ui->audioBufferSizeSlider->setTracking(false); // Stop it sending value on every change. ui->rxLatencySlider->setTracking(false); // Stop it sending value on every change.
prefs.audioTXLatency = settings.value("AudioTXLatency", defPrefs.audioTXLatency).toInt();
ui->rxLatencySlider->setEnabled(ui->lanEnableChk->isChecked());
ui->rxLatencySlider->setValue(prefs.audioTXLatency);
ui->rxLatencySlider->setTracking(false); // Stop it sending value on every change.
prefs.audioRXSampleRate = settings.value("AudioRXSampleRate", defPrefs.audioRXSampleRate).toInt(); prefs.audioRXSampleRate = settings.value("AudioRXSampleRate", defPrefs.audioRXSampleRate).toInt();
prefs.audioTXSampleRate = settings.value("AudioTXSampleRate", defPrefs.audioTXSampleRate).toInt(); prefs.audioTXSampleRate = settings.value("AudioTXSampleRate", defPrefs.audioTXSampleRate).toInt();
@ -917,10 +923,10 @@ void wfmain::saveSettings()
settings.setValue("AudioLANPort", prefs.audioLANPort); settings.setValue("AudioLANPort", prefs.audioLANPort);
settings.setValue("Username", prefs.username); settings.setValue("Username", prefs.username);
settings.setValue("Password", prefs.password); settings.setValue("Password", prefs.password);
settings.setValue("AudioRXBufferSize", prefs.audioRXBufferSize); settings.setValue("AudioRXLatency", prefs.audioRXLatency);
settings.setValue("AudioTXLatency", prefs.audioTXLatency);
settings.setValue("AudioRXSampleRate", prefs.audioRXSampleRate); settings.setValue("AudioRXSampleRate", prefs.audioRXSampleRate);
settings.setValue("AudioRXCodec", prefs.audioRXCodec); settings.setValue("AudioRXCodec", prefs.audioRXCodec);
settings.setValue("AudioTXBufferSize", prefs.audioRXBufferSize);
settings.setValue("AudioTXSampleRate", prefs.audioRXSampleRate); settings.setValue("AudioTXSampleRate", prefs.audioRXSampleRate);
settings.setValue("AudioTXCodec", prefs.audioTXCodec); settings.setValue("AudioTXCodec", prefs.audioTXCodec);
settings.setValue("AudioOutput", prefs.audioOutput); settings.setValue("AudioOutput", prefs.audioOutput);
@ -2866,11 +2872,17 @@ void wfmain::on_audioTXCodecCombo_currentIndexChanged(int value)
prefs.audioTXCodec = ui->audioTXCodecCombo->itemData(value).toInt(); prefs.audioTXCodec = ui->audioTXCodecCombo->itemData(value).toInt();
} }
void wfmain::on_audioBufferSizeSlider_valueChanged(int value) void wfmain::on_rxLatencySlider_valueChanged(int value)
{ {
prefs.audioRXBufferSize = value; prefs.audioRXLatency = value;
ui->bufferValue->setText(QString::number(value)); ui->rxLatencyValue->setText(QString::number(value));
emit sendChangeBufferSize(value); emit sendChangeLatency(value);
}
void wfmain::on_txLatencySlider_valueChanged(int value)
{
prefs.audioTXLatency = value;
ui->txLatencyValue->setText(QString::number(value));
} }
void wfmain::on_toFixedBtn_clicked() void wfmain::on_toFixedBtn_clicked()

Wyświetl plik

@ -108,9 +108,9 @@ signals:
void sayAll(); void sayAll();
void sendCommSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate); void sendCommSetup(unsigned char rigCivAddr, QString rigSerialPort, quint32 rigBaudRate);
void sendCommSetup(unsigned char rigCivAddr, QString ip, quint16 cport, quint16 sport, quint16 aport, void sendCommSetup(unsigned char rigCivAddr, QString ip, quint16 cport, quint16 sport, quint16 aport,
QString username, QString password, quint16 buffer, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec); QString username, QString password, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec);
void sendCloseComm(); void sendCloseComm();
void sendChangeBufferSize(quint16 value); void sendChangeLatency(quint16 latency);
void initServer(); void initServer();
void sendServerConfig(SERVERCONFIG conf); void sendServerConfig(SERVERCONFIG conf);
@ -329,7 +329,9 @@ private slots:
void on_connectBtn_clicked(); void on_connectBtn_clicked();
void on_audioBufferSizeSlider_valueChanged(int value); void on_rxLatencySlider_valueChanged(int value);
void on_txLatencySlider_valueChanged(int value);
void on_audioRXCodecCombo_currentIndexChanged(int value); void on_audioRXCodecCombo_currentIndexChanged(int value);
@ -527,7 +529,8 @@ private:
QString password; QString password;
QString audioOutput; QString audioOutput;
QString audioInput; QString audioInput;
quint16 audioRXBufferSize; quint16 audioRXLatency;
quint16 audioTXLatency;
quint16 audioRXSampleRate; quint16 audioRXSampleRate;
quint8 audioRXCodec; quint8 audioRXCodec;
quint16 audioTXSampleRate; quint16 audioTXSampleRate;

Wyświetl plik

@ -18,7 +18,7 @@
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>3</number>
</property> </property>
<widget class="QWidget" name="mainTab"> <widget class="QWidget" name="mainTab">
<attribute name="title"> <attribute name="title">
@ -1765,20 +1765,23 @@
<item> <item>
<widget class="QLabel" name="label_16"> <widget class="QLabel" name="label_16">
<property name="text"> <property name="text">
<string>RX Audio Buffer Size</string> <string>RX Latency (ms)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QSlider" name="audioBufferSizeSlider"> <widget class="QSlider" name="rxLatencySlider">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>0</width> <width>0</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
<property name="minimum">
<number>30</number>
</property>
<property name="maximum"> <property name="maximum">
<number>65536</number> <number>500</number>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -1786,7 +1789,34 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="bufferValue"> <widget class="QLabel" name="rxLatencyValue">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_24">
<property name="text">
<string>TX Latency (ms)</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="txLatencySlider">
<property name="minimum">
<number>30</number>
</property>
<property name="maximum">
<number>500</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="txLatencyValue">
<property name="text"> <property name="text">
<string>0</string> <string>0</string>
</property> </property>
@ -1948,7 +1978,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>810</width> <width>810</width>
<height>22</height> <height>21</height>
</rect> </rect>
</property> </property>
</widget> </widget>