Bug 1943650 - Command-line --help output misformatted after --dbus-service. r=emilio
[gecko.git] / dom / media / driftcontrol / AudioResampler.cpp
blob1402fae39e6ea816dba5aa69a17d6d2e9e8460ab
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"
8 #include "TimeUnits.h"
10 namespace mozilla {
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();
21 iter.Next()) {
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.
28 continue;
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);
37 if (chunk.IsNull()) {
38 mResampler.AppendInputSilence(chunk.GetDuration());
39 continue;
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());
46 } else {
47 mResampler.AppendInput(chunk.ChannelData<int16_t>(), chunk.GetDuration());
52 AudioSegment AudioResampler::Resample(uint32_t aOutFrames, bool* aHasUnderrun) {
53 MOZ_ASSERT(aHasUnderrun);
55 AudioSegment segment;
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);
61 return segment;
64 media::TimeUnit outDuration(aOutFrames, mResampler.mOutRate);
65 mResampler.EnsurePreBuffer(outDuration);
67 const media::TimeUnit chunkCapacity(mOutputChunks.ChunkCapacity(),
68 mResampler.mOutRate);
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);
81 } else {
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
89 // chunk
90 segment.AppendAndConsumeChunk(AudioChunk(chunk));
93 return segment;
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