tor-browser

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

AudioCompactor.h (4593B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 #ifndef AudioCompactor_h
      7 #define AudioCompactor_h
      8 
      9 #include "MediaData.h"
     10 #include "MediaQueue.h"
     11 #include "VideoUtils.h"
     12 
     13 namespace mozilla {
     14 
     15 class AudioCompactor {
     16 public:
     17  explicit AudioCompactor(MediaQueue<AudioData>& aQueue) : mQueue(aQueue) {
     18    // Determine padding size used by AlignedBuffer.
     19    size_t paddedSize = AlignedAudioBuffer::AlignmentPaddingSize();
     20    mSamplesPadding = paddedSize / sizeof(AudioDataValue);
     21    if (mSamplesPadding * sizeof(AudioDataValue) < paddedSize) {
     22      // Round up.
     23      mSamplesPadding++;
     24    }
     25  }
     26 
     27  // Push audio data into the underlying queue with minimal heap allocation
     28  // slop.  This method is responsible for allocating AudioDataValue[] buffers.
     29  // The caller must provide a functor to copy the data into the buffers.  The
     30  // functor must provide the following signature:
     31  //
     32  //   uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples);
     33  //
     34  // The functor must copy as many complete frames as possible to the provided
     35  // buffer given its length (in AudioDataValue elements).  The number of frames
     36  // copied must be returned.  This copy functor must support being called
     37  // multiple times in order to copy the audio data fully.  The copy functor
     38  // must copy full frames as partial frames will be ignored.
     39  template <typename CopyFunc>
     40  bool Push(int64_t aOffset, int64_t aTime, int32_t aSampleRate,
     41            uint32_t aFrames, uint32_t aChannels, CopyFunc aCopyFunc) {
     42    auto time = media::TimeUnit::FromMicroseconds(aTime);
     43 
     44    // If we are losing more than a reasonable amount to padding, try to chunk
     45    // the data.
     46    size_t maxSlop = AudioDataSize(aFrames, aChannels) / MAX_SLOP_DIVISOR;
     47 
     48    while (aFrames > 0) {
     49      uint32_t samples = GetChunkSamples(aFrames, aChannels, maxSlop);
     50      if (samples / aChannels > mSamplesPadding / aChannels + 1) {
     51        samples -= mSamplesPadding;
     52      }
     53      AlignedAudioBuffer buffer(samples);
     54      if (!buffer) {
     55        return false;
     56      }
     57 
     58      // Copy audio data to buffer using caller-provided functor.
     59      uint32_t framesCopied = aCopyFunc(buffer.get(), samples);
     60 
     61      NS_ASSERTION(framesCopied <= aFrames, "functor copied too many frames");
     62      buffer.SetLength(size_t(framesCopied) * aChannels);
     63 
     64      auto duration = media::TimeUnit(framesCopied, aSampleRate);
     65      if (!duration.IsValid()) {
     66        return false;
     67      }
     68 
     69      RefPtr<AudioData> data = new AudioData(aOffset, time, std::move(buffer),
     70                                             aChannels, aSampleRate);
     71      MOZ_DIAGNOSTIC_ASSERT(duration == data->mDuration, "must be equal");
     72      mQueue.Push(data);
     73 
     74      // Remove the frames we just pushed into the queue and loop if there is
     75      // more to be done.
     76      time += duration;
     77      aFrames -= framesCopied;
     78 
     79      // NOTE: No need to update aOffset as its only an approximation anyway.
     80    }
     81 
     82    return true;
     83  }
     84 
     85  // Copy functor suitable for copying audio samples already in the
     86  // AudioDataValue format/layout expected by AudioStream on this platform.
     87  class NativeCopy {
     88   public:
     89    NativeCopy(const uint8_t* aSource, size_t aSourceBytes, uint32_t aChannels)
     90        : mSource(aSource),
     91          mSourceBytes(aSourceBytes),
     92          mChannels(aChannels),
     93          mNextByte(0) {}
     94 
     95    uint32_t operator()(AudioDataValue* aBuffer, uint32_t aSamples);
     96 
     97   private:
     98    const uint8_t* const mSource;
     99    const size_t mSourceBytes;
    100    const uint32_t mChannels;
    101    size_t mNextByte;
    102  };
    103 
    104  // Allow 12.5% slop before chunking kicks in.  Public so that the gtest can
    105  // access it.
    106  static const size_t MAX_SLOP_DIVISOR = 8;
    107 
    108 private:
    109  // Compute the number of AudioDataValue samples that will be fit the most
    110  // frames while keeping heap allocation slop less than the given threshold.
    111  static uint32_t GetChunkSamples(uint32_t aFrames, uint32_t aChannels,
    112                                  size_t aMaxSlop);
    113 
    114  static size_t BytesPerFrame(uint32_t aChannels) {
    115    return sizeof(AudioDataValue) * aChannels;
    116  }
    117 
    118  static size_t AudioDataSize(uint32_t aFrames, uint32_t aChannels) {
    119    return aFrames * BytesPerFrame(aChannels);
    120  }
    121 
    122  MediaQueue<AudioData>& mQueue;
    123  size_t mSamplesPadding;
    124 };
    125 
    126 }  // namespace mozilla
    127 
    128 #endif  // AudioCompactor_h