1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webaudio/AudioParam.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,149 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "AudioParam.h" 1.11 +#include "mozilla/dom/AudioParamBinding.h" 1.12 +#include "AudioNodeEngine.h" 1.13 +#include "AudioNodeStream.h" 1.14 +#include "AudioContext.h" 1.15 + 1.16 +namespace mozilla { 1.17 +namespace dom { 1.18 + 1.19 +NS_IMPL_CYCLE_COLLECTION_CLASS(AudioParam) 1.20 + 1.21 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioParam) 1.22 + tmp->DisconnectFromGraphAndDestroyStream(); 1.23 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mNode) 1.24 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.25 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.26 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioParam) 1.27 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode) 1.28 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.29 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.30 + 1.31 +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AudioParam) 1.32 + 1.33 +NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(AudioParam) 1.34 + 1.35 +NS_IMETHODIMP_(MozExternalRefCountType) 1.36 +AudioParam::Release() 1.37 +{ 1.38 + if (mRefCnt.get() == 1) { 1.39 + // We are about to be deleted, disconnect the object from the graph before 1.40 + // the derived type is destroyed. 1.41 + DisconnectFromGraphAndDestroyStream(); 1.42 + } 1.43 + NS_IMPL_CC_NATIVE_RELEASE_BODY(AudioParam) 1.44 +} 1.45 + 1.46 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioParam, AddRef) 1.47 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioParam, Release) 1.48 + 1.49 +AudioParam::AudioParam(AudioNode* aNode, 1.50 + AudioParam::CallbackType aCallback, 1.51 + float aDefaultValue) 1.52 + : AudioParamTimeline(aDefaultValue) 1.53 + , mNode(aNode) 1.54 + , mCallback(aCallback) 1.55 + , mDefaultValue(aDefaultValue) 1.56 +{ 1.57 + SetIsDOMBinding(); 1.58 +} 1.59 + 1.60 +AudioParam::~AudioParam() 1.61 +{ 1.62 + MOZ_ASSERT(mInputNodes.IsEmpty()); 1.63 +} 1.64 + 1.65 +JSObject* 1.66 +AudioParam::WrapObject(JSContext* aCx) 1.67 +{ 1.68 + return AudioParamBinding::Wrap(aCx, this); 1.69 +} 1.70 + 1.71 +void 1.72 +AudioParam::DisconnectFromGraphAndDestroyStream() 1.73 +{ 1.74 + // Addref this temporarily so the refcount bumping below doesn't destroy us 1.75 + // prematurely 1.76 + nsRefPtr<AudioParam> kungFuDeathGrip = this; 1.77 + 1.78 + while (!mInputNodes.IsEmpty()) { 1.79 + uint32_t i = mInputNodes.Length() - 1; 1.80 + nsRefPtr<AudioNode> input = mInputNodes[i].mInputNode; 1.81 + mInputNodes.RemoveElementAt(i); 1.82 + input->RemoveOutputParam(this); 1.83 + } 1.84 + 1.85 + if (mNodeStreamPort) { 1.86 + mNodeStreamPort->Destroy(); 1.87 + mNodeStreamPort = nullptr; 1.88 + } 1.89 + 1.90 + if (mStream) { 1.91 + mStream->Destroy(); 1.92 + mStream = nullptr; 1.93 + } 1.94 +} 1.95 + 1.96 +MediaStream* 1.97 +AudioParam::Stream() 1.98 +{ 1.99 + if (mStream) { 1.100 + return mStream; 1.101 + } 1.102 + 1.103 + AudioNodeEngine* engine = new AudioNodeEngine(nullptr); 1.104 + nsRefPtr<AudioNodeStream> stream = 1.105 + mNode->Context()->Graph()->CreateAudioNodeStream(engine, 1.106 + MediaStreamGraph::INTERNAL_STREAM, 1.107 + Node()->Context()->SampleRate()); 1.108 + 1.109 + // Force the input to have only one channel, and make it down-mix using 1.110 + // the speaker rules if needed. 1.111 + stream->SetChannelMixingParametersImpl(1, ChannelCountMode::Explicit, ChannelInterpretation::Speakers); 1.112 + // Mark as an AudioParam helper stream 1.113 + stream->SetAudioParamHelperStream(); 1.114 + 1.115 + mStream = stream.forget(); 1.116 + 1.117 + // Setup the AudioParam's stream as an input to the owner AudioNode's stream 1.118 + MediaStream* nodeStream = mNode->Stream(); 1.119 + MOZ_ASSERT(nodeStream->AsProcessedStream()); 1.120 + ProcessedMediaStream* ps = static_cast<ProcessedMediaStream*>(nodeStream); 1.121 + mNodeStreamPort = ps->AllocateInputPort(mStream, MediaInputPort::FLAG_BLOCK_INPUT); 1.122 + 1.123 + // Let the MSG's copy of AudioParamTimeline know about the change in the stream 1.124 + mCallback(mNode); 1.125 + 1.126 + return mStream; 1.127 +} 1.128 + 1.129 +float 1.130 +AudioParamTimeline::AudioNodeInputValue(size_t aCounter) const 1.131 +{ 1.132 + MOZ_ASSERT(mStream); 1.133 + 1.134 + // If we have a chunk produced by the AudioNode inputs to the AudioParam, 1.135 + // get its value now. We use aCounter to tell us which frame of the last 1.136 + // AudioChunk to look at. 1.137 + float audioNodeInputValue = 0.0f; 1.138 + const AudioChunk& lastAudioNodeChunk = 1.139 + static_cast<AudioNodeStream*>(mStream.get())->LastChunks()[0]; 1.140 + if (!lastAudioNodeChunk.IsNull()) { 1.141 + MOZ_ASSERT(lastAudioNodeChunk.GetDuration() == WEBAUDIO_BLOCK_SIZE); 1.142 + audioNodeInputValue = 1.143 + static_cast<const float*>(lastAudioNodeChunk.mChannelData[0])[aCounter]; 1.144 + audioNodeInputValue *= lastAudioNodeChunk.mVolume; 1.145 + } 1.146 + 1.147 + return audioNodeInputValue; 1.148 +} 1.149 + 1.150 +} 1.151 +} 1.152 +