1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "DynamicResampler.h"
10 DynamicResampler::DynamicResampler(uint32_t aInRate
, uint32_t aOutRate
,
11 uint32_t aInputPreBufferFrameCount
)
13 mInputPreBufferFrameCount(aInputPreBufferFrameCount
),
17 UpdateResampler(mInRate
, STEREO
);
18 mInputStreamFile
.Open("DynamicResamplerInFirstChannel", 1, mInRate
);
19 mOutputStreamFile
.Open("DynamicResamplerOutFirstChannel", 1, mOutRate
);
22 DynamicResampler::~DynamicResampler() {
24 speex_resampler_destroy(mResampler
);
28 void DynamicResampler::SetSampleFormat(AudioSampleFormat aFormat
) {
29 MOZ_ASSERT(mSampleFormat
== AUDIO_FORMAT_SILENCE
);
30 MOZ_ASSERT(aFormat
== AUDIO_FORMAT_S16
|| aFormat
== AUDIO_FORMAT_FLOAT32
);
32 mSampleFormat
= aFormat
;
33 for (AudioRingBuffer
& b
: mInternalInBuffer
) {
34 b
.SetSampleFormat(mSampleFormat
);
37 // Pre-allocate something big.
38 // EnsureInputBufferDuration() adds 50ms for jitter to this first allocation
39 // so the 50ms argument means at least 100ms.
40 EnsureInputBufferSizeInFrames(mInRate
/ 20);
43 void DynamicResampler::EnsurePreBuffer(media::TimeUnit aDuration
) {
44 if (mIsPreBufferSet
) {
48 uint32_t buffered
= mInternalInBuffer
[0].AvailableRead();
50 // Wait for the first input segment before deciding how much to pre-buffer.
51 // If it is large it indicates high-latency, and the buffer would have to
52 // handle that. This also means that the pre-buffer is not set up just
53 // before a large input segment would extend the buffering beyond the
58 mIsPreBufferSet
= true;
61 aDuration
.ToTicksAtRate(mInRate
) + mInputPreBufferFrameCount
;
62 EnsureInputBufferSizeInFrames(needed
);
64 if (needed
> buffered
) {
65 for (auto& b
: mInternalInBuffer
) {
66 b
.PrependSilence(needed
- buffered
);
68 } else if (needed
< buffered
) {
69 for (auto& b
: mInternalInBuffer
) {
70 b
.Discard(buffered
- needed
);
75 void DynamicResampler::SetInputPreBufferFrameCount(
76 uint32_t aInputPreBufferFrameCount
) {
77 mInputPreBufferFrameCount
= aInputPreBufferFrameCount
;
80 bool DynamicResampler::Resample(float* aOutBuffer
, uint32_t aOutFrames
,
81 uint32_t aChannelIndex
) {
82 MOZ_ASSERT(mSampleFormat
== AUDIO_FORMAT_FLOAT32
);
83 return ResampleInternal(aOutBuffer
, aOutFrames
, aChannelIndex
);
86 bool DynamicResampler::Resample(int16_t* aOutBuffer
, uint32_t aOutFrames
,
87 uint32_t aChannelIndex
) {
88 MOZ_ASSERT(mSampleFormat
== AUDIO_FORMAT_S16
);
89 return ResampleInternal(aOutBuffer
, aOutFrames
, aChannelIndex
);
92 void DynamicResampler::ResampleInternal(const float* aInBuffer
,
93 uint32_t* aInFrames
, float* aOutBuffer
,
95 uint32_t aChannelIndex
) {
96 MOZ_ASSERT(mResampler
);
97 MOZ_ASSERT(mChannels
);
101 MOZ_ASSERT(aInFrames
);
102 MOZ_ASSERT(*aInFrames
> 0);
103 MOZ_ASSERT(aOutBuffer
);
104 MOZ_ASSERT(aOutFrames
);
105 MOZ_ASSERT(*aOutFrames
> 0);
107 MOZ_ASSERT(aChannelIndex
<= mChannels
);
112 speex_resampler_process_float(mResampler
, aChannelIndex
, aInBuffer
,
113 aInFrames
, aOutBuffer
, aOutFrames
);
114 MOZ_ASSERT(rv
== RESAMPLER_ERR_SUCCESS
);
116 if (aChannelIndex
== 0 && !mIsWarmingUp
) {
117 mInputStreamFile
.Write(aInBuffer
, *aInFrames
);
118 mOutputStreamFile
.Write(aOutBuffer
, *aOutFrames
);
122 void DynamicResampler::ResampleInternal(const int16_t* aInBuffer
,
125 uint32_t* aOutFrames
,
126 uint32_t aChannelIndex
) {
127 MOZ_ASSERT(mResampler
);
128 MOZ_ASSERT(mChannels
);
130 MOZ_ASSERT(mOutRate
);
132 MOZ_ASSERT(aInFrames
);
133 MOZ_ASSERT(*aInFrames
> 0);
134 MOZ_ASSERT(aOutBuffer
);
135 MOZ_ASSERT(aOutFrames
);
136 MOZ_ASSERT(*aOutFrames
> 0);
138 MOZ_ASSERT(aChannelIndex
<= mChannels
);
143 speex_resampler_process_int(mResampler
, aChannelIndex
, aInBuffer
,
144 aInFrames
, aOutBuffer
, aOutFrames
);
145 MOZ_ASSERT(rv
== RESAMPLER_ERR_SUCCESS
);
147 if (aChannelIndex
== 0 && !mIsWarmingUp
) {
148 mInputStreamFile
.Write(aInBuffer
, *aInFrames
);
149 mOutputStreamFile
.Write(aOutBuffer
, *aOutFrames
);
153 void DynamicResampler::UpdateResampler(uint32_t aInRate
, uint32_t aChannels
) {
155 MOZ_ASSERT(aChannels
);
157 if (mChannels
!= aChannels
) {
158 uint32_t bufferSizeInFrames
= InFramesBufferSize();
160 speex_resampler_destroy(mResampler
);
162 mResampler
= speex_resampler_init(aChannels
, aInRate
, mOutRate
,
163 SPEEX_RESAMPLER_QUALITY_MIN
, nullptr);
164 MOZ_ASSERT(mResampler
);
165 mChannels
= aChannels
;
167 mResamplerIsBypassed
&= aInRate
== mOutRate
;
168 // Between mono and stereo changes, keep always allocated 2 channels to
169 // avoid reallocations in the most common case.
170 if ((mChannels
== STEREO
|| mChannels
== 1) &&
171 mInternalInBuffer
.Length() == STEREO
) {
172 // Don't worry if format is not set it will write silence then.
173 if ((mSampleFormat
== AUDIO_FORMAT_S16
||
174 mSampleFormat
== AUDIO_FORMAT_FLOAT32
) &&
175 mChannels
== STEREO
) {
176 // The mono channel is always up to date. When we are going from mono
177 // to stereo upmix the mono to stereo channel
178 uint32_t bufferedDuration
= mInternalInBuffer
[0].AvailableRead();
179 mInternalInBuffer
[1].Clear();
180 if (bufferedDuration
) {
181 mInternalInBuffer
[1].Write(mInternalInBuffer
[0], bufferedDuration
);
184 // Maintain stereo size
185 mInputTail
.SetLength(STEREO
);
186 WarmUpResampler(false);
189 // upmix or downmix, for now just clear but it has to be updated
190 // because allocates and this is executed in audio thread.
191 mInternalInBuffer
.Clear();
192 for (uint32_t i
= 0; i
< mChannels
; ++i
) {
193 AudioRingBuffer
* b
= mInternalInBuffer
.AppendElement(0);
195 if (mSampleFormat
!= AUDIO_FORMAT_SILENCE
) {
196 // In ctor this update is not needed
197 b
->SetSampleFormat(mSampleFormat
);
200 EnsureInputBufferSizeInFrames(bufferSizeInFrames
);
201 mInputTail
.SetLength(mChannels
);
205 if (mInRate
!= aInRate
) {
206 // If the rates was the same the resampler was not being used so warm up.
207 if (mResamplerIsBypassed
) {
208 mResamplerIsBypassed
= false;
209 WarmUpResampler(true);
215 speex_resampler_set_rate(mResampler
, aInRate
, mOutRate
);
216 MOZ_ASSERT(rv
== RESAMPLER_ERR_SUCCESS
);
221 void DynamicResampler::WarmUpResampler(bool aSkipLatency
) {
222 MOZ_ASSERT(mInputTail
.Length());
224 for (uint32_t i
= 0; i
< mChannels
; ++i
) {
225 if (!mInputTail
[i
].Length()) {
228 uint32_t inFrames
= mInputTail
[i
].Length();
229 uint32_t outFrames
= 5 * TailBuffer::MAXSIZE
; // something big
230 if (mSampleFormat
== AUDIO_FORMAT_S16
) {
231 short outBuffer
[5 * TailBuffer::MAXSIZE
] = {};
232 ResampleInternal(mInputTail
[i
].Buffer
<short>(), &inFrames
, outBuffer
,
234 MOZ_ASSERT(inFrames
== (uint32_t)mInputTail
[i
].Length());
236 float outBuffer
[100] = {};
237 ResampleInternal(mInputTail
[i
].Buffer
<float>(), &inFrames
, outBuffer
,
239 MOZ_ASSERT(inFrames
== (uint32_t)mInputTail
[i
].Length());
243 // Don't generate output frames corresponding to times before the next
245 speex_resampler_skip_zeros(mResampler
);
247 mIsWarmingUp
= false;
250 void DynamicResampler::AppendInput(Span
<const float* const> aInBuffer
,
251 uint32_t aInFrames
) {
252 MOZ_ASSERT(mSampleFormat
== AUDIO_FORMAT_FLOAT32
);
253 AppendInputInternal(aInBuffer
, aInFrames
);
255 void DynamicResampler::AppendInput(Span
<const int16_t* const> aInBuffer
,
256 uint32_t aInFrames
) {
257 MOZ_ASSERT(mSampleFormat
== AUDIO_FORMAT_S16
);
258 AppendInputInternal(aInBuffer
, aInFrames
);
261 void DynamicResampler::AppendInputSilence(const uint32_t aInFrames
) {
262 MOZ_ASSERT(aInFrames
);
263 MOZ_ASSERT(mChannels
);
264 MOZ_ASSERT(mInternalInBuffer
.Length() >= (uint32_t)mChannels
);
265 for (uint32_t i
= 0; i
< mChannels
; ++i
) {
266 mInternalInBuffer
[i
].WriteSilence(aInFrames
);
270 uint32_t DynamicResampler::InFramesBufferSize() const {
271 if (mSampleFormat
== AUDIO_FORMAT_SILENCE
) {
274 // Buffers may have different capacities if a memory allocation has failed.
275 MOZ_ASSERT(!mInternalInBuffer
.IsEmpty());
276 uint32_t min
= std::numeric_limits
<uint32_t>::max();
277 for (const auto& b
: mInternalInBuffer
) {
278 min
= std::min(min
, b
.Capacity());
283 uint32_t DynamicResampler::InFramesBuffered(uint32_t aChannelIndex
) const {
284 MOZ_ASSERT(mChannels
);
285 MOZ_ASSERT(aChannelIndex
<= mChannels
);
286 MOZ_ASSERT(aChannelIndex
<= mInternalInBuffer
.Length());
287 if (!mIsPreBufferSet
) {
288 return mInputPreBufferFrameCount
;
290 return mInternalInBuffer
[aChannelIndex
].AvailableRead();
293 } // namespace mozilla