diff options
Diffstat (limited to 'dom/media/driftcontrol/DynamicResampler.cpp')
-rw-r--r-- | dom/media/driftcontrol/DynamicResampler.cpp | 83 |
1 files changed, 45 insertions, 38 deletions
diff --git a/dom/media/driftcontrol/DynamicResampler.cpp b/dom/media/driftcontrol/DynamicResampler.cpp index e6f230278e..65a2ae3b57 100644 --- a/dom/media/driftcontrol/DynamicResampler.cpp +++ b/dom/media/driftcontrol/DynamicResampler.cpp @@ -8,14 +8,13 @@ namespace mozilla { DynamicResampler::DynamicResampler(uint32_t aInRate, uint32_t aOutRate, - media::TimeUnit aPreBufferDuration) - : mInRate(aInRate), - mPreBufferDuration(aPreBufferDuration), - mOutRate(aOutRate) { + uint32_t aInputPreBufferFrameCount) + : mOutRate(aOutRate), + mInputPreBufferFrameCount(aInputPreBufferFrameCount), + mInRate(aInRate) { MOZ_ASSERT(aInRate); MOZ_ASSERT(aOutRate); - MOZ_ASSERT(aPreBufferDuration.IsPositiveOrZero()); - UpdateResampler(mOutRate, STEREO); + UpdateResampler(mInRate, STEREO); mInputStreamFile.Open("DynamicResamplerInFirstChannel", 1, mInRate); mOutputStreamFile.Open("DynamicResamplerOutFirstChannel", 1, mOutRate); } @@ -35,7 +34,10 @@ void DynamicResampler::SetSampleFormat(AudioSampleFormat aFormat) { b.SetSampleFormat(mSampleFormat); } - EnsureInputBufferDuration(CalculateInputBufferDuration()); + // Pre-allocate something big. + // EnsureInputBufferDuration() adds 50ms for jitter to this first allocation + // so the 50ms argument means at least 100ms. + EnsureInputBufferSizeInFrames(mInRate / 20); } void DynamicResampler::EnsurePreBuffer(media::TimeUnit aDuration) { @@ -43,33 +45,36 @@ void DynamicResampler::EnsurePreBuffer(media::TimeUnit aDuration) { return; } - media::TimeUnit buffered(mInternalInBuffer[0].AvailableRead(), mInRate); - if (buffered.IsZero()) { + uint32_t buffered = mInternalInBuffer[0].AvailableRead(); + if (buffered == 0) { // Wait for the first input segment before deciding how much to pre-buffer. // If it is large it indicates high-latency, and the buffer would have to - // handle that. + // handle that. This also means that the pre-buffer is not set up just + // before a large input segment would extend the buffering beyond the + // desired level. return; } mIsPreBufferSet = true; - media::TimeUnit needed = aDuration + mPreBufferDuration; - EnsureInputBufferDuration(needed); + uint32_t needed = + aDuration.ToTicksAtRate(mInRate) + mInputPreBufferFrameCount; + EnsureInputBufferSizeInFrames(needed); if (needed > buffered) { for (auto& b : mInternalInBuffer) { - b.PrependSilence((needed - buffered).ToTicksAtRate(mInRate)); + b.PrependSilence(needed - buffered); } } else if (needed < buffered) { for (auto& b : mInternalInBuffer) { - b.Discard((buffered - needed).ToTicksAtRate(mInRate)); + b.Discard(buffered - needed); } } } -void DynamicResampler::SetPreBufferDuration(media::TimeUnit aDuration) { - MOZ_ASSERT(aDuration.IsPositive()); - mPreBufferDuration = aDuration; +void DynamicResampler::SetInputPreBufferFrameCount( + uint32_t aInputPreBufferFrameCount) { + mInputPreBufferFrameCount = aInputPreBufferFrameCount; } bool DynamicResampler::Resample(float* aOutBuffer, uint32_t aOutFrames, @@ -93,7 +98,6 @@ void DynamicResampler::ResampleInternal(const float* aInBuffer, MOZ_ASSERT(mInRate); MOZ_ASSERT(mOutRate); - MOZ_ASSERT(aInBuffer); MOZ_ASSERT(aInFrames); MOZ_ASSERT(*aInFrames > 0); MOZ_ASSERT(aOutBuffer); @@ -125,7 +129,6 @@ void DynamicResampler::ResampleInternal(const int16_t* aInBuffer, MOZ_ASSERT(mInRate); MOZ_ASSERT(mOutRate); - MOZ_ASSERT(aInBuffer); MOZ_ASSERT(aInFrames); MOZ_ASSERT(*aInFrames > 0); MOZ_ASSERT(aOutBuffer); @@ -147,19 +150,20 @@ void DynamicResampler::ResampleInternal(const int16_t* aInBuffer, } } -void DynamicResampler::UpdateResampler(uint32_t aOutRate, uint32_t aChannels) { - MOZ_ASSERT(aOutRate); +void DynamicResampler::UpdateResampler(uint32_t aInRate, uint32_t aChannels) { + MOZ_ASSERT(aInRate); MOZ_ASSERT(aChannels); if (mChannels != aChannels) { + uint32_t bufferSizeInFrames = InFramesBufferSize(); if (mResampler) { speex_resampler_destroy(mResampler); } - mResampler = speex_resampler_init(aChannels, mInRate, aOutRate, + mResampler = speex_resampler_init(aChannels, aInRate, mOutRate, SPEEX_RESAMPLER_QUALITY_MIN, nullptr); MOZ_ASSERT(mResampler); mChannels = aChannels; - mOutRate = aOutRate; + mInRate = aInRate; // Between mono and stereo changes, keep always allocated 2 channels to // avoid reallocations in the most common case. if ((mChannels == STEREO || mChannels == 1) && @@ -192,14 +196,12 @@ void DynamicResampler::UpdateResampler(uint32_t aOutRate, uint32_t aChannels) { b->SetSampleFormat(mSampleFormat); } } - media::TimeUnit d = mSetBufferDuration; - mSetBufferDuration = media::TimeUnit::Zero(); - EnsureInputBufferDuration(d); + EnsureInputBufferSizeInFrames(bufferSizeInFrames); mInputTail.SetLength(mChannels); return; } - if (mOutRate != aOutRate) { + if (mInRate != aInRate) { // If the rates was the same the resampler was not being used so warm up. if (mOutRate == mInRate) { WarmUpResampler(true); @@ -208,9 +210,9 @@ void DynamicResampler::UpdateResampler(uint32_t aOutRate, uint32_t aChannels) { #ifdef DEBUG int rv = #endif - speex_resampler_set_rate(mResampler, mInRate, aOutRate); + speex_resampler_set_rate(mResampler, aInRate, mOutRate); MOZ_ASSERT(rv == RESAMPLER_ERR_SUCCESS); - mOutRate = aOutRate; + mInRate = aInRate; } } @@ -236,13 +238,9 @@ void DynamicResampler::WarmUpResampler(bool aSkipLatency) { } } if (aSkipLatency) { - int inputLatency = speex_resampler_get_input_latency(mResampler); - MOZ_ASSERT(inputLatency > 0); - uint32_t ratioNum, ratioDen; - speex_resampler_get_ratio(mResampler, &ratioNum, &ratioDen); - // Ratio at this point is one so only skip the input latency. No special - // calculations are needed. - speex_resampler_set_skip_frac_num(mResampler, inputLatency * ratioDen); + // Don't generate output frames corresponding to times before the next + // input sample. + speex_resampler_skip_zeros(mResampler); } mIsWarmingUp = false; } @@ -268,7 +266,16 @@ void DynamicResampler::AppendInputSilence(const uint32_t aInFrames) { } uint32_t DynamicResampler::InFramesBufferSize() const { - return mSetBufferDuration.ToTicksAtRate(mInRate); + if (mSampleFormat == AUDIO_FORMAT_SILENCE) { + return 0; + } + // Buffers may have different capacities if a memory allocation has failed. + MOZ_ASSERT(!mInternalInBuffer.IsEmpty()); + uint32_t min = std::numeric_limits<uint32_t>::max(); + for (const auto& b : mInternalInBuffer) { + min = std::min(min, b.Capacity()); + } + return min; } uint32_t DynamicResampler::InFramesBuffered(uint32_t aChannelIndex) const { @@ -276,7 +283,7 @@ uint32_t DynamicResampler::InFramesBuffered(uint32_t aChannelIndex) const { MOZ_ASSERT(aChannelIndex <= mChannels); MOZ_ASSERT(aChannelIndex <= mInternalInBuffer.Length()); if (!mIsPreBufferSet) { - return mPreBufferDuration.ToTicksAtRate(mInRate); + return mInputPreBufferFrameCount; } return mInternalInBuffer[aChannelIndex].AvailableRead(); } |