mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 08:33:38 +02:00
Use interpolated audio (codec packet-loss concealment) or zero samples (if no codec) when audio packets are lost. This audio is still processed by the audio pipeline to avoid clicks/pops.
This commit is contained in:
parent
68de18a3bb
commit
4acb99cd4f
7 changed files with 54 additions and 13 deletions
|
@ -136,7 +136,8 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
|||
// NOTE: we assume that each dropped packet contains the same number of samples
|
||||
// as the packet we just received.
|
||||
int packetsDropped = arrivalInfo._seqDiffFromExpected;
|
||||
writeFramesForDroppedPackets(packetsDropped * networkFrames);
|
||||
//writeFramesForDroppedPackets(packetsDropped * networkFrames);
|
||||
lostAudioData(packetsDropped);
|
||||
|
||||
// fall through to OnTime case
|
||||
}
|
||||
|
@ -208,6 +209,21 @@ int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray&
|
|||
}
|
||||
}
|
||||
|
||||
int InboundAudioStream::lostAudioData(int numPackets) {
|
||||
QByteArray decodedBuffer;
|
||||
|
||||
while (numPackets--) {
|
||||
if (_decoder) {
|
||||
_decoder->lostFrame(decodedBuffer);
|
||||
} else {
|
||||
decodedBuffer.resize(AudioConstants::NETWORK_FRAME_BYTES_STEREO);
|
||||
memset(decodedBuffer.data(), 0, decodedBuffer.size());
|
||||
}
|
||||
_ringBuffer.writeData(decodedBuffer.data(), decodedBuffer.size());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) {
|
||||
QByteArray decodedBuffer;
|
||||
if (_decoder) {
|
||||
|
@ -220,9 +236,6 @@ int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packet
|
|||
}
|
||||
|
||||
int InboundAudioStream::writeDroppableSilentFrames(int silentFrames) {
|
||||
if (_decoder) {
|
||||
_decoder->trackLostFrames(silentFrames);
|
||||
}
|
||||
|
||||
// calculate how many silent frames we should drop.
|
||||
int silentSamples = silentFrames * _numChannels;
|
||||
|
|
|
@ -134,6 +134,9 @@ protected:
|
|||
/// default implementation assumes packet contains raw audio samples after stream properties
|
||||
virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties);
|
||||
|
||||
/// produces audio data for lost network packets.
|
||||
virtual int lostAudioData(int numPackets);
|
||||
|
||||
/// writes silent frames to the buffer that may be dropped to reduce latency caused by the buffer
|
||||
virtual int writeDroppableSilentFrames(int silentFrames);
|
||||
|
||||
|
|
|
@ -38,6 +38,28 @@ int MixedProcessedAudioStream::writeLastFrameRepeatedWithFade(int frames) {
|
|||
return deviceFramesWritten;
|
||||
}
|
||||
|
||||
int MixedProcessedAudioStream::lostAudioData(int numPackets) {
|
||||
QByteArray decodedBuffer;
|
||||
QByteArray outputBuffer;
|
||||
|
||||
while (numPackets--) {
|
||||
if (_decoder) {
|
||||
_decoder->lostFrame(decodedBuffer);
|
||||
} else {
|
||||
decodedBuffer.resize(AudioConstants::NETWORK_FRAME_BYTES_STEREO);
|
||||
memset(decodedBuffer.data(), 0, decodedBuffer.size());
|
||||
}
|
||||
|
||||
emit addedStereoSamples(decodedBuffer);
|
||||
|
||||
emit processSamples(decodedBuffer, outputBuffer);
|
||||
|
||||
_ringBuffer.writeData(outputBuffer.data(), outputBuffer.size());
|
||||
qCDebug(audiostream, "Wrote %d samples to buffer (%d available)", outputBuffer.size() / (int)sizeof(int16_t), getSamplesAvailable());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) {
|
||||
QByteArray decodedBuffer;
|
||||
if (_decoder) {
|
||||
|
|
|
@ -36,6 +36,7 @@ protected:
|
|||
int writeDroppableSilentFrames(int silentFrames) override;
|
||||
int writeLastFrameRepeatedWithFade(int frames) override;
|
||||
int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) override;
|
||||
int lostAudioData(int numPackets) override;
|
||||
|
||||
private:
|
||||
int networkToDeviceFrames(int networkFrames);
|
||||
|
|
|
@ -23,8 +23,7 @@ public:
|
|||
virtual ~Decoder() { }
|
||||
virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) = 0;
|
||||
|
||||
// numFrames - number of samples (mono) or sample-pairs (stereo)
|
||||
virtual void trackLostFrames(int numFrames) = 0;
|
||||
virtual void lostFrame(QByteArray& decodedBuffer) = 0;
|
||||
};
|
||||
|
||||
class CodecPlugin : public Plugin {
|
||||
|
|
|
@ -65,12 +65,10 @@ public:
|
|||
AudioDecoder::process((const int16_t*)encodedBuffer.constData(), (int16_t*)decodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL, true);
|
||||
}
|
||||
|
||||
virtual void trackLostFrames(int numFrames) override {
|
||||
QByteArray encodedBuffer;
|
||||
QByteArray decodedBuffer;
|
||||
virtual void lostFrame(QByteArray& decodedBuffer) override {
|
||||
decodedBuffer.resize(_decodedSize);
|
||||
// NOTE: we don't actually use the results of this decode, we just do it to keep the state of the codec clean
|
||||
AudioDecoder::process((const int16_t*)encodedBuffer.constData(), (int16_t*)decodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL, false);
|
||||
// this performs packet loss interpolation
|
||||
AudioDecoder::process(nullptr, (int16_t*)decodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL, false);
|
||||
}
|
||||
private:
|
||||
int _decodedSize;
|
||||
|
|
|
@ -38,11 +38,14 @@ public:
|
|||
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override {
|
||||
encodedBuffer = decodedBuffer;
|
||||
}
|
||||
|
||||
virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override {
|
||||
decodedBuffer = encodedBuffer;
|
||||
}
|
||||
|
||||
virtual void trackLostFrames(int numFrames) override { }
|
||||
virtual void lostFrame(QByteArray& decodedBuffer) override {
|
||||
memset(decodedBuffer.data(), 0, decodedBuffer.size());
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* NAME;
|
||||
|
@ -77,7 +80,9 @@ public:
|
|||
decodedBuffer = qUncompress(encodedBuffer);
|
||||
}
|
||||
|
||||
virtual void trackLostFrames(int numFrames) override { }
|
||||
virtual void lostFrame(QByteArray& decodedBuffer) override {
|
||||
memset(decodedBuffer.data(), 0, decodedBuffer.size());
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* NAME;
|
||||
|
|
Loading…
Reference in a new issue