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_AUDIOMIXER_H_
7 #define MOZILLA_AUDIOMIXER_H_
9 #include "AudioSampleFormat.h"
10 #include "AudioSegment.h"
11 #include "AudioStream.h"
13 #include "mozilla/NotNull.h"
14 #include "mozilla/PodOperations.h"
18 struct MixerCallbackReceiver
{
19 // MixerCallback MAY modify aMixedBuffer but MUST clear
20 // aMixedBuffer->mBuffer if its data is to live longer than the duration of
22 virtual void MixerCallback(AudioChunk
* aMixedBuffer
,
23 uint32_t aSampleRate
) = 0;
26 * This class mixes multiple streams of audio together to output a single audio
29 * AudioMixer::Mix is to be called repeatedly with buffers that have the same
30 * length, sample rate, sample format and channel count. This class works with
33 * When all the tracks have been mixed, calling MixedChunk() will provide
34 * a buffer containing the mixed audio data.
36 * This class is not thread safe.
40 AudioMixer() { mChunk
.mBufferFormat
= AUDIO_OUTPUT_FORMAT
; }
42 ~AudioMixer() = default;
49 /* Get the data from the mixer. This is supposed to be called when all the
50 * tracks have been mixed in. The caller MAY modify the chunk but MUST clear
51 * mBuffer if its data needs to survive the next call to Mix(). */
52 AudioChunk
* MixedChunk() {
53 MOZ_ASSERT(mSampleRate
, "Mix not called for this cycle?");
58 /* Add a buffer to the mix. The buffer can be null if there's nothing to mix
59 * but the callback is still needed. */
60 void Mix(AudioDataValue
* aSamples
, uint32_t aChannels
, uint32_t aFrames
,
61 uint32_t aSampleRate
) {
62 if (!mChunk
.mDuration
) {
63 mChunk
.mDuration
= aFrames
;
64 MOZ_ASSERT(aChannels
> 0);
65 mChunk
.mChannelData
.SetLength(aChannels
);
66 mSampleRate
= aSampleRate
;
67 EnsureCapacityAndSilence();
70 MOZ_ASSERT(aFrames
== mChunk
.mDuration
);
71 MOZ_ASSERT(aChannels
== mChunk
.ChannelCount());
72 MOZ_ASSERT(aSampleRate
== mSampleRate
);
78 for (uint32_t i
= 0; i
< aFrames
* aChannels
; i
++) {
79 mChunk
.ChannelDataForWrite
<AudioDataValue
>(0)[i
] += aSamples
[i
];
84 void EnsureCapacityAndSilence() {
85 uint32_t sampleCount
= mChunk
.mDuration
* mChunk
.ChannelCount();
86 if (!mChunk
.mBuffer
|| sampleCount
> mSampleCapacity
) {
87 CheckedInt
<size_t> bufferSize(sizeof(AudioDataValue
));
88 bufferSize
*= sampleCount
;
89 mChunk
.mBuffer
= SharedBuffer::Create(bufferSize
);
90 mSampleCapacity
= sampleCount
;
92 MOZ_ASSERT(!mChunk
.mBuffer
->IsShared());
93 mChunk
.mChannelData
[0] =
94 static_cast<SharedBuffer
*>(mChunk
.mBuffer
.get())->Data();
95 for (size_t i
= 1; i
< mChunk
.ChannelCount(); ++i
) {
96 mChunk
.mChannelData
[i
] =
97 mChunk
.ChannelData
<AudioDataValue
>()[0] + i
* mChunk
.mDuration
;
99 PodZero(mChunk
.ChannelDataForWrite
<AudioDataValue
>(0), sampleCount
);
102 /* Buffer containing the mixed audio data. */
104 /* Size allocated for mChunk.mBuffer. */
105 uint32_t mSampleCapacity
= 0;
106 /* Sample rate the of the mixed data. */
107 uint32_t mSampleRate
= 0;
110 } // namespace mozilla
112 #endif // MOZILLA_AUDIOMIXER_H_