kopia lustrzana https://gitlab.com/eliggett/wfview
Add USB audio handling to UDP server
rodzic
6ac94d0876
commit
8583973ca8
|
@ -979,7 +979,7 @@ qint64 audioHandler::readData(char* data, qint64 maxlen)
|
|||
|
||||
if (timediff > (int)latency * 2) {
|
||||
qDebug(logAudio()) << "Packet " << hex << packet->seq <<
|
||||
" arrived too late (increase rx latency!) " <<
|
||||
" arrived too late (increase output latency!) " <<
|
||||
dec << packet->time.msecsTo(QTime::currentTime()) << "ms";
|
||||
while (packet !=audioBuffer.end() && timediff > (int)latency) {
|
||||
timediff = packet->time.msecsTo(QTime::currentTime());
|
||||
|
@ -1060,7 +1060,7 @@ qint64 audioHandler::writeData(const char* data, qint64 len)
|
|||
{
|
||||
chunkAvailable = true;
|
||||
}
|
||||
else if (audioBuffer.length()==1 && current->sent != chunkSize) {
|
||||
else if (audioBuffer.length()<=1 && current->sent != chunkSize) {
|
||||
chunkAvailable = false;
|
||||
}
|
||||
|
||||
|
@ -1094,7 +1094,7 @@ void audioHandler::stateChanged(QAudio::State state)
|
|||
qDebug(logAudio()) << "Audio now in idle state: " << audioBuffer.length() << " packets in buffer, isInput=" << isInput;
|
||||
if (audioOutput != Q_NULLPTR && audioOutput->error() == QAudio::UnderrunError)
|
||||
{
|
||||
qDebug(logAudio()) << this->metaObject()->className() << "RX:Buffer underrun, isInput=" << isInput;
|
||||
qDebug(logAudio()) << this->metaObject()->className() << "Output buffer underrun, isInput=" << isInput;
|
||||
audioOutput->suspend();
|
||||
}
|
||||
break;
|
||||
|
@ -1187,7 +1187,7 @@ void audioHandler::incomingAudio(audioPacket data)
|
|||
// Restart playback
|
||||
if (audioOutput->state() == QAudio::SuspendedState)
|
||||
{
|
||||
qDebug(logAudio()) << "RX Audio Suspended, Resuming...";
|
||||
qDebug(logAudio()) << "Output Audio Suspended, Resuming...";
|
||||
audioOutput->resume();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,22 +76,15 @@ void commHandler::receiveDataFromUserToRig(const QByteArray &data)
|
|||
|
||||
void commHandler::sendDataOut(const QByteArray &writeData)
|
||||
{
|
||||
|
||||
mutex.lock();
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
|
||||
qint64 bytesWritten;
|
||||
|
||||
bytesWritten = port->write(writeData);
|
||||
qDebug(logSerial()) << "bytesWritten: " << bytesWritten << " length of byte array: " << writeData.length()\
|
||||
<< " size of byte array: " << writeData.size()\
|
||||
<< " Wrote all bytes? " << (bool) (bytesWritten == (qint64)writeData.size());
|
||||
|
||||
#else
|
||||
port->write(writeData);
|
||||
|
||||
#endif
|
||||
if (bytesWritten != writeData.length()) {
|
||||
qDebug(logSerial()) << "bytesWritten: " << bytesWritten << " length of byte array: " << writeData.length()\
|
||||
<< " size of byte array: " << writeData.size()\
|
||||
<< " Wrote all bytes? " << (bool)(bytesWritten == (qint64)writeData.size());
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
|
|
@ -147,17 +147,21 @@ typedef union token_packet {
|
|||
quint16 seq; // 0x06
|
||||
quint32 sentid; // 0x08
|
||||
quint32 rcvdid; // 0x0c
|
||||
char unuseda[3]; // 0x10
|
||||
char unuseda[3]; // 0x10
|
||||
quint16 code; // 0x13
|
||||
quint16 res; // 0x15
|
||||
quint8 innerseq; // 0x17
|
||||
char unusedb; // 0x18
|
||||
char unusedc; // 0x19
|
||||
quint8 innerseq; // 0x17
|
||||
char unusedb; // 0x18
|
||||
char unusedc; // 0x19
|
||||
quint16 tokrequest; // 0x1a
|
||||
quint32 token; // 0x1c
|
||||
char unusedd[16]; // 0x20
|
||||
char unusedd[7]; // 0x20
|
||||
quint16 commoncap; // 0x27
|
||||
char unuseddd[2]; // 0x29
|
||||
char identa; // 0x2b
|
||||
quint32 identb; // 0x2c
|
||||
quint32 response; // 0x30
|
||||
char unusede[12]; // 0x34
|
||||
char unusede[12]; // 0x34
|
||||
};
|
||||
char packet[TOKEN_SIZE];
|
||||
} *token_packet_t;
|
||||
|
|
|
@ -783,7 +783,7 @@ void udpAudio::sendTxAudio()
|
|||
txaudio->getNextAudioChunk(audio);
|
||||
int counter = 1;
|
||||
int len = 0;
|
||||
|
||||
|
||||
while (len < audio.length()) {
|
||||
QByteArray partial = audio.mid(len, 1364);
|
||||
audio_packet p;
|
||||
|
|
16
udphandler.h
16
udphandler.h
|
@ -129,7 +129,7 @@ public:
|
|||
quint32 packetsSent=0;
|
||||
quint32 packetsLost=0;
|
||||
|
||||
quint16 seqPrefix=0;
|
||||
quint16 seqPrefix = 0;
|
||||
|
||||
private:
|
||||
void sendRetransmitRequest();
|
||||
|
@ -173,10 +173,10 @@ public:
|
|||
~udpAudio();
|
||||
|
||||
signals:
|
||||
void haveAudioData(audioPacket data);
|
||||
void haveAudioData(audioPacket data);
|
||||
|
||||
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port,quint8 resampleQuality);
|
||||
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port,quint8 resampleQuality);
|
||||
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
||||
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
||||
|
||||
void haveChangeLatency(quint16 value);
|
||||
|
||||
|
@ -206,11 +206,11 @@ private:
|
|||
bool sentPacketConnect2 = false;
|
||||
uint16_t sendAudioSeq = 0;
|
||||
|
||||
audioHandler* rxaudio=Q_NULLPTR;
|
||||
QThread* rxAudioThread=Q_NULLPTR;
|
||||
audioHandler* rxaudio = Q_NULLPTR;
|
||||
QThread* rxAudioThread = Q_NULLPTR;
|
||||
|
||||
audioHandler* txaudio=Q_NULLPTR;
|
||||
QThread* txAudioThread=Q_NULLPTR;
|
||||
audioHandler* txaudio = Q_NULLPTR;
|
||||
QThread* txAudioThread = Q_NULLPTR;
|
||||
|
||||
QTimer* txAudioTimer=Q_NULLPTR;
|
||||
|
||||
|
|
266
udpserver.cpp
266
udpserver.cpp
|
@ -56,6 +56,7 @@ void udpServer::init()
|
|||
udpAudio = new QUdpSocket(this);
|
||||
udpAudio->bind(config.audioPort);
|
||||
QUdpSocket::connect(udpAudio, &QUdpSocket::readyRead, this, &udpServer::audioReceived);
|
||||
|
||||
}
|
||||
|
||||
udpServer::~udpServer()
|
||||
|
@ -124,7 +125,21 @@ udpServer::~udpServer()
|
|||
audioClients.removeAll(client);
|
||||
}
|
||||
|
||||
if (rxAudioTimer != Q_NULLPTR) {
|
||||
rxAudioTimer->stop();
|
||||
delete rxAudioTimer;
|
||||
rxAudioTimer = Q_NULLPTR;
|
||||
}
|
||||
|
||||
if (rxAudioThread != Q_NULLPTR) {
|
||||
rxAudioThread->quit();
|
||||
rxAudioThread->wait();
|
||||
}
|
||||
|
||||
if (txAudioThread != Q_NULLPTR) {
|
||||
txAudioThread->quit();
|
||||
txAudioThread->wait();
|
||||
}
|
||||
|
||||
if (udpControl != Q_NULLPTR) {
|
||||
udpControl->close();
|
||||
|
@ -138,7 +153,6 @@ udpServer::~udpServer()
|
|||
udpAudio->close();
|
||||
delete udpAudio;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -257,6 +271,8 @@ void udpServer::controlReceived()
|
|||
token_packet_t in = (token_packet_t)r.constData();
|
||||
current->rxSeq = in->seq;
|
||||
current->authInnerSeq = in->innerseq;
|
||||
current->identa = in->identa;
|
||||
current->identb = in->identb;
|
||||
if (in->res == 0x02) {
|
||||
// Request for new token
|
||||
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Received create token request";
|
||||
|
@ -268,6 +284,12 @@ void udpServer::controlReceived()
|
|||
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Received token disconnect request";
|
||||
sendTokenResponse(current, in->res);
|
||||
}
|
||||
else if (in->res == 0x04) {
|
||||
// Disconnect audio/civ
|
||||
sendTokenResponse(current, in->res);
|
||||
current->isStreaming = false;
|
||||
sendConnectionInfo(current);
|
||||
}
|
||||
else {
|
||||
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Received token request";
|
||||
sendTokenResponse(current, in->res);
|
||||
|
@ -321,14 +343,92 @@ void udpServer::controlReceived()
|
|||
current->rxSeq = in->seq;
|
||||
current->rxCodec = in->rxcodec;
|
||||
current->txCodec = in->txcodec;
|
||||
current->rxSampleRate = qFromBigEndian<quint16>(in->rxsample);
|
||||
current->txSampleRate = qFromBigEndian<quint16>(in->txsample);
|
||||
current->txBufferLen = qFromBigEndian<quint16>(in->txbuffer);
|
||||
current->rxSampleRate = qFromBigEndian<quint32>(in->rxsample);
|
||||
current->txSampleRate = qFromBigEndian<quint32>(in->txsample);
|
||||
current->txBufferLen = qFromBigEndian<quint32>(in->txbuffer);
|
||||
current->authInnerSeq = in->innerseq;
|
||||
current->ident = in->identb;
|
||||
current->identa = in->identa;
|
||||
current->identb = in->identb;
|
||||
sendStatus(current);
|
||||
current->authInnerSeq = 0x00;
|
||||
sendConnectionInfo(current);
|
||||
qDebug(logUdpServer()) << "rxCodec:" << current->rxCodec << " txCodec:" << current->txCodec <<
|
||||
" rxSampleRate" << current->rxSampleRate <<
|
||||
" txSampleRate" << current->rxSampleRate <<
|
||||
" txBufferLen" << current->txBufferLen;
|
||||
|
||||
if (!config.lan) {
|
||||
// Radio is connected by USB/Serial and we assume that audio is connected as well.
|
||||
// Create audio TX/RX threads if they don't already exist (first client chooses samplerate/codec)
|
||||
if (txaudio == Q_NULLPTR)
|
||||
{
|
||||
bool uLaw = false;
|
||||
quint8 channels = 1;
|
||||
quint8 samples = 8;
|
||||
txSampleRate = current->txSampleRate;
|
||||
txCodec = current->txCodec;
|
||||
|
||||
if (current->txCodec == 0x01 || current->txCodec == 0x20) {
|
||||
uLaw = true;
|
||||
}
|
||||
if (current->txCodec == 0x08 || current->txCodec == 0x10 || current->txCodec == 0x20) {
|
||||
channels = 2;
|
||||
}
|
||||
if (current->txCodec == 0x04 || current->txCodec == 0x10) {
|
||||
samples = 16;
|
||||
}
|
||||
|
||||
|
||||
txaudio = new audioHandler();
|
||||
txAudioThread = new QThread(this);
|
||||
txaudio->moveToThread(txAudioThread);
|
||||
|
||||
txAudioThread->start();
|
||||
|
||||
connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)));
|
||||
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
|
||||
|
||||
emit setupTxAudio(samples, channels, current->txSampleRate, in->txbuffer, uLaw, false, config.audioOutput, config.resampleQuality);
|
||||
hasTxAudio=datagram.senderAddress();
|
||||
|
||||
connect(this, SIGNAL(haveAudioData(audioPacket)), txaudio, SLOT(incomingAudio(audioPacket)));
|
||||
|
||||
}
|
||||
if (rxaudio == Q_NULLPTR)
|
||||
{
|
||||
bool uLaw = false;
|
||||
quint8 channels = 1;
|
||||
quint8 samples = 8;
|
||||
rxSampleRate = current->rxSampleRate;
|
||||
rxCodec = current->rxCodec;
|
||||
|
||||
if (current->rxCodec == 0x01 || current->rxCodec == 0x20) {
|
||||
uLaw = true;
|
||||
}
|
||||
if (current->rxCodec == 0x08 || current->rxCodec == 0x10 || current->rxCodec == 0x20) {
|
||||
channels = 2;
|
||||
}
|
||||
if (current->rxCodec == 0x04 || current->rxCodec == 0x10) {
|
||||
samples = 16;
|
||||
}
|
||||
|
||||
|
||||
rxaudio = new audioHandler();
|
||||
rxAudioThread = new QThread(this);
|
||||
rxaudio->moveToThread(rxAudioThread);
|
||||
rxAudioThread->start();
|
||||
|
||||
connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)));
|
||||
connect(rxAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
|
||||
|
||||
emit setupRxAudio(samples, channels, current->rxSampleRate, 150, uLaw, true, config.audioInput, config.resampleQuality);
|
||||
|
||||
rxAudioTimer = new QTimer();
|
||||
connect(rxAudioTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRxAudio, this));
|
||||
rxAudioTimer->start(10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -497,7 +597,7 @@ void udpServer::audioReceived()
|
|||
current->retransmitTimer = new QTimer();
|
||||
connect(current->retransmitTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRetransmitRequest, this, current));
|
||||
current->retransmitTimer->start(RETRANSMIT_PERIOD);
|
||||
|
||||
current->seqPrefix = 0;
|
||||
qDebug(logUdpServer()) << "New Audio connection created from :" << current->ipAddress.toString() << ":" << QString::number(current->port);
|
||||
audioClients.append(current);
|
||||
}
|
||||
|
@ -531,11 +631,42 @@ void udpServer::audioReceived()
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Audio packets start as follows:
|
||||
PCM 16bit and PCM8/uLAW stereo: 0x44,0x02 for first packet and 0x6c,0x05 for second.
|
||||
uLAW 8bit/PCM 8bit 0xd8,0x03 for all packets
|
||||
PCM 16bit stereo 0x6c,0x05 first & second 0x70,0x04 third
|
||||
|
||||
|
||||
*/
|
||||
control_packet_t in = (control_packet_t)r.constData();
|
||||
|
||||
if (in->type != 0x01 && in->len >= 0xAC) {
|
||||
if (in->seq == 0)
|
||||
{
|
||||
// Seq number has rolled over.
|
||||
current->seqPrefix++;
|
||||
}
|
||||
|
||||
// 0xac is the smallest possible audio packet.
|
||||
audioPacket tempAudio;
|
||||
tempAudio.seq = (quint32)current->seqPrefix << 16 | in->seq;
|
||||
tempAudio.time = QTime::currentTime();;
|
||||
tempAudio.sent = 0;
|
||||
tempAudio.datain = r.mid(0x18);
|
||||
// Prefer signal/slot to forward audio as it is thread/safe
|
||||
// Need to do more testing but latency appears fine.
|
||||
//if (hasTxAudio == datagram.senderAddress())
|
||||
//{
|
||||
qDebug(logUdpServer()) << "sending tx audio " << in->seq;
|
||||
emit haveAudioData(tempAudio);
|
||||
//}
|
||||
//rxaudio->incomingAudio(tempAudio);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
commonReceived(&audioClients, current, r);
|
||||
|
||||
|
@ -563,13 +694,13 @@ void udpServer::commonReceived(QList<CLIENT*>* l,CLIENT* current, QByteArray r)
|
|||
if (in->type == 0x03) {
|
||||
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Received 'are you there'";
|
||||
current->remoteId = in->sentid;
|
||||
sendControl(current, 0x04, 0x00);
|
||||
sendControl(current, 0x04, in->seq);
|
||||
} // This is This is "Are you ready" in response to "I am here".
|
||||
else if (in->type == 0x06)
|
||||
{
|
||||
qDebug(logUdpServer()) << current->ipAddress.toString() << ": Received 'Are you ready'";
|
||||
current->remoteId = in->sentid;
|
||||
sendControl(current, 0x06, 0x00);
|
||||
sendControl(current, 0x06, in->seq);
|
||||
} // This is a retransmit request
|
||||
else if (in->type == 0x01)
|
||||
{
|
||||
|
@ -801,7 +932,7 @@ void udpServer::sendCapabilities(CLIENT* c)
|
|||
p.seq = c->txSeq;
|
||||
p.sentid = c->myId;
|
||||
p.rcvdid = c->remoteId;
|
||||
p.innerseq = c->authInnerSeq;
|
||||
p.innerseq = c->authInnerSeq;
|
||||
p.tokrequest = c->tokenRx;
|
||||
p.token = c->tokenTx;
|
||||
p.code = 0x0298;
|
||||
|
@ -809,26 +940,23 @@ void udpServer::sendCapabilities(CLIENT* c)
|
|||
p.capa = 0x01;
|
||||
p.commoncap = c->commonCap;
|
||||
|
||||
memcpy(p.macaddress, macAddress.toLocal8Bit(), 6);
|
||||
memcpy(p.macaddress, macAddress.toLocal8Bit(), 6);
|
||||
// IRU seems to expect an "Icom" mac address so replace the first 3 octets of our Mac with one in their range!
|
||||
memcpy(p.macaddress, QByteArrayLiteral("\x00\x90\xc7").constData(), 3);
|
||||
|
||||
|
||||
memcpy(p.name, rigCaps.modelName.toLocal8Bit(), rigname.length());
|
||||
memcpy(p.name, rigCaps.modelName.toLocal8Bit(), rigCaps.modelName.length());
|
||||
memcpy(p.audio, QByteArrayLiteral("ICOM_VAUDIO").constData(), 11);
|
||||
|
||||
if (rigCaps.hasWiFi && !rigCaps.hasEthernet) {
|
||||
p.conntype = 0x0707; // 0x0707 for wifi rig.
|
||||
}
|
||||
else {
|
||||
p.conntype = 0x073f; // 0x0707 for ethernet rig.
|
||||
p.conntype = 0x073f; // 0x073f for ethernet rig.
|
||||
}
|
||||
|
||||
p.civ = rigCaps.civ;
|
||||
p.baudrate = (quint32)qToBigEndian(19200);
|
||||
|
||||
//p.lena = 0x8b01; // rx sample frequencies supported
|
||||
//p.lenb = 0x8b01; // tx sample frequencies supported
|
||||
/*
|
||||
0x80 = 12K only
|
||||
0x40 = 44.1K only
|
||||
|
@ -839,11 +967,52 @@ void udpServer::sendCapabilities(CLIENT* c)
|
|||
0x02 = 16K only
|
||||
0x01 = 8K only
|
||||
*/
|
||||
p.rxsample = 0x0800; // rx sample frequency
|
||||
p.txsample = 0x0800; // tx sample frequency
|
||||
if (rxaudio == Q_NULLPTR) {
|
||||
p.rxsample = 0x8b01; // all rx sample frequencies supported
|
||||
}
|
||||
else {
|
||||
if (rxSampleRate == 48000) {
|
||||
p.rxsample = 0x0800; // fixed rx sample frequency
|
||||
}
|
||||
else if (rxSampleRate == 32000) {
|
||||
p.rxsample = 0x0400;
|
||||
}
|
||||
else if (rxSampleRate == 24000) {
|
||||
p.rxsample = 0x0001;
|
||||
}
|
||||
else if (rxSampleRate == 16000) {
|
||||
p.rxsample = 0x0200;
|
||||
}
|
||||
else if (rxSampleRate == 12000) {
|
||||
p.rxsample = 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
if (txaudio == Q_NULLPTR) {
|
||||
p.txsample = 0x8b01; // all tx sample frequencies supported
|
||||
p.enablea = 0x01; // 0x01 enables TX 24K mode?
|
||||
}
|
||||
else {
|
||||
p.enablea = 0x00; // 0x01 enables TX 24K mode?
|
||||
if (txSampleRate == 48000) {
|
||||
p.txsample = 0x0800; // fixed tx sample frequency
|
||||
}
|
||||
else if (txSampleRate == 32000) {
|
||||
p.txsample = 0x0400;
|
||||
}
|
||||
else if (txSampleRate == 24000) {
|
||||
p.txsample = 0x0000;
|
||||
p.enablea = 0x01;
|
||||
}
|
||||
else if (txSampleRate == 16000) {
|
||||
p.txsample = 0x0200;
|
||||
}
|
||||
else if (txSampleRate == 12000) {
|
||||
p.txsample = 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
// I still don't know what these are?
|
||||
p.enablea = 0x00; // 0x01 enables TX 24K mode?
|
||||
p.enableb = 0x01; // 0x01 doesn't seem to do anything?
|
||||
p.enablec = 0x01; // 0x01 doesn't seem to do anything?
|
||||
p.capf = 0x5001;
|
||||
|
@ -882,20 +1051,21 @@ void udpServer::sendConnectionInfo(CLIENT* c)
|
|||
p.token = c->tokenTx;
|
||||
p.code = 0x0380;
|
||||
p.commoncap = c->commonCap;
|
||||
p.identa = (char)0x90;
|
||||
p.identb = c->ident;
|
||||
p.identa = c->identa;
|
||||
p.identb = c->identb;
|
||||
|
||||
// 0x1a-0x1f is authid (random number?
|
||||
// memcpy(p + 0x40, QByteArrayLiteral("IC-7851").constData(), 7);
|
||||
|
||||
memcpy(p.packet + 0x40, rigname.toLocal8Bit(), rigname.length());
|
||||
memcpy(p.packet + 0x40, rigCaps.modelName.toLocal8Bit(), rigCaps.modelName.length());
|
||||
|
||||
// This is the current streaming client (should we support multiple clients?)
|
||||
if (c->isStreaming) {
|
||||
p.busy = 0x01;
|
||||
memcpy(p.computer, c->clientName.constData(), c->clientName.length());
|
||||
p.ipaddress = qToBigEndian(c->ipAddress.toIPv4Address());
|
||||
p.identb = c->ident;
|
||||
p.identa = c->identa;
|
||||
p.identb = c->identb;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&mutex);
|
||||
|
@ -929,6 +1099,9 @@ void udpServer::sendTokenResponse(CLIENT* c, quint8 type)
|
|||
p.tokrequest = c->tokenRx;
|
||||
p.token = c->tokenTx;
|
||||
p.code = 0x0230;
|
||||
p.identa = c->identa;
|
||||
p.identb = c->identb;
|
||||
p.commoncap = c->commonCap;
|
||||
p.res = type;
|
||||
|
||||
QMutexLocker locker(&mutex);
|
||||
|
@ -996,8 +1169,8 @@ void udpServer::sendStatus(CLIENT* c)
|
|||
p.res = 0x03;
|
||||
p.unknown = 0x1000;
|
||||
p.unusede = (char)0x80;
|
||||
p.identa = (char)0x90;
|
||||
p.identb = c->ident;
|
||||
p.identa = c->identa;
|
||||
p.identb = c->identb;
|
||||
|
||||
p.civport=qToBigEndian(c->civPort);
|
||||
p.audioport=qToBigEndian(c->audioPort);
|
||||
|
@ -1054,6 +1227,24 @@ void udpServer::dataForServer(QByteArray d)
|
|||
return;
|
||||
}
|
||||
|
||||
void udpServer::sendRxAudio()
|
||||
{
|
||||
if (rxaudio && rxaudio->isChunkAvailable()) {
|
||||
QByteArray audio;
|
||||
rxaudio->getNextAudioChunk(audio);
|
||||
int len = 0;
|
||||
|
||||
while (len < audio.length()) {
|
||||
audioPacket partial;
|
||||
partial.datain = audio.mid(len, 1364);
|
||||
receiveAudioData(partial);
|
||||
len = len + partial.datain.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void udpServer::receiveAudioData(const audioPacket &d)
|
||||
{
|
||||
//qDebug(logUdpServer()) << "Server got:" << d.data.length();
|
||||
|
@ -1068,6 +1259,7 @@ void udpServer::receiveAudioData(const audioPacket &d)
|
|||
p.ident = 0x0080; // audio is always this?
|
||||
p.datalen = (quint16)qToBigEndian((quint16)d.datain.length());
|
||||
p.sendseq = (quint16)qToBigEndian((quint16)client->sendAudioSeq); // THIS IS BIG ENDIAN!
|
||||
p.seq = client->txSeq;
|
||||
QByteArray t = QByteArray::fromRawData((const char*)p.packet, sizeof(p));
|
||||
t.append(d.datain);
|
||||
QMutexLocker locker(&mutex);
|
||||
|
@ -1216,4 +1408,28 @@ void udpServer::deleteConnection(QList<CLIENT*> *l, CLIENT* c)
|
|||
delete c; // Is this needed or will the erase have done it?
|
||||
c = Q_NULLPTR;
|
||||
qDebug(logUdpServer()) << "Current Number of clients connected: " << l->length();
|
||||
|
||||
if (l->length() == 0) {
|
||||
|
||||
if (rxAudioTimer != Q_NULLPTR) {
|
||||
rxAudioTimer->stop();
|
||||
delete rxAudioTimer;
|
||||
rxAudioTimer = Q_NULLPTR;
|
||||
}
|
||||
|
||||
if (rxAudioThread != Q_NULLPTR) {
|
||||
rxAudioThread->quit();
|
||||
rxAudioThread->wait();
|
||||
rxaudio = Q_NULLPTR;
|
||||
rxAudioThread = Q_NULLPTR;
|
||||
}
|
||||
|
||||
if (txAudioThread != Q_NULLPTR) {
|
||||
txAudioThread->quit();
|
||||
txAudioThread->wait();
|
||||
txaudio = Q_NULLPTR;
|
||||
txAudioThread = Q_NULLPTR;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
25
udpserver.h
25
udpserver.h
|
@ -49,6 +49,10 @@ public slots:
|
|||
|
||||
signals:
|
||||
void haveDataFromServer(QByteArray);
|
||||
void haveAudioData(audioPacket data);
|
||||
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
||||
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
@ -74,7 +78,8 @@ private:
|
|||
quint16 authSeq;
|
||||
quint16 innerSeq;
|
||||
quint16 sendAudioSeq;
|
||||
quint32 ident;
|
||||
quint8 identa;
|
||||
quint32 identb;
|
||||
quint16 tokenRx;
|
||||
quint32 tokenTx;
|
||||
quint32 commonCap;
|
||||
|
@ -97,7 +102,7 @@ private:
|
|||
QVector <SEQBUFENTRY> txSeqBuf;
|
||||
QVector <quint16> rxSeqBuf;
|
||||
QVector <SEQBUFENTRY> rxMissing;
|
||||
|
||||
quint16 seqPrefix;
|
||||
};
|
||||
|
||||
void controlReceived();
|
||||
|
@ -114,6 +119,7 @@ private:
|
|||
void sendStatus(CLIENT* c);
|
||||
void sendRetransmitRequest(CLIENT* c);
|
||||
void watchdog(CLIENT* c);
|
||||
void sendRxAudio();
|
||||
void deleteConnection(QList<CLIENT*> *l, CLIENT* c);
|
||||
|
||||
SERVERCONFIG config;
|
||||
|
@ -128,7 +134,6 @@ private:
|
|||
quint32 civId = 0;
|
||||
quint32 audioId = 0;
|
||||
|
||||
QString rigname = "IC-9700";
|
||||
quint8 rigciv = 0xa2;
|
||||
|
||||
QMutex mutex; // Used for critical operations.
|
||||
|
@ -138,6 +143,20 @@ private:
|
|||
QList <CLIENT*> audioClients = QList<CLIENT*>();
|
||||
QTime timeStarted;
|
||||
rigCapabilities rigCaps;
|
||||
|
||||
audioHandler* rxaudio = Q_NULLPTR;
|
||||
QThread* rxAudioThread = Q_NULLPTR;
|
||||
|
||||
audioHandler* txaudio = Q_NULLPTR;
|
||||
QThread* txAudioThread = Q_NULLPTR;
|
||||
|
||||
QTimer* rxAudioTimer=Q_NULLPTR;
|
||||
quint16 rxSampleRate = 0;
|
||||
quint16 txSampleRate = 0;
|
||||
quint8 rxCodec = 0;
|
||||
quint8 txCodec = 0;
|
||||
|
||||
QHostAddress hasTxAudio;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -16,9 +16,14 @@ struct SERVERUSER {
|
|||
|
||||
struct SERVERCONFIG {
|
||||
bool enabled;
|
||||
bool lan;
|
||||
quint16 controlPort;
|
||||
quint16 civPort;
|
||||
quint16 audioPort;
|
||||
QString audioOutput;
|
||||
QString audioInput;
|
||||
quint8 resampleQuality;
|
||||
|
||||
QList <SERVERUSER> users;
|
||||
};
|
||||
|
||||
|
|
18
wfmain.cpp
18
wfmain.cpp
|
@ -201,6 +201,12 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, QWidget *parent
|
|||
|
||||
// Start server if enabled in config
|
||||
if (serverConfig.enabled) {
|
||||
serverConfig.lan = prefs.enableLAN;
|
||||
if (!serverConfig.lan) {
|
||||
serverConfig.resampleQuality = udpPrefs.resampleQuality;
|
||||
serverConfig.audioInput = udpPrefs.audioInput;
|
||||
serverConfig.audioOutput = udpPrefs.audioOutput;
|
||||
}
|
||||
udp = new udpServer(serverConfig);
|
||||
|
||||
serverThread = new QThread(this);
|
||||
|
@ -863,7 +869,7 @@ void wfmain::loadSettings()
|
|||
|
||||
udpPrefs.audioOutput = settings.value("AudioOutput", udpDefPrefs.audioOutput).toString();
|
||||
qDebug(logGui()) << "Got Audio Output: " << udpPrefs.audioOutput;
|
||||
ui->audioOutputCombo->setEnabled(ui->lanEnableBtn->isChecked());
|
||||
//ui->audioOutputCombo->setEnabled(ui->lanEnableBtn->isChecked());
|
||||
int audioOutputIndex = ui->audioOutputCombo->findText(udpPrefs.audioOutput);
|
||||
if (audioOutputIndex != -1) {
|
||||
ui->audioOutputCombo->setCurrentIndex(audioOutputIndex);
|
||||
|
@ -871,7 +877,7 @@ void wfmain::loadSettings()
|
|||
|
||||
udpPrefs.audioInput = settings.value("AudioInput", udpDefPrefs.audioInput).toString();
|
||||
qDebug(logGui()) << "Got Audio Input: " << udpPrefs.audioInput;
|
||||
ui->audioInputCombo->setEnabled(ui->lanEnableBtn->isChecked());
|
||||
//ui->audioInputCombo->setEnabled(ui->lanEnableBtn->isChecked());
|
||||
int audioInputIndex = ui->audioInputCombo->findText(udpPrefs.audioInput);
|
||||
if (audioInputIndex != -1) {
|
||||
ui->audioInputCombo->setCurrentIndex(audioInputIndex);
|
||||
|
@ -2918,6 +2924,14 @@ void wfmain::on_serialEnableBtn_clicked(bool checked)
|
|||
ui->controlPortTxt->setEnabled(!checked);
|
||||
ui->usernameTxt->setEnabled(!checked);
|
||||
ui->passwordTxt->setEnabled(!checked);
|
||||
ui->audioRXCodecCombo->setEnabled(!checked);
|
||||
ui->audioTXCodecCombo->setEnabled(!checked);
|
||||
ui->audioSampleRateCombo->setEnabled(!checked);
|
||||
ui->rxLatencySlider->setEnabled(!checked);
|
||||
ui->txLatencySlider->setEnabled(!checked);
|
||||
ui->rxLatencyValue->setEnabled(!checked);
|
||||
ui->txLatencyValue->setEnabled(!checked);
|
||||
|
||||
}
|
||||
|
||||
void wfmain::on_lanEnableBtn_clicked(bool checked)
|
||||
|
|
Ładowanie…
Reference in New Issue