Fix txaudio and move udphandler into its own thread

audioplugins
Phil Taylor 2021-02-21 14:53:42 +00:00
rodzic 4cb3289602
commit ba0509ba61
8 zmienionych plików z 123 dodań i 85 usunięć

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;

Wyświetl plik

@ -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
};
};

Wyświetl plik

@ -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()

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;
};

Wyświetl plik

@ -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;