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_AUDIOMIXER_H_
7 : #define MOZILLA_AUDIOMIXER_H_
8 :
9 : #include "AudioSampleFormat.h"
10 : #include "nsTArray.h"
11 : #include "mozilla/PodOperations.h"
12 : #include "mozilla/LinkedList.h"
13 : #include "AudioStream.h"
14 :
15 : namespace mozilla {
16 :
17 0 : struct MixerCallbackReceiver {
18 : virtual void MixerCallback(AudioDataValue* aMixedBuffer,
19 : AudioSampleFormat aFormat,
20 : uint32_t aChannels,
21 : uint32_t aFrames,
22 : uint32_t aSampleRate) = 0;
23 : };
24 : /**
25 : * This class mixes multiple streams of audio together to output a single audio
26 : * stream.
27 : *
28 : * AudioMixer::Mix is to be called repeatedly with buffers that have the same
29 : * length, sample rate, sample format and channel count. This class works with
30 : * interleaved and plannar buffers, but the buffer mixed must be of the same
31 : * type during a mixing cycle.
32 : *
33 : * When all the tracks have been mixed, calling FinishMixing will call back with
34 : * a buffer containing the mixed audio data.
35 : *
36 : * This class is not thread safe.
37 : */
38 : class AudioMixer
39 : {
40 : public:
41 0 : AudioMixer()
42 0 : : mFrames(0),
43 : mChannels(0),
44 0 : mSampleRate(0)
45 0 : { }
46 :
47 0 : ~AudioMixer()
48 0 : {
49 : MixerCallback* cb;
50 0 : while ((cb = mCallbacks.popFirst())) {
51 0 : delete cb;
52 : }
53 0 : }
54 :
55 0 : void StartMixing()
56 : {
57 0 : mSampleRate = mChannels = mFrames = 0;
58 0 : }
59 :
60 : /* Get the data from the mixer. This is supposed to be called when all the
61 : * tracks have been mixed in. The caller should not hold onto the data. */
62 0 : void FinishMixing() {
63 0 : MOZ_ASSERT(mChannels && mFrames && mSampleRate, "Mix not called for this cycle?");
64 0 : for (MixerCallback* cb = mCallbacks.getFirst();
65 0 : cb != nullptr; cb = cb->getNext()) {
66 0 : cb->mReceiver->MixerCallback(mMixedAudio.Elements(),
67 : AudioSampleTypeToFormat<AudioDataValue>::Format,
68 : mChannels,
69 : mFrames,
70 0 : mSampleRate);
71 : }
72 0 : PodZero(mMixedAudio.Elements(), mMixedAudio.Length());
73 0 : mSampleRate = mChannels = mFrames = 0;
74 0 : }
75 :
76 : /* Add a buffer to the mix. */
77 0 : void Mix(AudioDataValue* aSamples,
78 : uint32_t aChannels,
79 : uint32_t aFrames,
80 : uint32_t aSampleRate) {
81 0 : if (!mFrames && !mChannels) {
82 0 : mFrames = aFrames;
83 0 : mChannels = aChannels;
84 0 : mSampleRate = aSampleRate;
85 0 : EnsureCapacityAndSilence();
86 : }
87 :
88 0 : MOZ_ASSERT(aFrames == mFrames);
89 0 : MOZ_ASSERT(aChannels == mChannels);
90 0 : MOZ_ASSERT(aSampleRate == mSampleRate);
91 :
92 0 : for (uint32_t i = 0; i < aFrames * aChannels; i++) {
93 0 : mMixedAudio[i] += aSamples[i];
94 : }
95 0 : }
96 :
97 0 : void AddCallback(MixerCallbackReceiver* aReceiver) {
98 0 : mCallbacks.insertBack(new MixerCallback(aReceiver));
99 0 : }
100 :
101 : bool FindCallback(MixerCallbackReceiver* aReceiver) {
102 : for (MixerCallback* cb = mCallbacks.getFirst();
103 : cb != nullptr; cb = cb->getNext()) {
104 : if (cb->mReceiver == aReceiver) {
105 : return true;
106 : }
107 : }
108 : return false;
109 : }
110 :
111 0 : bool RemoveCallback(MixerCallbackReceiver* aReceiver) {
112 0 : for (MixerCallback* cb = mCallbacks.getFirst();
113 0 : cb != nullptr; cb = cb->getNext()) {
114 0 : if (cb->mReceiver == aReceiver) {
115 0 : cb->remove();
116 0 : delete cb;
117 0 : return true;
118 : }
119 : }
120 0 : return false;
121 : }
122 : private:
123 0 : void EnsureCapacityAndSilence() {
124 0 : if (mFrames * mChannels > mMixedAudio.Length()) {
125 0 : mMixedAudio.SetLength(mFrames* mChannels);
126 : }
127 0 : PodZero(mMixedAudio.Elements(), mMixedAudio.Length());
128 0 : }
129 :
130 0 : class MixerCallback : public LinkedListElement<MixerCallback>
131 : {
132 : public:
133 0 : explicit MixerCallback(MixerCallbackReceiver* aReceiver)
134 0 : : mReceiver(aReceiver)
135 0 : { }
136 : MixerCallbackReceiver* mReceiver;
137 : };
138 :
139 : /* Function that is called when the mixing is done. */
140 : LinkedList<MixerCallback> mCallbacks;
141 : /* Number of frames for this mixing block. */
142 : uint32_t mFrames;
143 : /* Number of channels for this mixing block. */
144 : uint32_t mChannels;
145 : /* Sample rate the of the mixed data. */
146 : uint32_t mSampleRate;
147 : /* Buffer containing the mixed audio data. */
148 : nsTArray<AudioDataValue> mMixedAudio;
149 : };
150 :
151 : } // namespace mozilla
152 :
153 : #endif // MOZILLA_AUDIOMIXER_H_
|