Bug 1685822 [wpt PR 27117] - [Import Maps] Add tests for rejecting multiple import...
[gecko.git] / dom / media / AudioPacketizer.h
blob8df04c0c5c99fa5bf5824176596c29889a5a6b8f
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/. */
6 #ifndef AudioPacketizer_h_
7 #define AudioPacketizer_h_
9 #include <mozilla/PodOperations.h>
10 #include <mozilla/Assertions.h>
11 #include <mozilla/UniquePtr.h>
12 #include <AudioSampleFormat.h>
14 // Enable this to warn when `Output` has been called but not enough data was
15 // buffered.
16 // #define LOG_PACKETIZER_UNDERRUN
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).
24 * Input and output, as well as length units in the public interface are
25 * interleaved frames.
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
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.
34 * The implementation uses a circular buffer using absolute virtual indices.
36 template <typename InputType, typename OutputType>
37 class AudioPacketizer {
38 public:
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");
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);
77 mWriteIndex = toCopy;
78 mReadIndex = 0;
79 mLength = newLength;
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);
91 mWriteIndex += inputSamples;
94 OutputType* Output() {
95 uint32_t samplesNeeded = mPacketSize * mChannels;
96 OutputType* out = new OutputType[samplesNeeded];
98 Output(out);
100 return out;
103 void Output(OutputType* aOutputBuffer) {
104 uint32_t samplesNeeded = mPacketSize * mChannels;
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;
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);
130 mReadIndex += samplesNeeded;
133 void Clear() {
134 mReadIndex = 0;
135 mWriteIndex = 0;
138 uint32_t PacketsAvailable() const {
139 return AvailableSamples() / mChannels / mPacketSize;
142 uint32_t FramesAvailable() const { return AvailableSamples() / mChannels; }
144 bool Empty() const { return mWriteIndex == mReadIndex; }
146 bool Full() const { return mWriteIndex - mReadIndex == mLength; }
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;
153 private:
154 uint32_t ReadIndex() const { return mReadIndex % mLength; }
156 uint32_t WriteIndex() const { return mWriteIndex % mLength; }
158 uint32_t AvailableSamples() const { return mWriteIndex - mReadIndex; }
160 uint32_t EmptySlots() const { return mLength - AvailableSamples(); }
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;
172 } // namespace mozilla
174 #endif // AudioPacketizer_h_