michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/ChannelMergerNode.h" michael@0: #include "mozilla/dom/ChannelMergerNodeBinding.h" michael@0: #include "AudioNodeEngine.h" michael@0: #include "AudioNodeStream.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED0(ChannelMergerNode, AudioNode) michael@0: michael@0: class ChannelMergerNodeEngine : public AudioNodeEngine michael@0: { michael@0: public: michael@0: ChannelMergerNodeEngine(ChannelMergerNode* aNode) michael@0: : AudioNodeEngine(aNode) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: } michael@0: michael@0: virtual void ProcessBlocksOnPorts(AudioNodeStream* aStream, michael@0: const OutputChunks& aInput, michael@0: OutputChunks& aOutput, michael@0: bool* aFinished) MOZ_OVERRIDE michael@0: { michael@0: MOZ_ASSERT(aInput.Length() >= 1, "Should have one or more input ports"); michael@0: michael@0: // Get the number of output channels, and allocate it michael@0: uint32_t channelCount = 0; michael@0: for (uint16_t i = 0; i < InputCount(); ++i) { michael@0: channelCount += aInput[i].mChannelData.Length(); michael@0: } michael@0: if (channelCount == 0) { michael@0: aOutput[0].SetNull(WEBAUDIO_BLOCK_SIZE); michael@0: return; michael@0: } michael@0: channelCount = std::min(channelCount, WebAudioUtils::MaxChannelCount); michael@0: AllocateAudioBlock(channelCount, &aOutput[0]); michael@0: michael@0: // Append each channel in each input to the output michael@0: uint32_t channelIndex = 0; michael@0: for (uint16_t i = 0; true; ++i) { michael@0: MOZ_ASSERT(i < InputCount()); michael@0: for (uint32_t j = 0; j < aInput[i].mChannelData.Length(); ++j) { michael@0: AudioBlockCopyChannelWithScale( michael@0: static_cast(aInput[i].mChannelData[j]), michael@0: aInput[i].mVolume, michael@0: static_cast(const_cast(aOutput[0].mChannelData[channelIndex]))); michael@0: ++channelIndex; michael@0: if (channelIndex >= channelCount) { michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE michael@0: { michael@0: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); michael@0: } michael@0: }; michael@0: michael@0: ChannelMergerNode::ChannelMergerNode(AudioContext* aContext, michael@0: uint16_t aInputCount) michael@0: : AudioNode(aContext, michael@0: 2, michael@0: ChannelCountMode::Max, michael@0: ChannelInterpretation::Speakers) michael@0: , mInputCount(aInputCount) michael@0: { michael@0: mStream = aContext->Graph()->CreateAudioNodeStream(new ChannelMergerNodeEngine(this), michael@0: MediaStreamGraph::INTERNAL_STREAM); michael@0: } michael@0: michael@0: JSObject* michael@0: ChannelMergerNode::WrapObject(JSContext* aCx) michael@0: { michael@0: return ChannelMergerNodeBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: } michael@0: } michael@0: