mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 19:52:26 +02:00
Fix audio glitches caused by initial burst of SelectedAudioFormat packets.
Temporary codec mismatch is expected during audio codec startup, due to packets already in-flight.
This commit is contained in:
parent
e4e37e65e6
commit
a702c5a0e4
2 changed files with 26 additions and 6 deletions
|
@ -46,6 +46,10 @@ static const int STATS_FOR_STATS_PACKET_WINDOW_SECONDS = 30;
|
||||||
// _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset.
|
// _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset.
|
||||||
static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND;
|
static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND;
|
||||||
|
|
||||||
|
// When the audio codec is switched, temporary codec mismatch is expected due to packets in-flight.
|
||||||
|
// A SelectedAudioFormat packet is not sent until this threshold is exceeded.
|
||||||
|
static const int MAX_MISMATCHED_AUDIO_CODEC_COUNT = 10;
|
||||||
|
|
||||||
InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) :
|
InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) :
|
||||||
_ringBuffer(numChannels * numFrames, numBlocks),
|
_ringBuffer(numChannels * numFrames, numBlocks),
|
||||||
_numChannels(numChannels),
|
_numChannels(numChannels),
|
||||||
|
@ -134,6 +138,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
switch (arrivalInfo._status) {
|
switch (arrivalInfo._status) {
|
||||||
case SequenceNumberStats::Unreasonable: {
|
case SequenceNumberStats::Unreasonable: {
|
||||||
lostAudioData(1);
|
lostAudioData(1);
|
||||||
|
qDebug(audio) << "Sequence Unreasonable (LOST)";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SequenceNumberStats::Early: {
|
case SequenceNumberStats::Early: {
|
||||||
|
@ -143,6 +148,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
// fall through to the "on time" logic to actually handle this packet
|
// fall through to the "on time" logic to actually handle this packet
|
||||||
int packetsDropped = arrivalInfo._seqDiffFromExpected;
|
int packetsDropped = arrivalInfo._seqDiffFromExpected;
|
||||||
lostAudioData(packetsDropped);
|
lostAudioData(packetsDropped);
|
||||||
|
qDebug(audio) << "Sequence Early (LOST)";
|
||||||
|
|
||||||
// fall through to OnTime case
|
// fall through to OnTime case
|
||||||
}
|
}
|
||||||
|
@ -153,6 +159,8 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
// If we recieved a SilentAudioFrame from our sender, we might want to drop
|
// If we recieved a SilentAudioFrame from our sender, we might want to drop
|
||||||
// some of the samples in order to catch up to our desired jitter buffer size.
|
// some of the samples in order to catch up to our desired jitter buffer size.
|
||||||
writeDroppableSilentFrames(networkFrames);
|
writeDroppableSilentFrames(networkFrames);
|
||||||
|
qDebug(audio) << "OnTime (SILENT)";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// note: PCM and no codec are identical
|
// note: PCM and no codec are identical
|
||||||
bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == "";
|
bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == "";
|
||||||
|
@ -160,11 +168,15 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) {
|
if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) {
|
||||||
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
||||||
parseAudioData(message.getType(), afterProperties);
|
parseAudioData(message.getType(), afterProperties);
|
||||||
|
qDebug(audio) << "OnTime (DECODE:" << codecInPacket << afterProperties.size() << ")";
|
||||||
|
_mismatchedAudioCodecCount = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
_mismatchedAudioCodecCount++;
|
||||||
qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket;
|
qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket;
|
||||||
|
|
||||||
if (packetPCM) {
|
if (packetPCM) {
|
||||||
// If there are PCM packets in-flight while the codec is changed, use them.
|
// If there are PCM packets in-flight after the codec is changed, use them.
|
||||||
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead());
|
||||||
_ringBuffer.writeData(afterProperties.data(), afterProperties.size());
|
_ringBuffer.writeData(afterProperties.data(), afterProperties.size());
|
||||||
} else {
|
} else {
|
||||||
|
@ -174,12 +186,16 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
lostAudioData(1);
|
lostAudioData(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_mismatchedAudioCodecCount > MAX_MISMATCHED_AUDIO_CODEC_COUNT) {
|
||||||
|
_mismatchedAudioCodecCount = 0;
|
||||||
|
|
||||||
// inform others of the mismatch
|
// inform others of the mismatch
|
||||||
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
|
auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
|
||||||
if (sendingNode) {
|
if (sendingNode) {
|
||||||
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
|
||||||
|
qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -515,6 +531,7 @@ float calculateRepeatedFrameFadeFactor(int indexOfRepeat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InboundAudioStream::setupCodec(CodecPluginPointer codec, const QString& codecName, int numChannels) {
|
void InboundAudioStream::setupCodec(CodecPluginPointer codec, const QString& codecName, int numChannels) {
|
||||||
|
qDebug(audio) << "Setup Codec:" << codecName;
|
||||||
cleanupCodec(); // cleanup any previously allocated coders first
|
cleanupCodec(); // cleanup any previously allocated coders first
|
||||||
_codec = codec;
|
_codec = codec;
|
||||||
_selectedCodecName = codecName;
|
_selectedCodecName = codecName;
|
||||||
|
@ -525,6 +542,8 @@ void InboundAudioStream::setupCodec(CodecPluginPointer codec, const QString& cod
|
||||||
|
|
||||||
void InboundAudioStream::cleanupCodec() {
|
void InboundAudioStream::cleanupCodec() {
|
||||||
// release any old codec encoder/decoder first...
|
// release any old codec encoder/decoder first...
|
||||||
|
qDebug(audio) << "Cleanup Codec:" << _selectedCodecName;
|
||||||
|
|
||||||
if (_codec) {
|
if (_codec) {
|
||||||
if (_decoder) {
|
if (_decoder) {
|
||||||
_codec->releaseDecoder(_decoder);
|
_codec->releaseDecoder(_decoder);
|
||||||
|
|
|
@ -186,6 +186,7 @@ protected:
|
||||||
CodecPluginPointer _codec;
|
CodecPluginPointer _codec;
|
||||||
QString _selectedCodecName;
|
QString _selectedCodecName;
|
||||||
Decoder* _decoder { nullptr };
|
Decoder* _decoder { nullptr };
|
||||||
|
int _mismatchedAudioCodecCount { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
float calculateRepeatedFrameFadeFactor(int indexOfRepeat);
|
float calculateRepeatedFrameFadeFactor(int indexOfRepeat);
|
||||||
|
|
Loading…
Reference in a new issue