#include "tciaudiohandler.h" #include "logcategories.h" #include "tciserver.h" tciAudioHandler::tciAudioHandler(QObject* parent) { Q_UNUSED(parent) } tciAudioHandler::~tciAudioHandler() { if (converterThread != Q_NULLPTR) { converterThread->quit(); converterThread->wait(); } } bool tciAudioHandler::init(audioSetup setup) { if (isInitialized) { return false; } this->setup = setup; qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "TCI Audio handler starting:" << setup.name; radioFormat = toQAudioFormat(setup.codec, setup.sampleRate); qDebug(logAudio()) << "Creating" << (setup.isinput ? "Input" : "Output") << "audio device:" << setup.name << #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) ", bits" << radioFormat.sampleSize() << #else ", format" << radioFormat.sampleFormat() << #endif ", codec" << setup.codec << ", latency" << setup.latency << ", localAFGain" << setup.localAFgain << ", radioChan" << radioFormat.channelCount() << ", resampleQuality" << setup.resampleQuality << ", samplerate" << radioFormat.sampleRate() << ", uLaw" << setup.ulaw; codecType codec = LPCM; if (setup.codec == 0x01 || setup.codec == 0x20) codec = PCMU; else if (setup.codec == 0x40 || setup.codec == 0x40) codec = OPUS; if (setup.isinput) nativeFormat.setChannelCount(2); else nativeFormat.setChannelCount(2); nativeFormat.setSampleRate(48000); this->setVolume(setup.localAFgain); #if (QT_VERSION < QT_VERSION_CHECK(6,0,0)) nativeFormat.setSampleType(QAudioFormat::Float); nativeFormat.setSampleSize(32); #else nativeFormat.setSampleFormat(QAudioFormat::Float); #endif converter = new audioConverter(); converterThread = new QThread(this); if (setup.isinput) { converterThread->setObjectName("audioConvIn()"); } else { converterThread->setObjectName("audioConvOut()"); } converter->moveToThread(converterThread); connect(this, SIGNAL(setupConverter(QAudioFormat,codecType,QAudioFormat,codecType,quint8,quint8)), converter, SLOT(init(QAudioFormat,codecType,QAudioFormat,codecType,quint8,quint8))); connect(converterThread, SIGNAL(finished()), converter, SLOT(deleteLater())); connect(this, SIGNAL(sendToConverter(audioPacket)), converter, SLOT(convert(audioPacket))); converterThread->start(QThread::TimeCriticalPriority); if (setup.isinput) { emit setupConverter(nativeFormat, codecType::LPCM, radioFormat, codec, 7, setup.resampleQuality); connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedInput(audioPacket))); if (setup.tci != Q_NULLPTR) { connect((tciServer*)setup.tci, SIGNAL(sendTCIAudio(QByteArray)), this, SLOT(receiveTCIAudio(QByteArray))); //connect(this,SIGNAL(setupTxPacket(int)), (tciServer*)setup.tci, SLOT(setupTxPacket(int))); //emit setupTxPacket((nativeFormat.bytesForDuration(setup.blockSize * 1000)*2)/sizeof(float)); } else { qCritical(logAudio()) << "***** TCI NOT FOUND *****"; } } else { emit setupConverter(radioFormat, codec, nativeFormat, codecType::LPCM, 7, setup.resampleQuality); connect(converter, SIGNAL(converted(audioPacket)), this, SLOT(convertedOutput(audioPacket))); if (setup.tci != Q_NULLPTR) { connect(this,SIGNAL(sendTCIAudio(audioPacket)), (tciServer*)setup.tci, SLOT(receiveTCIAudio(audioPacket))); } else { qCritical(logAudio()) << "***** TCI NOT FOUND *****"; } } return isInitialized; } void tciAudioHandler::setVolume(unsigned char volume) { this->volume = audiopot[volume]; } void tciAudioHandler::incomingAudio(audioPacket packet) { packet.volume = volume; emit sendToConverter(packet); return; } void tciAudioHandler::convertedOutput(audioPacket packet) { arrayBuffer.append(packet.data); amplitude = packet.amplitudePeak; currentLatency = 0; emit haveLevels(getAmplitude(), packet.amplitudeRMS, setup.latency, currentLatency, isUnderrun, isOverrun); if (arrayBuffer.length() >= TCI_AUDIO_LENGTH * sizeof(float)) { packet.data.clear(); packet.data = arrayBuffer.mid(0, TCI_AUDIO_LENGTH * sizeof(float)); arrayBuffer.remove(0, TCI_AUDIO_LENGTH * sizeof(float)); emit sendTCIAudio(packet); } } void tciAudioHandler::convertedInput(audioPacket packet) { if (packet.data.size() > 0) { emit haveAudioData(packet); amplitude = packet.amplitudePeak; currentLatency = 0; emit haveLevels(getAmplitude(), static_cast(packet.amplitudeRMS * 255.0), setup.latency, currentLatency, isUnderrun, isOverrun); } } void tciAudioHandler::getNextAudio() { if (tempBuf.data.length() >= nativeFormat.bytesForDuration(setup.blockSize * 1000)) { audioPacket packet; packet.time = QTime::currentTime(); packet.sent = 0; packet.volume = volume; memcpy(&packet.guid, setup.guid, GUIDLEN); packet.data.clear(); audioMutex.lock(); packet.data = tempBuf.data.mid(0, nativeFormat.bytesForDuration(setup.blockSize * 1000)); tempBuf.data.remove(0, nativeFormat.bytesForDuration(setup.blockSize * 1000)); audioMutex.unlock(); emit sendToConverter(packet); } /* If there is still enough data in the buffer, call myself again in 20ms */ if (tempBuf.data.length() >= nativeFormat.bytesForDuration(setup.blockSize * 1000)) { QTimer::singleShot(setup.blockSize, this, &tciAudioHandler::getNextAudio); } } void tciAudioHandler::receiveTCIAudio(const QByteArray packet) { if (packet.size() > 0) { audioMutex.lock(); tempBuf.data.append(packet); audioMutex.unlock(); } getNextAudio(); } void tciAudioHandler::changeLatency(const quint16 newSize) { qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Changing latency to: " << newSize << " from " << setup.latency; } int tciAudioHandler::getLatency() { return currentLatency; } quint16 tciAudioHandler::getAmplitude() { return static_cast(amplitude * 255.0); }