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