Backed out changeset 06f41c22f3a6 (bug 1888460) for causing linux xpcshell failures...
[gecko.git] / dom / media / AudioBufferUtils.h
blob3d0d1e9b6b2674198ca150821e00e9b952a9ef5f
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 MOZILLA_SCRATCHBUFFER_H_
7 #define MOZILLA_SCRATCHBUFFER_H_
9 #include "AudioSegment.h"
10 #include "mozilla/PodOperations.h"
11 #include "mozilla/UniquePtr.h"
12 #include "nsDebug.h"
14 #include <algorithm>
16 namespace mozilla {
18 /**
19 * The classes in this file provide a interface that uses frames as a unit.
20 * However, they store their offsets in samples (because it's handy for pointer
21 * operations). Those functions can convert between the two units.
23 static inline uint32_t FramesToSamples(uint32_t aChannels, uint32_t aFrames) {
24 return aFrames * aChannels;
27 static inline uint32_t SamplesToFrames(uint32_t aChannels, uint32_t aSamples) {
28 MOZ_ASSERT(!(aSamples % aChannels), "Frame alignment is wrong.");
29 return aSamples / aChannels;
32 /**
33 * Class that gets a buffer pointer from an audio callback and provides a safe
34 * interface to manipulate this buffer, and to ensure we are not missing frames
35 * by the end of the callback.
37 template <typename T>
38 class AudioCallbackBufferWrapper {
39 public:
40 AudioCallbackBufferWrapper()
41 : mBuffer(nullptr), mSamples(0), mSampleWriteOffset(1), mChannels(0) {}
43 explicit AudioCallbackBufferWrapper(uint32_t aChannels)
44 : mBuffer(nullptr),
45 mSamples(0),
46 mSampleWriteOffset(1),
47 mChannels(aChannels)
50 MOZ_ASSERT(aChannels);
53 AudioCallbackBufferWrapper& operator=(
54 const AudioCallbackBufferWrapper& aOther) {
55 MOZ_ASSERT(!aOther.mBuffer,
56 "Don't use this ctor after AudioCallbackDriver::Init");
57 MOZ_ASSERT(aOther.mSamples == 0,
58 "Don't use this ctor after AudioCallbackDriver::Init");
59 MOZ_ASSERT(aOther.mSampleWriteOffset == 1,
60 "Don't use this ctor after AudioCallbackDriver::Init");
61 MOZ_ASSERT(aOther.mChannels != 0);
63 mBuffer = nullptr;
64 mSamples = 0;
65 mSampleWriteOffset = 1;
66 mChannels = aOther.mChannels;
68 return *this;
71 /**
72 * Set the buffer in this wrapper. This is to be called at the beginning of
73 * the callback.
75 void SetBuffer(T* aBuffer, uint32_t aFrames) {
76 MOZ_ASSERT(!mBuffer && !mSamples, "SetBuffer called twice.");
77 mBuffer = aBuffer;
78 mSamples = FramesToSamples(mChannels, aFrames);
79 mSampleWriteOffset = 0;
82 /**
83 * Write some frames to the internal buffer. Free space in the buffer should
84 * be checked prior to calling these.
86 void WriteFrames(T* aBuffer, uint32_t aFrames) {
87 MOZ_ASSERT(aFrames <= Available(),
88 "Writing more that we can in the audio buffer.");
90 PodCopy(mBuffer + mSampleWriteOffset, aBuffer,
91 FramesToSamples(mChannels, aFrames));
92 mSampleWriteOffset += FramesToSamples(mChannels, aFrames);
94 void WriteFrames(const AudioChunk& aChunk, uint32_t aFrames) {
95 MOZ_ASSERT(aFrames <= Available(),
96 "Writing more that we can in the audio buffer.");
98 InterleaveAndConvertBuffer(aChunk.ChannelData<T>().Elements(), aFrames,
99 aChunk.mVolume, aChunk.ChannelCount(),
100 mBuffer + mSampleWriteOffset);
101 mSampleWriteOffset += FramesToSamples(mChannels, aFrames);
105 * Number of frames that can be written to the buffer.
107 uint32_t Available() {
108 return SamplesToFrames(mChannels, mSamples - mSampleWriteOffset);
112 * Check that the buffer is completly filled, and reset internal state so this
113 * instance can be reused.
115 void BufferFilled() {
116 MOZ_ASSERT(Available() == 0, "Frames should have been written");
117 MOZ_ASSERT(mBuffer, "Buffer not set.");
118 mSamples = 0;
119 mSampleWriteOffset = 0;
120 mBuffer = nullptr;
123 private:
124 /* This is not an owned pointer, but the pointer passed to use via the audio
125 * callback. */
126 T* mBuffer;
127 /* The number of samples of this audio buffer. */
128 uint32_t mSamples;
129 /* The position at which new samples should be written. We want to return to
130 * the audio callback iff this is equal to mSamples. */
131 uint32_t mSampleWriteOffset;
132 uint32_t mChannels;
136 * This is a class that interfaces with the AudioCallbackBufferWrapper, and is
137 * responsible for storing the excess of data produced by the MediaTrackGraph
138 * because of different rounding constraints, to be used the next time the audio
139 * backend calls back.
141 template <typename T, uint32_t BLOCK_SIZE>
142 class SpillBuffer {
143 public:
144 SpillBuffer() : mBuffer(nullptr), mPosition(0), mChannels(0) {}
146 explicit SpillBuffer(uint32_t aChannels)
147 : mPosition(0), mChannels(aChannels) {
148 MOZ_ASSERT(aChannels);
149 mBuffer = MakeUnique<T[]>(BLOCK_SIZE * mChannels);
150 PodZero(mBuffer.get(), BLOCK_SIZE * mChannels);
153 SpillBuffer& operator=(SpillBuffer& aOther) {
154 MOZ_ASSERT(aOther.mPosition == 0,
155 "Don't use this ctor after AudioCallbackDriver::Init");
156 MOZ_ASSERT(aOther.mChannels != 0);
157 MOZ_ASSERT(aOther.mBuffer);
159 mPosition = aOther.mPosition;
160 mChannels = aOther.mChannels;
161 mBuffer = std::move(aOther.mBuffer);
163 return *this;
166 SpillBuffer& operator=(SpillBuffer&& aOther) {
167 return this->operator=(aOther);
170 /* Empty the spill buffer into the buffer of the audio callback. This returns
171 * the number of frames written. */
172 uint32_t Empty(AudioCallbackBufferWrapper<T>& aBuffer) {
173 uint32_t framesToWrite =
174 std::min(aBuffer.Available(), SamplesToFrames(mChannels, mPosition));
176 aBuffer.WriteFrames(mBuffer.get(), framesToWrite);
178 mPosition -= FramesToSamples(mChannels, framesToWrite);
179 // If we didn't empty the spill buffer for some reason, shift the remaining
180 // data down
181 if (mPosition > 0) {
182 MOZ_ASSERT(FramesToSamples(mChannels, framesToWrite) + mPosition <=
183 BLOCK_SIZE * mChannels);
184 PodMove(mBuffer.get(),
185 mBuffer.get() + FramesToSamples(mChannels, framesToWrite),
186 mPosition);
189 return framesToWrite;
191 /* Fill the spill buffer from aInput.
192 * Return the number of frames written to the spill buffer */
193 uint32_t Fill(const AudioChunk& aInput) {
194 uint32_t framesToWrite =
195 std::min(static_cast<uint32_t>(aInput.mDuration),
196 BLOCK_SIZE - SamplesToFrames(mChannels, mPosition));
198 MOZ_ASSERT(FramesToSamples(mChannels, framesToWrite) + mPosition <=
199 BLOCK_SIZE * mChannels);
200 InterleaveAndConvertBuffer(
201 aInput.ChannelData<T>().Elements(), framesToWrite, aInput.mVolume,
202 aInput.ChannelCount(), mBuffer.get() + mPosition);
204 mPosition += FramesToSamples(mChannels, framesToWrite);
206 return framesToWrite;
209 private:
210 /* The spilled data. */
211 UniquePtr<T[]> mBuffer;
212 /* The current write position, in samples, in the buffer when filling, or the
213 * amount of buffer filled when emptying. */
214 uint32_t mPosition;
215 uint32_t mChannels;
218 } // namespace mozilla
220 #endif // MOZILLA_SCRATCHBUFFER_H_