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 #ifndef AudioPacketizer_h_ 7 #define AudioPacketizer_h_ 8 9 #include <mozilla/PodOperations.h> 10 #include <mozilla/Assertions.h> 11 #include <mozilla/UniquePtr.h> 12 #include <AudioSampleFormat.h> 13 14 // Enable this to warn when `Output` has been called but not enough data was 15 // buffered. 16 // #define LOG_PACKETIZER_UNDERRUN 17 18 namespace mozilla { 19 /** 20 * This class takes arbitrary input data, and returns packets of a specific 21 * size. In the process, it can convert audio samples from 16bit integers to 22 * float (or vice-versa). 23 * 24 * Input and output, as well as length units in the public interface are 25 * interleaved frames. 26 * 27 * Allocations of output buffer can be performed by this class. Buffers can 28 * simply be delete-d. This is because packets are intended to be sent off to 29 * non-gecko code using normal pointers/length pairs 30 * 31 * Alternatively, consumers can pass in a buffer in which the output is copied. 32 * The buffer needs to be large enough to store a packet worth of audio. 33 * 34 * The implementation uses a circular buffer using absolute virtual indices. 35 */ 36 template <typename InputType, typename OutputType> 37 class AudioPacketizer { 38 public: AudioPacketizer(uint32_t aPacketSize,uint32_t aChannels)39 AudioPacketizer(uint32_t aPacketSize, uint32_t aChannels) 40 : mPacketSize(aPacketSize), 41 mChannels(aChannels), 42 mReadIndex(0), 43 mWriteIndex(0), 44 // Start off with a single packet 45 mStorage(new InputType[aPacketSize * aChannels]), 46 mLength(aPacketSize * aChannels) { 47 MOZ_ASSERT(aPacketSize > 0 && aChannels > 0, 48 "The packet size and the number of channel should be strictly " 49 "positive"); 50 } 51 Input(const InputType * aFrames,uint32_t aFrameCount)52 void Input(const InputType* aFrames, uint32_t aFrameCount) { 53 uint32_t inputSamples = aFrameCount * mChannels; 54 // Need to grow the storage. This should rarely happen, if at all, once the 55 // array has the right size. 56 if (inputSamples > EmptySlots()) { 57 // Calls to Input and Output are roughtly interleaved 58 // (Input,Output,Input,Output, etc.), or balanced 59 // (Input,Input,Input,Output,Output,Output), so we update the buffer to 60 // the exact right size in order to not waste space. 61 uint32_t newLength = AvailableSamples() + inputSamples; 62 uint32_t toCopy = AvailableSamples(); 63 UniquePtr<InputType[]> oldStorage = std::move(mStorage); 64 mStorage = mozilla::MakeUnique<InputType[]>(newLength); 65 // Copy the old data at the beginning of the new storage. 66 if (WriteIndex() >= ReadIndex()) { 67 PodCopy(mStorage.get(), oldStorage.get() + ReadIndex(), 68 AvailableSamples()); 69 } else { 70 uint32_t firstPartLength = mLength - ReadIndex(); 71 uint32_t secondPartLength = AvailableSamples() - firstPartLength; 72 PodCopy(mStorage.get(), oldStorage.get() + ReadIndex(), 73 firstPartLength); 74 PodCopy(mStorage.get() + firstPartLength, oldStorage.get(), 75 secondPartLength); 76 } 77 mWriteIndex = toCopy; 78 mReadIndex = 0; 79 mLength = newLength; 80 } 81 82 if (WriteIndex() + inputSamples <= mLength) { 83 PodCopy(mStorage.get() + WriteIndex(), aFrames, aFrameCount * mChannels); 84 } else { 85 uint32_t firstPartLength = mLength - WriteIndex(); 86 uint32_t secondPartLength = inputSamples - firstPartLength; 87 PodCopy(mStorage.get() + WriteIndex(), aFrames, firstPartLength); 88 PodCopy(mStorage.get(), aFrames + firstPartLength, secondPartLength); 89 } 90 91 mWriteIndex += inputSamples; 92 } 93 Output()94 OutputType* Output() { 95 uint32_t samplesNeeded = mPacketSize * mChannels; 96 OutputType* out = new OutputType[samplesNeeded]; 97 98 Output(out); 99 100 return out; 101 } 102 Output(OutputType * aOutputBuffer)103 void Output(OutputType* aOutputBuffer) { 104 uint32_t samplesNeeded = mPacketSize * mChannels; 105 106 // Under-run. Pad the end of the buffer with silence. 107 if (AvailableSamples() < samplesNeeded) { 108 #ifdef LOG_PACKETIZER_UNDERRUN 109 char buf[256]; 110 snprintf(buf, 256, 111 "AudioPacketizer %p underrun: available: %u, needed: %u\n", this, 112 AvailableSamples(), samplesNeeded); 113 NS_WARNING(buf); 114 #endif 115 uint32_t zeros = samplesNeeded - AvailableSamples(); 116 PodZero(aOutputBuffer + AvailableSamples(), zeros); 117 samplesNeeded -= zeros; 118 } 119 if (ReadIndex() + samplesNeeded <= mLength) { 120 ConvertAudioSamples<InputType, OutputType>(mStorage.get() + ReadIndex(), 121 aOutputBuffer, samplesNeeded); 122 } else { 123 uint32_t firstPartLength = mLength - ReadIndex(); 124 uint32_t secondPartLength = samplesNeeded - firstPartLength; 125 ConvertAudioSamples<InputType, OutputType>( 126 mStorage.get() + ReadIndex(), aOutputBuffer, firstPartLength); 127 ConvertAudioSamples<InputType, OutputType>( 128 mStorage.get(), aOutputBuffer + firstPartLength, secondPartLength); 129 } 130 mReadIndex += samplesNeeded; 131 } 132 Clear()133 void Clear() { 134 mReadIndex = 0; 135 mWriteIndex = 0; 136 } 137 PacketsAvailable()138 uint32_t PacketsAvailable() const { 139 return AvailableSamples() / mChannels / mPacketSize; 140 } 141 FramesAvailable()142 uint32_t FramesAvailable() const { return AvailableSamples() / mChannels; } 143 Empty()144 bool Empty() const { return mWriteIndex == mReadIndex; } 145 Full()146 bool Full() const { return mWriteIndex - mReadIndex == mLength; } 147 148 // Size of one packet of audio, in frames 149 const uint32_t mPacketSize; 150 // Number of channels of the stream flowing through this packetizer 151 const uint32_t mChannels; 152 153 private: ReadIndex()154 uint32_t ReadIndex() const { return mReadIndex % mLength; } 155 WriteIndex()156 uint32_t WriteIndex() const { return mWriteIndex % mLength; } 157 AvailableSamples()158 uint32_t AvailableSamples() const { return mWriteIndex - mReadIndex; } 159 EmptySlots()160 uint32_t EmptySlots() const { return mLength - AvailableSamples(); } 161 162 // Two virtual index into the buffer: the read position and the write 163 // position. 164 uint64_t mReadIndex; 165 uint64_t mWriteIndex; 166 // Storage for the samples 167 mozilla::UniquePtr<InputType[]> mStorage; 168 // Length of the buffer, in samples 169 uint32_t mLength; 170 }; 171 172 } // namespace mozilla 173 174 #endif // AudioPacketizer_h_ 175