Backed out changeset 06f41c22f3a6 (bug 1888460) for causing linux xpcshell failures...
[gecko.git] / dom / media / AudioRingBuffer.cpp
blob475de653b8602cdb336b16598130e4cd7ff96e0c
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 #include "AudioRingBuffer.h"
8 #include "MediaData.h"
9 #include "mozilla/Assertions.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/PodOperations.h"
13 namespace mozilla {
15 /**
16 * RingBuffer is used to preallocate a buffer of a specific size in bytes and
17 * then to use it for writing and reading values without requiring re-allocation
18 * or memory moving. Note that re-allocations can happen if the length of the
19 * buffer is explicitly set to something larger than is already allocated.
20 * Also note that the total byte size of the buffer modulo the size of the
21 * chosen type must be zero. The RingBuffer has been created with audio sample
22 * values types in mind which are integer or float. However, it can be used with
23 * any trivial type. It is _not_ thread-safe! The constructor can be called on
24 * any thread but the reads and write must happen on the same thread, which can
25 * be different than the construction thread.
27 template <typename T>
28 class RingBuffer final {
29 public:
30 explicit RingBuffer(AlignedByteBuffer&& aMemoryBuffer)
31 : mStorage(ConvertToSpan(aMemoryBuffer)),
32 mMemoryBuffer(std::move(aMemoryBuffer)) {
33 MOZ_ASSERT(std::is_trivial<T>::value);
36 /**
37 * Write `aSamples` number of zeros in the buffer, before any existing data.
39 uint32_t PrependSilence(uint32_t aSamples) {
40 MOZ_ASSERT(aSamples);
41 return Prepend(Span<T>(), aSamples);
44 /**
45 * Write `aSamples` number of zeros in the buffer.
47 uint32_t WriteSilence(uint32_t aSamples) {
48 MOZ_ASSERT(aSamples);
49 return Write(Span<T>(), aSamples);
52 /**
53 * Copy `aBuffer` to the RingBuffer.
55 uint32_t Write(const Span<const T>& aBuffer) {
56 MOZ_ASSERT(!aBuffer.IsEmpty());
57 return Write(aBuffer, aBuffer.Length());
60 private:
61 /**
62 * Copy `aSamples` number of elements from `aBuffer` to the beginning of the
63 * RingBuffer. If `aBuffer` is empty prepend `aSamples` of zeros.
65 uint32_t Prepend(const Span<const T>& aBuffer, uint32_t aSamples) {
66 MOZ_ASSERT(aSamples > 0);
67 MOZ_ASSERT(aBuffer.IsEmpty() || aBuffer.Length() == aSamples);
69 if (IsFull()) {
70 return 0;
73 uint32_t toWrite = std::min(AvailableWrite(), aSamples);
74 uint32_t part2 = std::min(mReadIndex, toWrite);
75 uint32_t part1 = toWrite - part2;
77 Span<T> part2Buffer = mStorage.Subspan(mReadIndex - part2, part2);
78 Span<T> part1Buffer = mStorage.Subspan(Capacity() - part1, part1);
80 if (!aBuffer.IsEmpty()) {
81 Span<const T> fromPart1 = aBuffer.To(part1);
82 Span<const T> fromPart2 = aBuffer.Subspan(part1, part2);
84 CopySpan(part1Buffer, fromPart1);
85 CopySpan(part2Buffer, fromPart2);
86 } else {
87 // aBuffer is empty, prepend zeros.
88 PodZero(part1Buffer.Elements(), part1Buffer.Length());
89 PodZero(part2Buffer.Elements(), part2Buffer.Length());
92 mReadIndex = NextIndex(mReadIndex, Capacity() - toWrite);
94 return toWrite;
97 /**
98 * Copy `aSamples` number of elements from `aBuffer` to the RingBuffer. If
99 * `aBuffer` is empty append `aSamples` of zeros.
101 uint32_t Write(const Span<const T>& aBuffer, uint32_t aSamples) {
102 MOZ_ASSERT(aSamples > 0);
103 MOZ_ASSERT(aBuffer.IsEmpty() || aBuffer.Length() == aSamples);
105 if (IsFull()) {
106 return 0;
109 uint32_t toWrite = std::min(AvailableWrite(), aSamples);
110 uint32_t part1 = std::min(Capacity() - mWriteIndex, toWrite);
111 uint32_t part2 = toWrite - part1;
113 Span<T> part1Buffer = mStorage.Subspan(mWriteIndex, part1);
114 Span<T> part2Buffer = mStorage.To(part2);
116 if (!aBuffer.IsEmpty()) {
117 Span<const T> fromPart1 = aBuffer.To(part1);
118 Span<const T> fromPart2 = aBuffer.Subspan(part1, part2);
120 CopySpan(part1Buffer, fromPart1);
121 CopySpan(part2Buffer, fromPart2);
122 } else {
123 // The aBuffer is empty, append zeros.
124 PodZero(part1Buffer.Elements(), part1Buffer.Length());
125 PodZero(part2Buffer.Elements(), part2Buffer.Length());
128 mWriteIndex = NextIndex(mWriteIndex, toWrite);
130 return toWrite;
133 public:
135 * Copy `aSamples` number of elements from `aBuffer` to the RingBuffer. The
136 * `aBuffer` does not change.
138 uint32_t Write(const RingBuffer& aBuffer, uint32_t aSamples) {
139 MOZ_ASSERT(aSamples);
141 if (IsFull()) {
142 return 0;
145 uint32_t toWriteThis = std::min(AvailableWrite(), aSamples);
146 uint32_t toReadThat = std::min(aBuffer.AvailableRead(), toWriteThis);
147 uint32_t part1 =
148 std::min(aBuffer.Capacity() - aBuffer.mReadIndex, toReadThat);
149 uint32_t part2 = toReadThat - part1;
151 Span<T> part1Buffer = aBuffer.mStorage.Subspan(aBuffer.mReadIndex, part1);
152 DebugOnly<uint32_t> ret = Write(part1Buffer);
153 MOZ_ASSERT(ret == part1);
154 if (part2) {
155 Span<T> part2Buffer = aBuffer.mStorage.To(part2);
156 ret = Write(part2Buffer);
157 MOZ_ASSERT(ret == part2);
160 return toReadThat;
164 * Copy `aBuffer.Length()` number of elements from RingBuffer to `aBuffer`.
166 uint32_t Read(const Span<T>& aBuffer) {
167 MOZ_ASSERT(!aBuffer.IsEmpty());
168 MOZ_ASSERT(aBuffer.size() <= std::numeric_limits<uint32_t>::max());
170 if (IsEmpty()) {
171 return 0;
174 uint32_t toRead = std::min<uint32_t>(AvailableRead(), aBuffer.Length());
175 uint32_t part1 = std::min(Capacity() - mReadIndex, toRead);
176 uint32_t part2 = toRead - part1;
178 Span<T> part1Buffer = mStorage.Subspan(mReadIndex, part1);
179 Span<T> part2Buffer = mStorage.To(part2);
181 Span<T> toPart1 = aBuffer.To(part1);
182 Span<T> toPart2 = aBuffer.Subspan(part1, part2);
184 CopySpan(toPart1, part1Buffer);
185 CopySpan(toPart2, part2Buffer);
187 mReadIndex = NextIndex(mReadIndex, toRead);
189 return toRead;
193 * Provide `aCallable` that will be called with the internal linear read
194 * buffers and the number of samples available for reading. The `aCallable`
195 * will be called at most 2 times. The `aCallable` must return the number of
196 * samples that have been actually read. If that number is smaller than the
197 * available number of samples, provided in the argument, the `aCallable` will
198 * not be called again. The RingBuffer's available read samples will be
199 * decreased by the number returned from the `aCallable`.
201 * The important aspects of this method are that first, it makes it possible
202 * to avoid extra copies to an intermediates buffer, and second, each buffer
203 * provided to `aCallable is a linear piece of memory which can be used
204 * directly to a resampler for example.
206 * In general, the problem with ring buffers is that they cannot provide one
207 * linear chunk of memory so extra copies, to a linear buffer, are often
208 * needed. This method bridge that gap by breaking the ring buffer's
209 * internal read memory into linear pieces and making it available through
210 * the `aCallable`. In the body of the `aCallable` those buffers can be used
211 * directly without any copy or intermediate steps.
213 uint32_t ReadNoCopy(
214 std::function<uint32_t(const Span<const T>&)>&& aCallable) {
215 if (IsEmpty()) {
216 return 0;
219 uint32_t part1 = std::min(Capacity() - mReadIndex, AvailableRead());
220 uint32_t part2 = AvailableRead() - part1;
222 Span<T> part1Buffer = mStorage.Subspan(mReadIndex, part1);
223 uint32_t toRead = aCallable(part1Buffer);
224 MOZ_ASSERT(toRead <= part1);
226 if (toRead == part1 && part2) {
227 Span<T> part2Buffer = mStorage.To(part2);
228 toRead += aCallable(part2Buffer);
229 MOZ_ASSERT(toRead <= part1 + part2);
232 mReadIndex = NextIndex(mReadIndex, toRead);
234 return toRead;
238 * Remove the next `aSamples` number of samples from the ring buffer.
240 uint32_t Discard(uint32_t aSamples) {
241 MOZ_ASSERT(aSamples);
243 if (IsEmpty()) {
244 return 0;
247 uint32_t toDiscard = std::min(AvailableRead(), aSamples);
248 mReadIndex = NextIndex(mReadIndex, toDiscard);
250 return toDiscard;
254 * Empty the ring buffer.
256 uint32_t Clear() {
257 if (IsEmpty()) {
258 return 0;
261 uint32_t toDiscard = AvailableRead();
262 mReadIndex = NextIndex(mReadIndex, toDiscard);
264 return toDiscard;
268 * Set the ring buffer to the requested size. NB: In bytes.
270 * Re-allocates memory if a larger buffer is requested than what is already
271 * allocated.
273 bool SetLengthBytes(uint32_t aLengthBytes) {
274 MOZ_ASSERT(aLengthBytes % sizeof(T) == 0,
275 "Length in bytes is not a whole number of samples");
277 uint32_t lengthSamples = aLengthBytes / sizeof(T);
278 uint32_t oldLengthSamples = Capacity();
279 uint32_t availableRead = AvailableRead();
280 if (!mMemoryBuffer.SetLength(aLengthBytes)) {
281 return false;
284 // mStorage may now have been deallocated.
285 mStorage = ConvertToSpan(mMemoryBuffer);
286 if (mWriteIndex < mReadIndex) {
287 // The old data wrapped around the end of the (old) buffer. It needs to be
288 // moved so it is continuous.
289 const uint32_t toMove = mWriteIndex;
291 // The bit that goes between the old and the new end of the buffer.
292 const uint32_t toMove1 =
293 std::min(lengthSamples - oldLengthSamples, toMove);
295 // [0, toMove1) -> [oldLength, oldLength + toMove1).
296 Span<T> from1 = mStorage.Subspan(0, toMove1);
297 Span<T> to1 = mStorage.Subspan(oldLengthSamples, toMove1);
298 PodMove(to1.Elements(), from1.Elements(), toMove1);
301 // The last bit of data that starts at 0. Could be empty.
302 const uint32_t toMove2 = toMove - toMove1;
304 // [toMove1, toMove) -> [0, toMove2).
305 Span<T> from2 = mStorage.Subspan(toMove1, toMove2);
306 Span<T> to2 = mStorage.Subspan(0, toMove2);
307 PodMove(to2.Elements(), from2.Elements(), toMove2);
310 mWriteIndex = NextIndex(mReadIndex, availableRead);
313 return true;
317 * Returns true if the full capacity of the ring buffer is being used. When
318 * full any attempt to write more samples to the ring buffer will fail.
320 bool IsFull() const { return (mWriteIndex + 1) % Capacity() == mReadIndex; }
323 * Returns true if the ring buffer is empty. When empty any attempt to read
324 * more samples from the ring buffer will fail.
326 bool IsEmpty() const { return mWriteIndex == mReadIndex; }
329 * The number of samples available for writing.
331 uint32_t AvailableWrite() const {
332 /* We subtract one element here to always keep at least one sample
333 * free in the buffer, to distinguish between full and empty array. */
334 uint32_t rv = mReadIndex - mWriteIndex - 1;
335 if (mWriteIndex >= mReadIndex) {
336 rv += Capacity();
338 return rv;
342 * The number of samples available for reading.
344 uint32_t AvailableRead() const {
345 if (mWriteIndex >= mReadIndex) {
346 return mWriteIndex - mReadIndex;
348 return mWriteIndex + Capacity() - mReadIndex;
352 * The number of samples this ring buffer can hold.
354 uint32_t Capacity() const { return mStorage.Length(); }
356 private:
357 uint32_t NextIndex(uint32_t aIndex, uint32_t aStep) const {
358 MOZ_ASSERT(aStep < Capacity());
359 MOZ_ASSERT(aIndex < Capacity());
360 return (aIndex + aStep) % Capacity();
363 Span<T> ConvertToSpan(const AlignedByteBuffer& aOther) const {
364 MOZ_ASSERT(aOther.Length() % sizeof(T) == 0);
365 return Span<T>(reinterpret_cast<T*>(aOther.Data()),
366 aOther.Length() / sizeof(T));
369 void CopySpan(Span<T>& aTo, const Span<const T>& aFrom) {
370 MOZ_ASSERT(aTo.Length() == aFrom.Length());
371 std::copy(aFrom.cbegin(), aFrom.cend(), aTo.begin());
374 private:
375 uint32_t mReadIndex = 0;
376 uint32_t mWriteIndex = 0;
377 /* Points to the mMemoryBuffer. */
378 Span<T> mStorage;
379 /* The actual allocated memory set from outside. It is set in the ctor and it
380 * is not used again. It is here to control the lifetime of the memory. The
381 * memory is accessed through the mStorage. The idea is that the memory used
382 * from the RingBuffer can be pre-allocated. Note that a re-allocation will
383 * happen if the length in bytes is set to something larger than is already
384 * allocated. */
385 AlignedByteBuffer mMemoryBuffer;
388 /** AudioRingBuffer **/
390 /* The private members of AudioRingBuffer. */
391 class AudioRingBuffer::AudioRingBufferPrivate {
392 public:
393 AudioSampleFormat mSampleFormat = AUDIO_FORMAT_SILENCE;
394 Maybe<RingBuffer<float>> mFloatRingBuffer;
395 Maybe<RingBuffer<int16_t>> mIntRingBuffer;
396 Maybe<AlignedByteBuffer> mBackingBuffer;
399 AudioRingBuffer::AudioRingBuffer(uint32_t aSizeInBytes)
400 : mPtr(MakeUnique<AudioRingBufferPrivate>()) {
401 mPtr->mBackingBuffer.emplace(aSizeInBytes);
402 MOZ_ASSERT(mPtr->mBackingBuffer);
405 AudioRingBuffer::~AudioRingBuffer() = default;
407 void AudioRingBuffer::SetSampleFormat(AudioSampleFormat aFormat) {
408 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_SILENCE);
409 MOZ_ASSERT(aFormat == AUDIO_FORMAT_S16 || aFormat == AUDIO_FORMAT_FLOAT32);
410 MOZ_ASSERT(!mPtr->mIntRingBuffer);
411 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
412 MOZ_ASSERT(mPtr->mBackingBuffer);
414 mPtr->mSampleFormat = aFormat;
415 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
416 mPtr->mIntRingBuffer.emplace(mPtr->mBackingBuffer.extract());
417 MOZ_ASSERT(!mPtr->mBackingBuffer);
418 return;
420 mPtr->mFloatRingBuffer.emplace(mPtr->mBackingBuffer.extract());
421 MOZ_ASSERT(!mPtr->mBackingBuffer);
424 uint32_t AudioRingBuffer::Write(const Span<const float>& aBuffer) {
425 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
426 MOZ_ASSERT(!mPtr->mIntRingBuffer);
427 MOZ_ASSERT(!mPtr->mBackingBuffer);
428 return mPtr->mFloatRingBuffer->Write(aBuffer);
431 uint32_t AudioRingBuffer::Write(const Span<const int16_t>& aBuffer) {
432 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16);
433 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
434 MOZ_ASSERT(!mPtr->mBackingBuffer);
435 return mPtr->mIntRingBuffer->Write(aBuffer);
438 uint32_t AudioRingBuffer::Write(const AudioRingBuffer& aBuffer,
439 uint32_t aSamples) {
440 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
441 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
442 MOZ_ASSERT(!mPtr->mBackingBuffer);
443 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
444 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
445 return mPtr->mIntRingBuffer->Write(aBuffer.mPtr->mIntRingBuffer.ref(),
446 aSamples);
448 MOZ_ASSERT(!mPtr->mIntRingBuffer);
449 return mPtr->mFloatRingBuffer->Write(aBuffer.mPtr->mFloatRingBuffer.ref(),
450 aSamples);
453 uint32_t AudioRingBuffer::PrependSilence(uint32_t aSamples) {
454 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
455 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
456 MOZ_ASSERT(!mPtr->mBackingBuffer);
457 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
458 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
459 return mPtr->mIntRingBuffer->PrependSilence(aSamples);
461 MOZ_ASSERT(!mPtr->mIntRingBuffer);
462 return mPtr->mFloatRingBuffer->PrependSilence(aSamples);
465 uint32_t AudioRingBuffer::WriteSilence(uint32_t aSamples) {
466 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
467 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
468 MOZ_ASSERT(!mPtr->mBackingBuffer);
469 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
470 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
471 return mPtr->mIntRingBuffer->WriteSilence(aSamples);
473 MOZ_ASSERT(!mPtr->mIntRingBuffer);
474 return mPtr->mFloatRingBuffer->WriteSilence(aSamples);
477 uint32_t AudioRingBuffer::Read(const Span<float>& aBuffer) {
478 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
479 MOZ_ASSERT(!mPtr->mIntRingBuffer);
480 MOZ_ASSERT(!mPtr->mBackingBuffer);
481 return mPtr->mFloatRingBuffer->Read(aBuffer);
484 uint32_t AudioRingBuffer::Read(const Span<int16_t>& aBuffer) {
485 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16);
486 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
487 MOZ_ASSERT(!mPtr->mBackingBuffer);
488 return mPtr->mIntRingBuffer->Read(aBuffer);
491 uint32_t AudioRingBuffer::ReadNoCopy(
492 std::function<uint32_t(const Span<const float>&)>&& aCallable) {
493 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
494 MOZ_ASSERT(!mPtr->mIntRingBuffer);
495 MOZ_ASSERT(!mPtr->mBackingBuffer);
496 return mPtr->mFloatRingBuffer->ReadNoCopy(std::move(aCallable));
499 uint32_t AudioRingBuffer::ReadNoCopy(
500 std::function<uint32_t(const Span<const int16_t>&)>&& aCallable) {
501 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16);
502 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
503 MOZ_ASSERT(!mPtr->mBackingBuffer);
504 return mPtr->mIntRingBuffer->ReadNoCopy(std::move(aCallable));
507 uint32_t AudioRingBuffer::Discard(uint32_t aSamples) {
508 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
509 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
510 MOZ_ASSERT(!mPtr->mBackingBuffer);
511 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
512 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
513 return mPtr->mIntRingBuffer->Discard(aSamples);
515 MOZ_ASSERT(!mPtr->mIntRingBuffer);
516 return mPtr->mFloatRingBuffer->Discard(aSamples);
519 uint32_t AudioRingBuffer::Clear() {
520 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
521 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
522 MOZ_ASSERT(!mPtr->mBackingBuffer);
523 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
524 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
525 MOZ_ASSERT(mPtr->mIntRingBuffer);
526 return mPtr->mIntRingBuffer->Clear();
528 MOZ_ASSERT(!mPtr->mIntRingBuffer);
529 MOZ_ASSERT(mPtr->mFloatRingBuffer);
530 return mPtr->mFloatRingBuffer->Clear();
533 bool AudioRingBuffer::SetLengthBytes(uint32_t aLengthBytes) {
534 if (mPtr->mFloatRingBuffer) {
535 return mPtr->mFloatRingBuffer->SetLengthBytes(aLengthBytes);
537 if (mPtr->mIntRingBuffer) {
538 return mPtr->mIntRingBuffer->SetLengthBytes(aLengthBytes);
540 if (mPtr->mBackingBuffer) {
541 return mPtr->mBackingBuffer->SetLength(aLengthBytes);
543 MOZ_ASSERT_UNREACHABLE("Unexpected");
544 return true;
547 uint32_t AudioRingBuffer::Capacity() const {
548 if (mPtr->mFloatRingBuffer) {
549 return mPtr->mFloatRingBuffer->Capacity();
551 if (mPtr->mIntRingBuffer) {
552 return mPtr->mIntRingBuffer->Capacity();
554 MOZ_ASSERT_UNREACHABLE("Unexpected");
555 return 0;
558 bool AudioRingBuffer::IsFull() const {
559 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
560 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
561 MOZ_ASSERT(!mPtr->mBackingBuffer);
562 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
563 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
564 return mPtr->mIntRingBuffer->IsFull();
566 MOZ_ASSERT(!mPtr->mIntRingBuffer);
567 return mPtr->mFloatRingBuffer->IsFull();
570 bool AudioRingBuffer::IsEmpty() const {
571 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
572 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
573 MOZ_ASSERT(!mPtr->mBackingBuffer);
574 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
575 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
576 return mPtr->mIntRingBuffer->IsEmpty();
578 MOZ_ASSERT(!mPtr->mIntRingBuffer);
579 return mPtr->mFloatRingBuffer->IsEmpty();
582 uint32_t AudioRingBuffer::AvailableWrite() const {
583 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
584 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
585 MOZ_ASSERT(!mPtr->mBackingBuffer);
586 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
587 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
588 return mPtr->mIntRingBuffer->AvailableWrite();
590 MOZ_ASSERT(!mPtr->mIntRingBuffer);
591 return mPtr->mFloatRingBuffer->AvailableWrite();
594 uint32_t AudioRingBuffer::AvailableRead() const {
595 MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
596 mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
597 MOZ_ASSERT(!mPtr->mBackingBuffer);
598 if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
599 MOZ_ASSERT(!mPtr->mFloatRingBuffer);
600 return mPtr->mIntRingBuffer->AvailableRead();
602 MOZ_ASSERT(!mPtr->mIntRingBuffer);
603 return mPtr->mFloatRingBuffer->AvailableRead();
606 } // namespace mozilla