AudioResampler.cpp (3959B)
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/. */ 5 6 #include "AudioResampler.h" 7 8 #include "TimeUnits.h" 9 10 namespace mozilla { 11 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) {} 17 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; 29 } 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; 35 } 36 MOZ_ASSERT(mIsSampleFormatSet); 37 if (chunk.IsNull()) { 38 mResampler.AppendInputSilence(chunk.GetDuration()); 39 continue; 40 } 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()); 48 } 49 } 50 } 51 52 AudioSegment AudioResampler::Resample(uint32_t aOutFrames, bool* aHasUnderrun) { 53 MOZ_ASSERT(aHasUnderrun); 54 55 AudioSegment segment; 56 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; 62 } 63 64 media::TimeUnit outDuration(aOutFrames, mResampler.mOutRate); 65 mResampler.EnsurePreBuffer(outDuration); 66 67 const media::TimeUnit chunkCapacity(mOutputChunks.ChunkCapacity(), 68 mResampler.mOutRate); 69 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; 75 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); 84 } 85 } 86 chunk.mDuration = outFrames; 87 88 // Create a copy in order to consume that copy and not the pre-allocated 89 // chunk 90 segment.AppendAndConsumeChunk(AudioChunk(chunk)); 91 } 92 93 return segment; 94 } 95 96 void AudioResampler::Update(uint32_t aInRate, uint32_t aChannels) { 97 mResampler.UpdateResampler(aInRate, aChannels); 98 mOutputChunks.Update(aChannels); 99 } 100 101 uint32_t AudioResampler::InputCapacityFrames() const { 102 return mResampler.InFramesBufferSize(); 103 } 104 105 uint32_t AudioResampler::InputReadableFrames() const { 106 return mResampler.InFramesBuffered(0); 107 } 108 109 } // namespace mozilla