kopia lustrzana https://gitlab.com/eliggett/wfview
Fix txaudio and move udphandler into its own thread
rodzic
4cb3289602
commit
ba0509ba61
|
@ -131,7 +131,7 @@ bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16
|
|||
isInitialized = setDevice(QAudioDeviceInfo::defaultInputDevice());
|
||||
else
|
||||
isInitialized = setDevice(QAudioDeviceInfo::defaultOutputDevice());
|
||||
|
||||
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
|
@ -172,11 +172,9 @@ bool audioHandler::setDevice(QAudioDeviceInfo deviceInfo)
|
|||
void audioHandler::reinit()
|
||||
{
|
||||
qDebug() << this->metaObject()->className() << ": reinit() running";
|
||||
bool running = false;
|
||||
if (audioOutput && audioOutput->state() != QAudio::StoppedState) {
|
||||
running = true;
|
||||
this->stop();
|
||||
}
|
||||
this->stop();
|
||||
|
||||
// Calculate the minimum required audio buffer
|
||||
// This may need work depending on how it performs on other platforms.
|
||||
|
@ -207,9 +205,7 @@ void audioHandler::reinit()
|
|||
connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
|
||||
}
|
||||
|
||||
if (running) {
|
||||
this->start();
|
||||
}
|
||||
this->start();
|
||||
this->flush();
|
||||
}
|
||||
|
||||
|
@ -224,15 +220,10 @@ void audioHandler::start()
|
|||
|
||||
if (isInput) {
|
||||
this->open(QIODevice::WriteOnly | QIODevice::Unbuffered);
|
||||
}
|
||||
else {
|
||||
this->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
|
||||
}
|
||||
|
||||
if (isInput) {
|
||||
audioInput->start(this);
|
||||
}
|
||||
else {
|
||||
this->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
|
||||
audioOutput->start(this);
|
||||
}
|
||||
}
|
||||
|
@ -319,7 +310,7 @@ qint64 audioHandler::writeData(const char* data, qint64 len)
|
|||
if (buffer.length() > bufferSize * 4)
|
||||
{
|
||||
qWarning() << "writeData() Buffer overflow";
|
||||
buffer.clear(); // Will cause a click!
|
||||
// buffer.clear(); // Will cause a click!
|
||||
}
|
||||
|
||||
if (isUlaw) {
|
||||
|
@ -402,6 +393,11 @@ void audioHandler::getBufferSize()
|
|||
emit sendBufferSize(audioOutput->bufferSize());
|
||||
}
|
||||
|
||||
bool audioHandler::isChunkAvailable()
|
||||
{
|
||||
return chunkAvailable;
|
||||
}
|
||||
|
||||
void audioHandler::getNextAudioChunk(QByteArray& ret)
|
||||
{
|
||||
quint16 numSamples = radioSampleBits * 120;
|
||||
|
|
|
@ -40,10 +40,9 @@ public:
|
|||
qint64 writeData(const char* data, qint64 len);
|
||||
qint64 bytesAvailable() const;
|
||||
bool isSequential() const;
|
||||
volatile bool chunkAvailable;
|
||||
void incomingAudio(const QByteArray& data);
|
||||
void getNextAudioChunk(QByteArray &data);
|
||||
|
||||
bool isChunkAvailable();
|
||||
public slots:
|
||||
bool init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 bufferSize, const bool isulaw, const bool isinput);
|
||||
void changeBufferSize(const quint16 newSize);
|
||||
|
@ -63,13 +62,14 @@ private:
|
|||
|
||||
QMutex mutex;
|
||||
|
||||
bool isInitialized;
|
||||
QAudioOutput* audioOutput;
|
||||
QAudioInput* audioInput;
|
||||
bool chunkAvailable;
|
||||
bool isInitialized;
|
||||
QAudioOutput* audioOutput;
|
||||
QAudioInput* audioInput;
|
||||
bool isUlaw;
|
||||
int bufferSize;
|
||||
bool isInput; // Used to determine whether input or output audio
|
||||
float volume;
|
||||
float volume;
|
||||
|
||||
QByteArray buffer;
|
||||
QAudioFormat format;
|
||||
|
|
|
@ -253,8 +253,8 @@ typedef union conninfo_packet {
|
|||
quint32 txsample; // 0x78
|
||||
quint32 civport; // 0x7c
|
||||
quint32 audioport; // 0x80
|
||||
char unusedk; // 0x84
|
||||
quint32 txbuffer; // 0x85
|
||||
char unusedk; // 0x84
|
||||
char unusedl[7]; // 0x89
|
||||
};
|
||||
};
|
||||
|
|
|
@ -86,7 +86,22 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString ip, quint16 cport
|
|||
this->password = password;
|
||||
*/
|
||||
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, buffer, rxsample, rxcodec, txsample, txcodec);
|
||||
|
||||
udpHandlerThread = new QThread(this);
|
||||
|
||||
udp->moveToThread(udpHandlerThread);
|
||||
|
||||
connect(this, SIGNAL(initUdpHandler()), udp, SLOT(init()));
|
||||
connect(udpHandlerThread, SIGNAL(finished()), udp, SLOT(deleteLater()));
|
||||
|
||||
|
||||
udpHandlerThread->start();
|
||||
|
||||
emit initUdpHandler();
|
||||
|
||||
|
||||
connect(udp, SIGNAL(haveDataFromPort(QByteArray)), this, SLOT(handleNewData(QByteArray)));
|
||||
|
||||
// data from the program to the comm port:
|
||||
|
@ -113,8 +128,9 @@ void rigCommander::closeComm()
|
|||
}
|
||||
comm = Q_NULLPTR;
|
||||
|
||||
if (udp != Q_NULLPTR) {
|
||||
delete udp;
|
||||
if (udpHandlerThread != Q_NULLPTR) {
|
||||
udpHandlerThread->quit();
|
||||
udpHandlerThread->wait();
|
||||
}
|
||||
udp = Q_NULLPTR;
|
||||
}
|
||||
|
@ -1438,7 +1454,7 @@ void rigCommander::getMeters(bool transmitting)
|
|||
{
|
||||
// Nice function to just grab every meter
|
||||
qDebug() << __func__ << ": grabbing all metering for mode " << (transmitting==true? "transmitting":"receiving") ;
|
||||
|
||||
|
||||
if(transmitting)
|
||||
{
|
||||
getRFPowerMeter();
|
||||
|
@ -1452,6 +1468,7 @@ void rigCommander::getMeters(bool transmitting)
|
|||
|
||||
getVdMeter();
|
||||
getIDMeter();
|
||||
|
||||
}
|
||||
|
||||
void rigCommander::getSMeter()
|
||||
|
|
|
@ -199,7 +199,7 @@ signals:
|
|||
void haveATUStatus(unsigned char status);
|
||||
void haveChangeBufferSize(quint16 value);
|
||||
void haveDataForServer(QByteArray outData);
|
||||
|
||||
void initUdpHandler();
|
||||
|
||||
private:
|
||||
void setup();
|
||||
|
@ -237,6 +237,8 @@ private:
|
|||
|
||||
commHandler * comm=Q_NULLPTR;
|
||||
udpHandler* udp=Q_NULLPTR;
|
||||
QThread* udpHandlerThread = Q_NULLPTR;
|
||||
|
||||
void determineRigCaps();
|
||||
QByteArray payloadIn;
|
||||
QByteArray echoPerfix;
|
||||
|
|
120
udphandler.cpp
120
udphandler.cpp
|
@ -52,6 +52,14 @@ udpHandler::udpHandler(QString ip, quint16 controlPort, quint16 civPort, quint16
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Set my computer name. Should this be configurable?
|
||||
compName = "wfview";
|
||||
|
||||
}
|
||||
|
||||
void udpHandler::init()
|
||||
{
|
||||
udpBase::init(); // Perform UDP socket initialization.
|
||||
|
||||
// Connect socket to my dataReceived function.
|
||||
|
@ -60,17 +68,18 @@ udpHandler::udpHandler(QString ip, quint16 controlPort, quint16 civPort, quint16
|
|||
/*
|
||||
Connect various timers
|
||||
*/
|
||||
connect(&tokenTimer, &QTimer::timeout, this, std::bind(&udpHandler::sendToken, this, 0x05));
|
||||
connect(&areYouThereTimer, &QTimer::timeout, this, QOverload<>::of(&udpHandler::sendAreYouThere));
|
||||
connect(&pingTimer, &QTimer::timeout, this, &udpBase::sendPing);
|
||||
connect(&idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0));
|
||||
tokenTimer = new QTimer();
|
||||
areYouThereTimer = new QTimer();
|
||||
pingTimer = new QTimer();
|
||||
idleTimer = new QTimer();
|
||||
|
||||
connect(tokenTimer, &QTimer::timeout, this, std::bind(&udpHandler::sendToken, this, 0x05));
|
||||
connect(areYouThereTimer, &QTimer::timeout, this, QOverload<>::of(&udpHandler::sendAreYouThere));
|
||||
connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing);
|
||||
connect(idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0));
|
||||
|
||||
// Start sending are you there packets - will be stopped once "I am here" received
|
||||
areYouThereTimer.start(AREYOUTHERE_PERIOD);
|
||||
|
||||
// Set my computer name. Should this be configurable?
|
||||
compName = "wfview";
|
||||
|
||||
areYouThereTimer->start(AREYOUTHERE_PERIOD);
|
||||
}
|
||||
|
||||
udpHandler::~udpHandler()
|
||||
|
@ -120,11 +129,11 @@ void udpHandler::dataReceived()
|
|||
control_packet_t in = (control_packet_t)r.constData();
|
||||
if (in->type == 0x04) {
|
||||
// If timer is active, stop it as they are obviously there!
|
||||
if (areYouThereTimer.isActive()) {
|
||||
areYouThereTimer.stop();
|
||||
if (areYouThereTimer->isActive()) {
|
||||
areYouThereTimer->stop();
|
||||
// send ping packets every second
|
||||
pingTimer.start(PING_PERIOD);
|
||||
idleTimer.start(IDLE_PERIOD);
|
||||
pingTimer->start(PING_PERIOD);
|
||||
idleTimer->start(IDLE_PERIOD);
|
||||
}
|
||||
}
|
||||
// This is "I am ready" in response to "Are you ready" so send login.
|
||||
|
@ -166,7 +175,7 @@ void udpHandler::dataReceived()
|
|||
if (in->response == 0x0000)
|
||||
{
|
||||
qDebug() << this->metaObject()->className() << ": Token renewal successful";
|
||||
tokenTimer.start(TOKEN_RENEWAL);
|
||||
tokenTimer->start(TOKEN_RENEWAL);
|
||||
gotAuthOK = true;
|
||||
if (!streamOpened)
|
||||
{
|
||||
|
@ -178,8 +187,10 @@ void udpHandler::dataReceived()
|
|||
{
|
||||
qWarning() << this->metaObject()->className() << ": Radio rejected token renewal, performing login";
|
||||
remoteId = in->sentid;
|
||||
isAuthenticated = false;
|
||||
sendLogin(); // Try sending login packet (didn't seem to work?)
|
||||
tokRequest = in->tokrequest;
|
||||
token = in->token;
|
||||
// Got new token response
|
||||
sendToken(0x02); // Update it.
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -200,6 +211,17 @@ void udpHandler::dataReceived()
|
|||
{
|
||||
emit haveNetworkError(radioIP.toString(), "Got radio disconnected.");
|
||||
qDebug() << this->metaObject()->className() << ": Got radio disconnected.";
|
||||
if (streamOpened) {
|
||||
// Close stream connections but keep connection open to the radio.
|
||||
if (audio != Q_NULLPTR) {
|
||||
delete audio;
|
||||
}
|
||||
|
||||
if (civ != Q_NULLPTR) {
|
||||
delete civ;
|
||||
}
|
||||
streamOpened = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -220,7 +242,7 @@ void udpHandler::dataReceived()
|
|||
qDebug() << this->metaObject()->className() << ": Received matching token response to our request";
|
||||
token = in->token;
|
||||
sendToken(0x02);
|
||||
tokenTimer.start(TOKEN_RENEWAL); // Start token request timer
|
||||
tokenTimer->start(TOKEN_RENEWAL); // Start token request timer
|
||||
isAuthenticated = true;
|
||||
}
|
||||
else
|
||||
|
@ -402,7 +424,7 @@ void udpHandler::sendToken(uint8_t magic)
|
|||
|
||||
authInnerSendSeq++;
|
||||
sendTrackedPacket(QByteArray::fromRawData((const char *)p.packet, sizeof(p)));
|
||||
tokenTimer.start(100); // Set 100ms timer for retry (this will be cancelled if a response is received)
|
||||
tokenTimer->start(100); // Set 100ms timer for retry (this will be cancelled if a response is received)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -424,13 +446,16 @@ udpCivData::udpCivData(QHostAddress local, QHostAddress ip, quint16 civPort)
|
|||
/*
|
||||
Connect various timers
|
||||
*/
|
||||
connect(&pingTimer, &QTimer::timeout, this, &udpBase::sendPing);
|
||||
connect(&idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0));
|
||||
pingTimer = new QTimer();
|
||||
idleTimer = new QTimer();
|
||||
|
||||
connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing);
|
||||
connect(idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0));
|
||||
|
||||
// send ping packets every 100 ms (maybe change to less frequent?)
|
||||
pingTimer.start(PING_PERIOD);
|
||||
pingTimer->start(PING_PERIOD);
|
||||
// Send idle packets every 100ms, this timer will be reset everytime a non-idle packet is sent.
|
||||
idleTimer.start(IDLE_PERIOD);
|
||||
idleTimer->start(IDLE_PERIOD);
|
||||
}
|
||||
|
||||
udpCivData::~udpCivData() {
|
||||
|
@ -608,23 +633,25 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
|
|||
|
||||
sendControl(false, 0x03, 0x00); // First connect packet
|
||||
|
||||
connect(&pingTimer, &QTimer::timeout, this, &udpBase::sendPing);
|
||||
pingTimer.start(PING_PERIOD); // send ping packets every 100ms
|
||||
txAudioTimer.setTimerType(Qt::PreciseTimer);
|
||||
connect(&txAudioTimer, &QTimer::timeout, this, &udpAudio::sendTxAudio);
|
||||
txAudioTimer.start(TXAUDIO_PERIOD);
|
||||
pingTimer = new QTimer();
|
||||
connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing);
|
||||
pingTimer->start(PING_PERIOD); // send ping packets every 100ms
|
||||
|
||||
emit setupTxAudio(txNumSamples, txChannelCount, txSampleRate, bufferSize, txIsUlawCodec, true);
|
||||
emit setupRxAudio(rxNumSamples, rxChannelCount, rxSampleRate, bufferSize, rxIsUlawCodec, false);
|
||||
|
||||
|
||||
txAudioTimer = new QTimer();
|
||||
txAudioTimer->setTimerType(Qt::PreciseTimer);
|
||||
connect(txAudioTimer, &QTimer::timeout, this, &udpAudio::sendTxAudio);
|
||||
txAudioTimer->start(TXAUDIO_PERIOD);
|
||||
}
|
||||
|
||||
udpAudio::~udpAudio()
|
||||
{
|
||||
if (txAudioTimer.isActive())
|
||||
if (txAudioTimer != Q_NULLPTR)
|
||||
{
|
||||
txAudioTimer.stop();
|
||||
txAudioTimer->stop();
|
||||
delete txAudioTimer;
|
||||
}
|
||||
|
||||
if (rxAudioThread) {
|
||||
|
@ -643,11 +670,12 @@ udpAudio::~udpAudio()
|
|||
void udpAudio::sendTxAudio()
|
||||
{
|
||||
|
||||
if (txaudio->chunkAvailable) {
|
||||
if (txaudio->isChunkAvailable()) {
|
||||
QByteArray audio;
|
||||
txaudio->getNextAudioChunk(audio);
|
||||
int counter = 1;
|
||||
int len = 0;
|
||||
|
||||
while (len < audio.length()) {
|
||||
QByteArray partial = audio.mid(len, 1364);
|
||||
txaudio_packet p;
|
||||
|
@ -655,15 +683,9 @@ void udpAudio::sendTxAudio()
|
|||
p.len = sizeof(p)+partial.length();
|
||||
p.sentid = myId;
|
||||
p.rcvdid = remoteId;
|
||||
if (counter % 2 == 0)
|
||||
{
|
||||
p.ident = 0x0680;
|
||||
}
|
||||
else {
|
||||
p.ident = 0x0681;
|
||||
}
|
||||
p.ident = 0x0080; // TX audio is always this?
|
||||
p.datalen = (quint16)qToBigEndian((quint16)partial.length());
|
||||
p.sendseq = (quint16)qToBigEndian(sendAudioSeq); // THIS IS BIG ENDIAN!
|
||||
p.sendseq = (quint16)qToBigEndian((quint16)sendAudioSeq); // THIS IS BIG ENDIAN!
|
||||
QByteArray tx = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
|
||||
tx.append(partial);
|
||||
len = len + partial.length();
|
||||
|
@ -754,14 +776,19 @@ udpBase::~udpBase()
|
|||
udp->close();
|
||||
delete udp;
|
||||
}
|
||||
if (pingTimer.isActive())
|
||||
if (pingTimer != Q_NULLPTR)
|
||||
{
|
||||
pingTimer.stop();
|
||||
pingTimer->stop();
|
||||
delete pingTimer;
|
||||
}
|
||||
if (idleTimer.isActive())
|
||||
if (idleTimer != Q_NULLPTR)
|
||||
{
|
||||
idleTimer.stop();
|
||||
idleTimer->stop();
|
||||
delete idleTimer;
|
||||
}
|
||||
pingTimer = Q_NULLPTR;
|
||||
idleTimer = Q_NULLPTR;
|
||||
|
||||
}
|
||||
|
||||
// Base class!
|
||||
|
@ -908,9 +935,6 @@ void udpBase::sendControl(bool tracked=true, quint8 type=0, quint16 seq=0)
|
|||
else {
|
||||
sendTrackedPacket(QByteArray::fromRawData((const char*)p.packet, sizeof(p)));
|
||||
}
|
||||
if (idleTimer.isActive()) {
|
||||
idleTimer.start(IDLE_PERIOD); // Reset idle counter if it's running
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -948,8 +972,8 @@ void udpBase::sendTrackedPacket(QByteArray d)
|
|||
|
||||
QMutexLocker locker(&mutex);
|
||||
udp->writeDatagram(d, radioIP, port);
|
||||
if (idleTimer.isActive()) {
|
||||
idleTimer.start(IDLE_PERIOD); // Reset idle counter if it's running
|
||||
if (idleTimer != Q_NULLPTR && idleTimer->isActive()) {
|
||||
idleTimer->start(IDLE_PERIOD); // Reset idle counter if it's running
|
||||
}
|
||||
packetsSent++;
|
||||
return;
|
||||
|
|
17
udphandler.h
17
udphandler.h
|
@ -27,7 +27,7 @@
|
|||
#define TOKEN_RENEWAL 60000
|
||||
#define PING_PERIOD 100
|
||||
#define IDLE_PERIOD 100
|
||||
#define TXAUDIO_PERIOD 10
|
||||
#define TXAUDIO_PERIOD 5
|
||||
#define AREYOUTHERE_PERIOD 500
|
||||
|
||||
|
||||
|
@ -85,9 +85,9 @@ public:
|
|||
void sendTrackedPacket(QByteArray d);
|
||||
void purgeOldEntries();
|
||||
|
||||
QTimer areYouThereTimer; // Send are-you-there packets every second until a response is received.
|
||||
QTimer pingTimer; // Start sending pings immediately.
|
||||
QTimer idleTimer; // Start watchdog once we are connected.
|
||||
QTimer* areYouThereTimer = Q_NULLPTR; // Send are-you-there packets every second until a response is received.
|
||||
QTimer* pingTimer = Q_NULLPTR; // Start sending pings immediately.
|
||||
QTimer* idleTimer = Q_NULLPTR; // Start watchdog once we are connected.
|
||||
|
||||
QDateTime lastPingSentTime;
|
||||
uint16_t pingSendSeq = 0;
|
||||
|
@ -169,7 +169,7 @@ private:
|
|||
audioHandler* txaudio=Q_NULLPTR;
|
||||
QThread* txAudioThread=Q_NULLPTR;
|
||||
|
||||
QTimer txAudioTimer;
|
||||
QTimer* txAudioTimer=Q_NULLPTR;
|
||||
|
||||
};
|
||||
|
||||
|
@ -195,7 +195,7 @@ public slots:
|
|||
void receiveDataFromUserToRig(QByteArray); // This slot will send data on to
|
||||
void receiveFromCivStream(QByteArray);
|
||||
void changeBufferSize(quint16 value);
|
||||
|
||||
void init();
|
||||
|
||||
signals:
|
||||
void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander
|
||||
|
@ -205,7 +205,6 @@ signals:
|
|||
|
||||
private:
|
||||
|
||||
|
||||
void sendAreYouThere();
|
||||
|
||||
void dataReceived();
|
||||
|
@ -244,8 +243,8 @@ private:
|
|||
char identa;
|
||||
quint32 identb;
|
||||
|
||||
QTimer tokenTimer;
|
||||
QTimer areYouThereTimer;
|
||||
QTimer* tokenTimer = Q_NULLPTR;
|
||||
QTimer* areYouThereTimer = Q_NULLPTR;
|
||||
|
||||
bool highBandwidthConnection = false;
|
||||
};
|
||||
|
|
4
wfmain.h
4
wfmain.h
|
@ -580,8 +580,8 @@ private:
|
|||
satelliteSetup *sat;
|
||||
udpServerSetup *srv;
|
||||
|
||||
udpServer *udp = Q_NULLPTR;
|
||||
QThread *serverThread = Q_NULLPTR;
|
||||
udpServer* udp = Q_NULLPTR;
|
||||
QThread* serverThread = Q_NULLPTR;
|
||||
|
||||
void bandStackBtnClick();
|
||||
bool waitingForBandStackRtn;
|
||||
|
|
Ładowanie…
Reference in New Issue