Line data Source code
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 MOZILLA_SCRATCHBUFFER_H_
7 : #define MOZILLA_SCRATCHBUFFER_H_
8 : #include <mozilla/PodOperations.h>
9 : #include <algorithm>
10 :
11 : namespace mozilla {
12 :
13 : /**
14 : * The classes in this file provide a interface that uses frames as a unit.
15 : * However, they store their offsets in samples (because it's handy for pointer
16 : * operations). Those functions can convert between the two units.
17 : */
18 0 : static inline uint32_t FramesToSamples(uint32_t aChannels, uint32_t aFrames) {
19 0 : return aFrames * aChannels;
20 : }
21 :
22 0 : static inline uint32_t SamplesToFrames(uint32_t aChannels, uint32_t aSamples) {
23 0 : MOZ_ASSERT(!(aSamples % aChannels), "Frame alignment is wrong.");
24 0 : return aSamples / aChannels;
25 : }
26 :
27 : /**
28 : * Class that gets a buffer pointer from an audio callback and provides a safe
29 : * interface to manipulate this buffer, and to ensure we are not missing frames
30 : * by the end of the callback.
31 : */
32 : template<typename T, uint32_t CHANNELS>
33 : class AudioCallbackBufferWrapper
34 : {
35 : public:
36 0 : AudioCallbackBufferWrapper()
37 : : mBuffer(nullptr),
38 : mSamples(0),
39 0 : mSampleWriteOffset(1)
40 0 : {}
41 : /**
42 : * Set the buffer in this wrapper. This is to be called at the beginning of
43 : * the callback.
44 : */
45 0 : void SetBuffer(T* aBuffer, uint32_t aFrames) {
46 0 : MOZ_ASSERT(!mBuffer && !mSamples,
47 : "SetBuffer called twice.");
48 0 : mBuffer = aBuffer;
49 0 : mSamples = FramesToSamples(CHANNELS, aFrames);
50 0 : mSampleWriteOffset = 0;
51 0 : }
52 :
53 : /**
54 : * Write some frames to the internal buffer. Free space in the buffer should
55 : * be check prior to calling this.
56 : */
57 0 : void WriteFrames(T* aBuffer, uint32_t aFrames) {
58 0 : MOZ_ASSERT(aFrames <= Available(),
59 : "Writing more that we can in the audio buffer.");
60 :
61 0 : PodCopy(mBuffer + mSampleWriteOffset, aBuffer, FramesToSamples(CHANNELS,
62 : aFrames));
63 0 : mSampleWriteOffset += FramesToSamples(CHANNELS, aFrames);
64 0 : }
65 :
66 : /**
67 : * Number of frames that can be written to the buffer.
68 : */
69 0 : uint32_t Available() {
70 0 : return SamplesToFrames(CHANNELS, mSamples - mSampleWriteOffset);
71 : }
72 :
73 : /**
74 : * Check that the buffer is completly filled, and reset internal state so this
75 : * instance can be reused.
76 : */
77 0 : void BufferFilled() {
78 : // It's okay to have exactly zero samples here, it can happen we have an
79 : // audio callback driver because of a hint on MSG creation, but the
80 : // AudioOutputStream has not been created yet, or if all the streams have finished
81 : // but we're still running.
82 : // Note: it's also ok if we had data in the scratch buffer - and we usually do - and
83 : // all the streams were ended (no mixer callback occured).
84 : // XXX Remove this warning, or find a way to avoid it if the mixer callback
85 : // isn't called.
86 0 : NS_WARNING_ASSERTION(
87 : Available() == 0 || mSampleWriteOffset == 0,
88 : "Audio Buffer is not full by the end of the callback.");
89 : // Make sure the data returned is always set and not random!
90 0 : if (Available()) {
91 0 : PodZero(mBuffer + mSampleWriteOffset, FramesToSamples(CHANNELS, Available()));
92 : }
93 0 : MOZ_ASSERT(mSamples, "Buffer not set.");
94 0 : mSamples = 0;
95 0 : mSampleWriteOffset = 0;
96 0 : mBuffer = nullptr;
97 0 : }
98 :
99 : private:
100 : /* This is not an owned pointer, but the pointer passed to use via the audio
101 : * callback. */
102 : T* mBuffer;
103 : /* The number of samples of this audio buffer. */
104 : uint32_t mSamples;
105 : /* The position at which new samples should be written. We want to return to
106 : * the audio callback iff this is equal to mSamples. */
107 : uint32_t mSampleWriteOffset;
108 : };
109 :
110 : /**
111 : * This is a class that interfaces with the AudioCallbackBufferWrapper, and is
112 : * responsible for storing the excess of data produced by the MediaStreamGraph
113 : * because of different rounding constraints, to be used the next time the audio
114 : * backend calls back.
115 : */
116 : template<typename T, uint32_t BLOCK_SIZE, uint32_t CHANNELS>
117 : class SpillBuffer
118 : {
119 : public:
120 0 : SpillBuffer()
121 0 : : mPosition(0)
122 : {
123 0 : PodArrayZero(mBuffer);
124 0 : }
125 : /* Empty the spill buffer into the buffer of the audio callback. This returns
126 : * the number of frames written. */
127 0 : uint32_t Empty(AudioCallbackBufferWrapper<T, CHANNELS>& aBuffer) {
128 0 : uint32_t framesToWrite = std::min(aBuffer.Available(),
129 0 : SamplesToFrames(CHANNELS, mPosition));
130 :
131 0 : aBuffer.WriteFrames(mBuffer, framesToWrite);
132 :
133 0 : mPosition -= FramesToSamples(CHANNELS, framesToWrite);
134 : // If we didn't empty the spill buffer for some reason, shift the remaining data down
135 0 : if (mPosition > 0) {
136 0 : PodMove(mBuffer, mBuffer + FramesToSamples(CHANNELS, framesToWrite),
137 0 : mPosition);
138 : }
139 :
140 0 : return framesToWrite;
141 : }
142 : /* Fill the spill buffer from aInput, containing aFrames frames, return the
143 : * number of frames written to the spill buffer */
144 0 : uint32_t Fill(T* aInput, uint32_t aFrames) {
145 : uint32_t framesToWrite = std::min(aFrames,
146 0 : BLOCK_SIZE - SamplesToFrames(CHANNELS,
147 0 : mPosition));
148 :
149 0 : PodCopy(mBuffer + mPosition, aInput, FramesToSamples(CHANNELS,
150 : framesToWrite));
151 :
152 0 : mPosition += FramesToSamples(CHANNELS, framesToWrite);
153 :
154 0 : return framesToWrite;
155 : }
156 : private:
157 : /* The spilled data. */
158 : T mBuffer[BLOCK_SIZE * CHANNELS];
159 : /* The current write position, in samples, in the buffer when filling, or the
160 : * amount of buffer filled when emptying. */
161 : uint32_t mPosition;
162 : };
163 :
164 : } // namespace mozilla
165 :
166 : #endif // MOZILLA_SCRATCHBUFFER_H_
|