no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / media / AudioBufferUtils.h
blob97b1956f7016c3b878db5c19109afe83bad1184d
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 "mozilla/PodOperations.h"
10 #include "mozilla/UniquePtr.h"
11 #include "nsDebug.h"
13 #include <algorithm>
15 namespace mozilla {
17 /**
18 * The classes in this file provide a interface that uses frames as a unit.
19 * However, they store their offsets in samples (because it's handy for pointer
20 * operations). Those functions can convert between the two units.
22 static inline uint32_t FramesToSamples(uint32_t aChannels, uint32_t aFrames) {
23 return aFrames * aChannels;
26 static inline uint32_t SamplesToFrames(uint32_t aChannels, uint32_t aSamples) {
27 MOZ_ASSERT(!(aSamples % aChannels), "Frame alignment is wrong.");
28 return aSamples / aChannels;
31 /**
32 * Class that gets a buffer pointer from an audio callback and provides a safe
33 * interface to manipulate this buffer, and to ensure we are not missing frames
34 * by the end of the callback.
36 template <typename T>
37 class AudioCallbackBufferWrapper {
38 public:
39 AudioCallbackBufferWrapper()
40 : mBuffer(nullptr), mSamples(0), mSampleWriteOffset(1), mChannels(0) {}
42 explicit AudioCallbackBufferWrapper(uint32_t aChannels)
43 : mBuffer(nullptr),
44 mSamples(0),
45 mSampleWriteOffset(1),
46 mChannels(aChannels)
49 MOZ_ASSERT(aChannels);
52 AudioCallbackBufferWrapper& operator=(
53 const AudioCallbackBufferWrapper& aOther) {
54 MOZ_ASSERT(!aOther.mBuffer,
55 "Don't use this ctor after AudioCallbackDriver::Init");
56 MOZ_ASSERT(aOther.mSamples == 0,
57 "Don't use this ctor after AudioCallbackDriver::Init");
58 MOZ_ASSERT(aOther.mSampleWriteOffset == 1,
59 "Don't use this ctor after AudioCallbackDriver::Init");
60 MOZ_ASSERT(aOther.mChannels != 0);
62 mBuffer = nullptr;
63 mSamples = 0;
64 mSampleWriteOffset = 1;
65 mChannels = aOther.mChannels;
67 return *this;
70 /**
71 * Set the buffer in this wrapper. This is to be called at the beginning of
72 * the callback.
74 void SetBuffer(T* aBuffer, uint32_t aFrames) {
75 MOZ_ASSERT(!mBuffer && !mSamples, "SetBuffer called twice.");
76 mBuffer = aBuffer;
77 mSamples = FramesToSamples(mChannels, aFrames);
78 mSampleWriteOffset = 0;
81 /**
82 * Write some frames to the internal buffer. Free space in the buffer should
83 * be check prior to calling this.
85 void WriteFrames(T* aBuffer, uint32_t aFrames) {
86 MOZ_ASSERT(aFrames <= Available(),
87 "Writing more that we can in the audio buffer.");
89 PodCopy(mBuffer + mSampleWriteOffset, aBuffer,
90 FramesToSamples(mChannels, aFrames));
91 mSampleWriteOffset += FramesToSamples(mChannels, aFrames);
94 /**
95 * Number of frames that can be written to the buffer.
97 uint32_t Available() {
98 return SamplesToFrames(mChannels, mSamples - mSampleWriteOffset);
102 * Check that the buffer is completly filled, and reset internal state so this
103 * instance can be reused.
105 void BufferFilled() {
106 MOZ_ASSERT(Available() == 0, "Frames should have been written");
107 MOZ_ASSERT(mBuffer, "Buffer not set.");
108 mSamples = 0;
109 mSampleWriteOffset = 0;
110 mBuffer = nullptr;
113 private:
114 /* This is not an owned pointer, but the pointer passed to use via the audio
115 * callback. */
116 T* mBuffer;
117 /* The number of samples of this audio buffer. */
118 uint32_t mSamples;
119 /* The position at which new samples should be written. We want to return to
120 * the audio callback iff this is equal to mSamples. */
121 uint32_t mSampleWriteOffset;
122 uint32_t mChannels;
126 * This is a class that interfaces with the AudioCallbackBufferWrapper, and is
127 * responsible for storing the excess of data produced by the MediaTrackGraph
128 * because of different rounding constraints, to be used the next time the audio
129 * backend calls back.
131 template <typename T, uint32_t BLOCK_SIZE>
132 class SpillBuffer {
133 public:
134 SpillBuffer() : mBuffer(nullptr), mPosition(0), mChannels(0) {}
136 explicit SpillBuffer(uint32_t aChannels)
137 : mPosition(0), mChannels(aChannels) {
138 MOZ_ASSERT(aChannels);
139 mBuffer = MakeUnique<T[]>(BLOCK_SIZE * mChannels);
140 PodZero(mBuffer.get(), BLOCK_SIZE * mChannels);
143 SpillBuffer& operator=(SpillBuffer& aOther) {
144 MOZ_ASSERT(aOther.mPosition == 0,
145 "Don't use this ctor after AudioCallbackDriver::Init");
146 MOZ_ASSERT(aOther.mChannels != 0);
147 MOZ_ASSERT(aOther.mBuffer);
149 mPosition = aOther.mPosition;
150 mChannels = aOther.mChannels;
151 mBuffer = std::move(aOther.mBuffer);
153 return *this;
156 SpillBuffer& operator=(SpillBuffer&& aOther) {
157 return this->operator=(aOther);
160 /* Empty the spill buffer into the buffer of the audio callback. This returns
161 * the number of frames written. */
162 uint32_t Empty(AudioCallbackBufferWrapper<T>& aBuffer) {
163 uint32_t framesToWrite =
164 std::min(aBuffer.Available(), SamplesToFrames(mChannels, mPosition));
166 aBuffer.WriteFrames(mBuffer.get(), framesToWrite);
168 mPosition -= FramesToSamples(mChannels, framesToWrite);
169 // If we didn't empty the spill buffer for some reason, shift the remaining
170 // data down
171 if (mPosition > 0) {
172 MOZ_ASSERT(FramesToSamples(mChannels, framesToWrite) + mPosition <=
173 BLOCK_SIZE * mChannels);
174 PodMove(mBuffer.get(),
175 mBuffer.get() + FramesToSamples(mChannels, framesToWrite),
176 mPosition);
179 return framesToWrite;
181 /* Fill the spill buffer from aInput, containing aFrames frames, return the
182 * number of frames written to the spill buffer */
183 uint32_t Fill(T* aInput, uint32_t aFrames) {
184 uint32_t framesToWrite =
185 std::min(aFrames, BLOCK_SIZE - SamplesToFrames(mChannels, mPosition));
187 MOZ_ASSERT(FramesToSamples(mChannels, framesToWrite) + mPosition <=
188 BLOCK_SIZE * mChannels);
189 PodCopy(mBuffer.get() + mPosition, aInput,
190 FramesToSamples(mChannels, framesToWrite));
192 mPosition += FramesToSamples(mChannels, framesToWrite);
194 return framesToWrite;
197 private:
198 /* The spilled data. */
199 UniquePtr<T[]> mBuffer;
200 /* The current write position, in samples, in the buffer when filling, or the
201 * amount of buffer filled when emptying. */
202 uint32_t mPosition;
203 uint32_t mChannels;
206 } // namespace mozilla
208 #endif // MOZILLA_SCRATCHBUFFER_H_