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 "AudioResampler.h"
12 AudioResampler::AudioResampler(uint32_t aInRate
, uint32_t aOutRate
,
13 uint32_t aInputPreBufferFrameCount
,
14 const PrincipalHandle
& aPrincipalHandle
)
15 : mResampler(aInRate
, aOutRate
, aInputPreBufferFrameCount
),
16 mOutputChunks(aOutRate
/ 10, STEREO
, aPrincipalHandle
) {}
18 void AudioResampler::AppendInput(const AudioSegment
& aInSegment
) {
19 MOZ_ASSERT(aInSegment
.GetDuration());
20 for (AudioSegment::ConstChunkIterator
iter(aInSegment
); !iter
.IsEnded();
22 const AudioChunk
& chunk
= *iter
;
23 if (!mIsSampleFormatSet
) {
24 // We don't know the format yet and all buffers are empty.
25 if (chunk
.mBufferFormat
== AUDIO_FORMAT_SILENCE
) {
26 // Only silence has been received and the format is unkown. Igonre it,
27 // if Resampler() is called it will return silence too.
30 // First no silence data, set the format once for lifetime and let it
31 // continue the rest of the flow. We will not get in here again.
32 mOutputChunks
.SetSampleFormat(chunk
.mBufferFormat
);
33 mResampler
.SetSampleFormat(chunk
.mBufferFormat
);
34 mIsSampleFormatSet
= true;
36 MOZ_ASSERT(mIsSampleFormatSet
);
38 mResampler
.AppendInputSilence(chunk
.GetDuration());
41 // Make sure the channel is up to date. An AudioSegment can contain chunks
42 // with different channel count.
43 UpdateChannels(chunk
.mChannelData
.Length());
44 if (chunk
.mBufferFormat
== AUDIO_FORMAT_FLOAT32
) {
45 mResampler
.AppendInput(chunk
.ChannelData
<float>(), chunk
.GetDuration());
47 mResampler
.AppendInput(chunk
.ChannelData
<int16_t>(), chunk
.GetDuration());
52 AudioSegment
AudioResampler::Resample(uint32_t aOutFrames
, bool* aHasUnderrun
) {
53 MOZ_ASSERT(aHasUnderrun
);
57 // We don't know what to do yet and we only have received silence if any just
58 // return what they want and leave
59 if (!mIsSampleFormatSet
) {
60 segment
.AppendNullData(aOutFrames
);
64 media::TimeUnit
outDuration(aOutFrames
, mResampler
.mOutRate
);
65 mResampler
.EnsurePreBuffer(outDuration
);
67 const media::TimeUnit
chunkCapacity(mOutputChunks
.ChunkCapacity(),
70 while (!outDuration
.IsZero()) {
71 MOZ_ASSERT(outDuration
.IsPositive());
72 AudioChunk
& chunk
= mOutputChunks
.GetNext();
73 const media::TimeUnit chunkDuration
= std::min(outDuration
, chunkCapacity
);
74 outDuration
-= chunkDuration
;
76 const uint32_t outFrames
= chunkDuration
.ToTicksAtRate(mResampler
.mOutRate
);
77 for (uint32_t i
= 0; i
< chunk
.ChannelCount(); ++i
) {
78 if (chunk
.mBufferFormat
== AUDIO_FORMAT_FLOAT32
) {
79 *aHasUnderrun
|= mResampler
.Resample(
80 chunk
.ChannelDataForWrite
<float>(i
), outFrames
, i
);
82 *aHasUnderrun
|= mResampler
.Resample(
83 chunk
.ChannelDataForWrite
<int16_t>(i
), outFrames
, i
);
86 chunk
.mDuration
= outFrames
;
88 // Create a copy in order to consume that copy and not the pre-allocated
90 segment
.AppendAndConsumeChunk(AudioChunk(chunk
));
96 void AudioResampler::Update(uint32_t aInRate
, uint32_t aChannels
) {
97 mResampler
.UpdateResampler(aInRate
, aChannels
);
98 mOutputChunks
.Update(aChannels
);
101 uint32_t AudioResampler::InputCapacityFrames() const {
102 return mResampler
.InFramesBufferSize();
105 uint32_t AudioResampler::InputReadableFrames() const {
106 return mResampler
.InFramesBuffered(0);
109 } // namespace mozilla