From bb6c615b4ccfc126e26f6de1eac345e3ccc51557 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Mon, 2 May 2022 11:22:05 +0100 Subject: [PATCH] Add some more debugging when audio is delayed --- audiohandler.cpp | 65 +++++++++++++++++++++++++++++++++++++++--------- audiohandler.h | 17 +++++++------ udphandler.cpp | 2 +- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/audiohandler.cpp b/audiohandler.cpp index 2a9e3b8..45cc2d4 100644 --- a/audiohandler.cpp +++ b/audiohandler.cpp @@ -212,9 +212,18 @@ void audioHandler::start() audioTimer->start(setup.blockSize); } else { - // Buffer size must be set before audio is started. - audioOutput->setBufferSize(getAudioSize(setup.latency, format)); + /* OK I don't understand what is happening here? + On Windows, I set the buffer size and when the stream is started, the buffer size is multiplied by 10? + this doesn't happen on Linux/ + We want the buffer sizes to be slightly more than the setup.latency value + */ +#ifdef Q_OS_WIN + audioOutput->setBufferSize(format.bytesForDuration(setup.latency * 100)); +#else + audioOutput->setBufferSize(format.bytesForDuration(setup.latency * 1000)); +#endif audioDevice = audioOutput->start(); + qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "bufferSize needed" << format.bytesForDuration((quint32)setup.latency * 1000) << "got" << audioOutput->bufferSize(); connect(audioOutput, &QAudioOutput::destroyed, audioDevice, &QIODevice::deleteLater, Qt::UniqueConnection); } if (!audioDevice) { @@ -244,6 +253,13 @@ void audioHandler::stop() void audioHandler::setVolume(unsigned char volume) { + /*float volumeLevelLinear = float(0.5); //cut amplitude in half + float volumeLevelDb = float(10 * (qLn(double(volumeLevelLinear)) / qLn(10))); + float volumeLinear = (volume / float(100)); + this->volume = volumeLinear * float(qPow(10, (qreal(volumeLevelDb)) / 20)); + + this->volume = qMin(this->volume, float(1)); + */ this->volume = audiopot[volume]; qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "setVolume: " << volume << "(" << this->volume << ")"; } @@ -251,7 +267,12 @@ void audioHandler::setVolume(unsigned char volume) void audioHandler::incomingAudio(audioPacket inPacket) { - + + + if (lastReceived.msecsTo(QTime::currentTime()) > 30) { + qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize; + } + lastReceived = QTime::currentTime(); audioPacket livePacket = inPacket; // Process uLaw. if (setup.ulaw) @@ -427,7 +448,6 @@ void audioHandler::incomingAudio(audioPacket inPacket) qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "Unsupported Sample Type:" << format.sampleType(); } - currentLatency = livePacket.time.msecsTo(QTime::currentTime()) + getAudioDuration(audioOutput->bufferSize()-audioOutput->bytesFree(),format); if (audioDevice != Q_NULLPTR) { audioDevice->write(livePacket.data); } @@ -437,8 +457,12 @@ void audioHandler::incomingAudio(audioPacket inPacket) incomingAudio(inPacket); // Call myself again to run the packet a second time (FEC) } + currentLatency = livePacket.time.msecsTo(QTime::currentTime()) + (format.durationForBytes(audioOutput->bufferSize() - audioOutput->bytesFree()) / 1000); lastSentSeq = inPacket.seq; } + else { + qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Received audio packet is empty?"; + } emit haveLevels(getAmplitude(), setup.latency, currentLatency,isUnderrun); @@ -454,14 +478,18 @@ void audioHandler::getNextAudioChunk() return; } + audioPacket livePacket; livePacket.time= QTime::currentTime(); livePacket.sent = 0; memcpy(&livePacket.guid, setup.guid, GUIDLEN); while (tempBuf.data.length() > format.bytesForDuration(setup.blockSize * 1000)) { + QTime startProcessing = QTime::currentTime(); livePacket.data.clear(); livePacket.data = tempBuf.data.mid(0, format.bytesForDuration(setup.blockSize * 1000)); tempBuf.data.remove(0, format.bytesForDuration(setup.blockSize * 1000)); + //qDebug(logAudio()) << "Got bytes " << format.bytesForDuration(setup.blockSize * 1000); + if (livePacket.data.length() > 0) { Eigen::VectorXf samplesF; @@ -618,6 +646,11 @@ void audioHandler::getNextAudioChunk() livePacket.data = outPacket; // Copy output packet back to input buffer. } emit haveAudioData(livePacket); + if (lastReceived.msecsTo(QTime::currentTime()) > 30) { + qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Time since last audio packet" << lastReceived.msecsTo(QTime::currentTime()) << "Expected around" << setup.blockSize << "Processing time" <bufferSize(), format) << "ms"; + qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Configured latency: " << setup.latency << "Buffer Duration:" << format.durationForBytes(audioOutput->bufferSize()/1000) << "ms"; } @@ -662,18 +695,22 @@ void audioHandler::stateChanged(QAudio::State state) { case QAudio::IdleState: { - isUnderrun = true; - if (underTimer->isActive()) { - underTimer->stop(); + if (!setup.isinput) + { + qDebug(logAudio()) << "Output Underrun detected" << "Buffer size" << audioOutput->bufferSize() << "Bytes free" << audioOutput->bytesFree(); + if (isUnderrun && audioOutput->bytesFree() > audioOutput->bufferSize()/2) { + audioOutput->suspend(); + } } + isUnderrun = true; + if (!underTimer->isActive()) { + underTimer->start(setup.latency/2); + } + break; } case QAudio::ActiveState: { - //qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio started!"; - if (!underTimer->isActive()) { - underTimer->start(500); - } break; } case QAudio::SuspendedState: @@ -694,4 +731,8 @@ void audioHandler::clearUnderrun() { isUnderrun = false; underTimer->stop(); + if (!setup.isinput) { + qDebug(logAudio()) << "clearUnderrun() " << "Buffer size" << audioOutput->bufferSize() << "Bytes free" << audioOutput->bytesFree(); + audioOutput->resume(); + } } \ No newline at end of file diff --git a/audiohandler.h b/audiohandler.h index 128b270..7a09af7 100644 --- a/audiohandler.h +++ b/audiohandler.h @@ -12,6 +12,7 @@ #include #include #include +#include /* QT Audio Headers */ #include @@ -111,7 +112,7 @@ private: bool isInitialized=false; bool isReady = false; bool audioBuffered = false; - + QTime lastReceived; QAudioOutput* audioOutput=Q_NULLPTR; QAudioInput* audioInput=Q_NULLPTR; QIODevice* audioDevice=Q_NULLPTR; @@ -137,7 +138,7 @@ private: audioPacket tempBuf; quint16 currentLatency; float amplitude; - qreal volume=1.0; + float volume=1.0; audioSetup setup; @@ -149,6 +150,12 @@ private: // Various audio handling functions declared inline +typedef Eigen::Matrix VectorXuint8; +typedef Eigen::Matrix VectorXint8; +typedef Eigen::Matrix VectorXint16; +typedef Eigen::Matrix VectorXint32; + +/* static inline qint64 getAudioSize(qint64 timeInMs, const QAudioFormat& format) { #ifdef Q_OS_LINUX @@ -169,11 +176,6 @@ static inline qint64 getAudioDuration(qint64 bytes, const QAudioFormat& format) return qint64(qFloor(bytes / (format.channelCount() * (format.sampleSize() / 8) * format.sampleRate() / qreal(1000)))); } -typedef Eigen::Matrix VectorXuint8; -typedef Eigen::Matrix VectorXint8; -typedef Eigen::Matrix VectorXint16; -typedef Eigen::Matrix VectorXint32; - static inline QByteArray samplesToInt(const QByteArray& data, const QAudioFormat& supported_format) { QByteArray input = data; @@ -347,4 +349,5 @@ static inline QByteArray samplesToFloat(const QByteArray& data, const QAudioForm return QByteArray(); } +*/ #endif // AUDIOHANDLER_H diff --git a/udphandler.cpp b/udphandler.cpp index 1b5907f..a036a98 100644 --- a/udphandler.cpp +++ b/udphandler.cpp @@ -202,7 +202,7 @@ void udpHandler::dataReceived() } QString tempLatency; - if (status.rxLatency > status.rxCurrentLatency && !status.rxUnderrun) + if (status.rxLatency * 1.3 > (status.rxCurrentLatency) && !status.rxUnderrun) { tempLatency = QString("%1 ms").arg(status.rxCurrentLatency,3); }