tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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