AudioMixer.h (3608B)
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 "AudioSegment.h" 11 #include "AudioStream.h" 12 #include "mozilla/PodOperations.h" 13 #include "nsTArray.h" 14 15 namespace mozilla { 16 17 struct MixerCallbackReceiver { 18 // MixerCallback MAY modify aMixedBuffer but MUST clear 19 // aMixedBuffer->mBuffer if its data is to live longer than the duration of 20 // the callback. 21 virtual void MixerCallback(AudioChunk* aMixedBuffer, 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 * planar buffers. 31 * 32 * When all the tracks have been mixed, calling MixedChunk() will provide 33 * a buffer containing the mixed audio data. 34 * 35 * This class is not thread safe. 36 */ 37 class AudioMixer { 38 public: 39 AudioMixer() { mChunk.mBufferFormat = AUDIO_OUTPUT_FORMAT; } 40 41 ~AudioMixer() = default; 42 43 void StartMixing() { 44 mChunk.mDuration = 0; 45 mSampleRate = 0; 46 } 47 48 /* Get the data from the mixer. This is supposed to be called when all the 49 * tracks have been mixed in. The caller MAY modify the chunk but MUST clear 50 * mBuffer if its data needs to survive the next call to Mix(). */ 51 AudioChunk* MixedChunk() { 52 MOZ_ASSERT(mSampleRate, "Mix not called for this cycle?"); 53 mSampleRate = 0; 54 return &mChunk; 55 }; 56 57 /* Add a buffer to the mix. The buffer can be null if there's nothing to mix 58 * but the callback is still needed. */ 59 void Mix(AudioDataValue* aSamples, uint32_t aChannels, uint32_t aFrames, 60 uint32_t aSampleRate) { 61 if (!mChunk.mDuration) { 62 mChunk.mDuration = aFrames; 63 MOZ_ASSERT(aChannels > 0); 64 mChunk.mChannelData.SetLength(aChannels); 65 mSampleRate = aSampleRate; 66 EnsureCapacityAndSilence(); 67 } 68 69 MOZ_ASSERT(aFrames == mChunk.mDuration); 70 MOZ_ASSERT(aChannels == mChunk.ChannelCount()); 71 MOZ_ASSERT(aSampleRate == mSampleRate); 72 73 if (!aSamples) { 74 return; 75 } 76 77 for (uint32_t i = 0; i < aFrames * aChannels; i++) { 78 mChunk.ChannelDataForWrite<AudioDataValue>(0)[i] += aSamples[i]; 79 } 80 } 81 82 private: 83 void EnsureCapacityAndSilence() { 84 uint32_t sampleCount = mChunk.mDuration * mChunk.ChannelCount(); 85 if (!mChunk.mBuffer || sampleCount > mSampleCapacity) { 86 CheckedInt<size_t> bufferSize(sizeof(AudioDataValue)); 87 bufferSize *= sampleCount; 88 mChunk.mBuffer = SharedBuffer::Create(bufferSize); 89 mSampleCapacity = sampleCount; 90 } 91 MOZ_ASSERT(!mChunk.mBuffer->IsShared()); 92 mChunk.mChannelData[0] = 93 static_cast<SharedBuffer*>(mChunk.mBuffer.get())->Data(); 94 for (size_t i = 1; i < mChunk.ChannelCount(); ++i) { 95 mChunk.mChannelData[i] = 96 mChunk.ChannelData<AudioDataValue>()[0] + i * mChunk.mDuration; 97 } 98 PodZero(mChunk.ChannelDataForWrite<AudioDataValue>(0), sampleCount); 99 } 100 101 /* Buffer containing the mixed audio data. */ 102 AudioChunk mChunk; 103 /* Size allocated for mChunk.mBuffer. */ 104 uint32_t mSampleCapacity = 0; 105 /* Sample rate the of the mixed data. */ 106 uint32_t mSampleRate = 0; 107 }; 108 109 } // namespace mozilla 110 111 #endif // MOZILLA_AUDIOMIXER_H_