/src/mozilla-central/dom/media/webaudio/AudioNode.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "AudioNode.h" |
8 | | #include "mozilla/ErrorResult.h" |
9 | | #include "AudioNodeStream.h" |
10 | | #include "AudioNodeEngine.h" |
11 | | #include "mozilla/dom/AudioParam.h" |
12 | | #include "mozilla/Services.h" |
13 | | #include "nsIObserverService.h" |
14 | | |
15 | | namespace mozilla { |
16 | | namespace dom { |
17 | | |
18 | | static const uint32_t INVALID_PORT = 0xffffffff; |
19 | | static uint32_t gId = 0; |
20 | | |
21 | | NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode) |
22 | | |
23 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AudioNode, DOMEventTargetHelper) |
24 | 0 | tmp->DisconnectFromGraph(); |
25 | 0 | if (tmp->mContext) { |
26 | 0 | tmp->mContext->UnregisterNode(tmp); |
27 | 0 | } |
28 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext) |
29 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputNodes) |
30 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputParams) |
31 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
32 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioNode, |
33 | 0 | DOMEventTargetHelper) |
34 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext) |
35 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputNodes) |
36 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputParams) |
37 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
38 | | |
39 | | NS_IMPL_ADDREF_INHERITED(AudioNode, DOMEventTargetHelper) |
40 | | NS_IMPL_RELEASE_INHERITED(AudioNode, DOMEventTargetHelper) |
41 | | |
42 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioNode) |
43 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
44 | 0 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
45 | | |
46 | | AudioNode::AudioNode(AudioContext* aContext, |
47 | | uint32_t aChannelCount, |
48 | | ChannelCountMode aChannelCountMode, |
49 | | ChannelInterpretation aChannelInterpretation) |
50 | | : DOMEventTargetHelper(aContext->GetParentObject()) |
51 | | , mContext(aContext) |
52 | | , mChannelCount(aChannelCount) |
53 | | , mChannelCountMode(aChannelCountMode) |
54 | | , mChannelInterpretation(aChannelInterpretation) |
55 | | , mId(gId++) |
56 | | , mPassThrough(false) |
57 | | , mAbstractMainThread(aContext->GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other)) |
58 | 0 | { |
59 | 0 | MOZ_ASSERT(aContext); |
60 | 0 | aContext->RegisterNode(this); |
61 | 0 | } |
62 | | |
63 | | AudioNode::~AudioNode() |
64 | 0 | { |
65 | 0 | MOZ_ASSERT(mInputNodes.IsEmpty()); |
66 | 0 | MOZ_ASSERT(mOutputNodes.IsEmpty()); |
67 | 0 | MOZ_ASSERT(mOutputParams.IsEmpty()); |
68 | 0 | MOZ_ASSERT(!mStream, |
69 | 0 | "The webaudio-node-demise notification must have been sent"); |
70 | 0 | if (mContext) { |
71 | 0 | mContext->UnregisterNode(this); |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | | void |
76 | | AudioNode::Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv) |
77 | 0 | { |
78 | 0 | if (aOptions.mChannelCount.WasPassed()) { |
79 | 0 | SetChannelCount(aOptions.mChannelCount.Value(), aRv); |
80 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
81 | 0 | return; |
82 | 0 | } |
83 | 0 | } |
84 | 0 | |
85 | 0 | if (aOptions.mChannelCountMode.WasPassed()) { |
86 | 0 | SetChannelCountModeValue(aOptions.mChannelCountMode.Value(), aRv); |
87 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
88 | 0 | return; |
89 | 0 | } |
90 | 0 | } |
91 | 0 | |
92 | 0 | if (aOptions.mChannelInterpretation.WasPassed()) { |
93 | 0 | SetChannelInterpretationValue(aOptions.mChannelInterpretation.Value(), aRv); |
94 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
95 | 0 | return; |
96 | 0 | } |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | | size_t |
101 | | AudioNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const |
102 | 0 | { |
103 | 0 | // Not owned: |
104 | 0 | // - mContext |
105 | 0 | // - mStream |
106 | 0 | size_t amount = 0; |
107 | 0 |
|
108 | 0 | amount += mInputNodes.ShallowSizeOfExcludingThis(aMallocSizeOf); |
109 | 0 | for (size_t i = 0; i < mInputNodes.Length(); i++) { |
110 | 0 | amount += mInputNodes[i].SizeOfExcludingThis(aMallocSizeOf); |
111 | 0 | } |
112 | 0 |
|
113 | 0 | // Just measure the array. The entire audio node graph is measured via the |
114 | 0 | // MediaStreamGraph's streams, so we don't want to double-count the elements. |
115 | 0 | amount += mOutputNodes.ShallowSizeOfExcludingThis(aMallocSizeOf); |
116 | 0 |
|
117 | 0 | amount += mOutputParams.ShallowSizeOfExcludingThis(aMallocSizeOf); |
118 | 0 | for (size_t i = 0; i < mOutputParams.Length(); i++) { |
119 | 0 | amount += mOutputParams[i]->SizeOfIncludingThis(aMallocSizeOf); |
120 | 0 | } |
121 | 0 |
|
122 | 0 | return amount; |
123 | 0 | } |
124 | | |
125 | | size_t |
126 | | AudioNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const |
127 | 0 | { |
128 | 0 | return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
129 | 0 | } |
130 | | |
131 | | template <class InputNode> |
132 | | static size_t |
133 | | FindIndexOfNode(const nsTArray<InputNode>& aInputNodes, const AudioNode* aNode) |
134 | 0 | { |
135 | 0 | for (size_t i = 0; i < aInputNodes.Length(); ++i) { |
136 | 0 | if (aInputNodes[i].mInputNode == aNode) { |
137 | 0 | return i; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | return nsTArray<InputNode>::NoIndex; |
141 | 0 | } |
142 | | |
143 | | template <class InputNode> |
144 | | static size_t |
145 | | FindIndexOfNodeWithPorts(const nsTArray<InputNode>& aInputNodes, |
146 | | const AudioNode* aNode, |
147 | | uint32_t aInputPort, uint32_t aOutputPort) |
148 | 0 | { |
149 | 0 | for (size_t i = 0; i < aInputNodes.Length(); ++i) { |
150 | 0 | if (aInputNodes[i].mInputNode == aNode && |
151 | 0 | aInputNodes[i].mInputPort == aInputPort && |
152 | 0 | aInputNodes[i].mOutputPort == aOutputPort) { |
153 | 0 | return i; |
154 | 0 | } |
155 | 0 | } |
156 | 0 | return nsTArray<InputNode>::NoIndex; |
157 | 0 | } |
158 | | |
159 | | void |
160 | | AudioNode::DisconnectFromGraph() |
161 | 0 | { |
162 | 0 | MOZ_ASSERT(mRefCnt.get() > mInputNodes.Length(), |
163 | 0 | "Caller should be holding a reference"); |
164 | 0 |
|
165 | 0 | // The idea here is that we remove connections one by one, and at each step |
166 | 0 | // the graph is in a valid state. |
167 | 0 |
|
168 | 0 | // Disconnect inputs. We don't need them anymore. |
169 | 0 | while (!mInputNodes.IsEmpty()) { |
170 | 0 | size_t i = mInputNodes.Length() - 1; |
171 | 0 | RefPtr<AudioNode> input = mInputNodes[i].mInputNode; |
172 | 0 | mInputNodes.RemoveElementAt(i); |
173 | 0 | input->mOutputNodes.RemoveElement(this); |
174 | 0 | } |
175 | 0 |
|
176 | 0 | while (!mOutputNodes.IsEmpty()) { |
177 | 0 | size_t i = mOutputNodes.Length() - 1; |
178 | 0 | RefPtr<AudioNode> output = mOutputNodes[i].forget(); |
179 | 0 | mOutputNodes.RemoveElementAt(i); |
180 | 0 | size_t inputIndex = FindIndexOfNode(output->mInputNodes, this); |
181 | 0 | // It doesn't matter which one we remove, since we're going to remove all |
182 | 0 | // entries for this node anyway. |
183 | 0 | output->mInputNodes.RemoveElementAt(inputIndex); |
184 | 0 | // This effects of this connection will remain. |
185 | 0 | output->NotifyHasPhantomInput(); |
186 | 0 | } |
187 | 0 |
|
188 | 0 | while (!mOutputParams.IsEmpty()) { |
189 | 0 | size_t i = mOutputParams.Length() - 1; |
190 | 0 | RefPtr<AudioParam> output = mOutputParams[i].forget(); |
191 | 0 | mOutputParams.RemoveElementAt(i); |
192 | 0 | size_t inputIndex = FindIndexOfNode(output->InputNodes(), this); |
193 | 0 | // It doesn't matter which one we remove, since we're going to remove all |
194 | 0 | // entries for this node anyway. |
195 | 0 | output->RemoveInputNode(inputIndex); |
196 | 0 | } |
197 | 0 |
|
198 | 0 | DestroyMediaStream(); |
199 | 0 | } |
200 | | |
201 | | AudioNode* |
202 | | AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput, |
203 | | uint32_t aInput, ErrorResult& aRv) |
204 | 0 | { |
205 | 0 | if (aOutput >= NumberOfOutputs() || |
206 | 0 | aInput >= aDestination.NumberOfInputs()) { |
207 | 0 | aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
208 | 0 | return nullptr; |
209 | 0 | } |
210 | 0 | |
211 | 0 | if (Context() != aDestination.Context()) { |
212 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
213 | 0 | return nullptr; |
214 | 0 | } |
215 | 0 | |
216 | 0 | if (FindIndexOfNodeWithPorts(aDestination.mInputNodes, |
217 | 0 | this, aInput, aOutput) != |
218 | 0 | nsTArray<AudioNode::InputNode>::NoIndex) { |
219 | 0 | // connection already exists. |
220 | 0 | return &aDestination; |
221 | 0 | } |
222 | 0 | |
223 | 0 | WEB_AUDIO_API_LOG("%f: %s %u Connect() to %s %u", |
224 | 0 | Context()->CurrentTime(), NodeType(), Id(), |
225 | 0 | aDestination.NodeType(), aDestination.Id()); |
226 | 0 |
|
227 | 0 | // The MediaStreamGraph will handle cycle detection. We don't need to do it |
228 | 0 | // here. |
229 | 0 |
|
230 | 0 | mOutputNodes.AppendElement(&aDestination); |
231 | 0 | InputNode* input = aDestination.mInputNodes.AppendElement(); |
232 | 0 | input->mInputNode = this; |
233 | 0 | input->mInputPort = aInput; |
234 | 0 | input->mOutputPort = aOutput; |
235 | 0 | AudioNodeStream* destinationStream = aDestination.mStream; |
236 | 0 | if (mStream && destinationStream) { |
237 | 0 | // Connect streams in the MediaStreamGraph |
238 | 0 | MOZ_ASSERT(aInput <= UINT16_MAX, "Unexpected large input port number"); |
239 | 0 | MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number"); |
240 | 0 | input->mStreamPort = destinationStream-> |
241 | 0 | AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK, TRACK_ANY, |
242 | 0 | static_cast<uint16_t>(aInput), |
243 | 0 | static_cast<uint16_t>(aOutput)); |
244 | 0 | } |
245 | 0 | aDestination.NotifyInputsChanged(); |
246 | 0 |
|
247 | 0 | return &aDestination; |
248 | 0 | } |
249 | | |
250 | | void |
251 | | AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput, |
252 | | ErrorResult& aRv) |
253 | 0 | { |
254 | 0 | if (aOutput >= NumberOfOutputs()) { |
255 | 0 | aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
256 | 0 | return; |
257 | 0 | } |
258 | 0 | |
259 | 0 | if (Context() != aDestination.GetParentObject()) { |
260 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
261 | 0 | return; |
262 | 0 | } |
263 | 0 | |
264 | 0 | if (FindIndexOfNodeWithPorts(aDestination.InputNodes(), |
265 | 0 | this, INVALID_PORT, aOutput) != |
266 | 0 | nsTArray<AudioNode::InputNode>::NoIndex) { |
267 | 0 | // connection already exists. |
268 | 0 | return; |
269 | 0 | } |
270 | 0 | |
271 | 0 | mOutputParams.AppendElement(&aDestination); |
272 | 0 | InputNode* input = aDestination.AppendInputNode(); |
273 | 0 | input->mInputNode = this; |
274 | 0 | input->mInputPort = INVALID_PORT; |
275 | 0 | input->mOutputPort = aOutput; |
276 | 0 |
|
277 | 0 | MediaStream* stream = aDestination.Stream(); |
278 | 0 | MOZ_ASSERT(stream->AsProcessedStream()); |
279 | 0 | ProcessedMediaStream* ps = static_cast<ProcessedMediaStream*>(stream); |
280 | 0 | if (mStream) { |
281 | 0 | // Setup our stream as an input to the AudioParam's stream |
282 | 0 | MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number"); |
283 | 0 | input->mStreamPort = |
284 | 0 | ps->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK, TRACK_ANY, |
285 | 0 | 0, static_cast<uint16_t>(aOutput)); |
286 | 0 | } |
287 | 0 | } |
288 | | |
289 | | void |
290 | | AudioNode::SendDoubleParameterToStream(uint32_t aIndex, double aValue) |
291 | 0 | { |
292 | 0 | MOZ_ASSERT(mStream, "How come we don't have a stream here?"); |
293 | 0 | mStream->SetDoubleParameter(aIndex, aValue); |
294 | 0 | } |
295 | | |
296 | | void |
297 | | AudioNode::SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue) |
298 | 0 | { |
299 | 0 | MOZ_ASSERT(mStream, "How come we don't have a stream here?"); |
300 | 0 | mStream->SetInt32Parameter(aIndex, aValue); |
301 | 0 | } |
302 | | |
303 | | void |
304 | | AudioNode::SendThreeDPointParameterToStream(uint32_t aIndex, |
305 | | const ThreeDPoint& aValue) |
306 | 0 | { |
307 | 0 | MOZ_ASSERT(mStream, "How come we don't have a stream here?"); |
308 | 0 | mStream->SetThreeDPointParameter(aIndex, aValue); |
309 | 0 | } |
310 | | |
311 | | void |
312 | | AudioNode::SendChannelMixingParametersToStream() |
313 | 0 | { |
314 | 0 | if (mStream) { |
315 | 0 | mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode, |
316 | 0 | mChannelInterpretation); |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | | template<> |
321 | | bool |
322 | | AudioNode::DisconnectFromOutputIfConnected<AudioNode>(uint32_t aOutputNodeIndex, |
323 | | uint32_t aInputIndex) |
324 | 0 | { |
325 | 0 | WEB_AUDIO_API_LOG("%f: %s %u Disconnect()", Context()->CurrentTime(), |
326 | 0 | NodeType(), Id()); |
327 | 0 |
|
328 | 0 | AudioNode* destination = mOutputNodes[aOutputNodeIndex]; |
329 | 0 |
|
330 | 0 | MOZ_ASSERT(aOutputNodeIndex < mOutputNodes.Length()); |
331 | 0 | MOZ_ASSERT(aInputIndex < destination->InputNodes().Length()); |
332 | 0 |
|
333 | 0 | // An upstream node may be starting to play on the graph thread, and the |
334 | 0 | // engine for a downstream node may be sending a PlayingRefChangeHandler |
335 | 0 | // ADDREF message to this (main) thread. Wait for a round trip before |
336 | 0 | // releasing nodes, to give engines receiving sound now time to keep their |
337 | 0 | // nodes alive. |
338 | 0 | class RunnableRelease final : public Runnable |
339 | 0 | { |
340 | 0 | public: |
341 | 0 | explicit RunnableRelease(already_AddRefed<AudioNode> aNode) |
342 | 0 | : mozilla::Runnable("RunnableRelease") |
343 | 0 | , mNode(aNode) |
344 | 0 | { |
345 | 0 | } |
346 | 0 |
|
347 | 0 | NS_IMETHOD Run() override |
348 | 0 | { |
349 | 0 | mNode = nullptr; |
350 | 0 | return NS_OK; |
351 | 0 | } |
352 | 0 | private: |
353 | 0 | RefPtr<AudioNode> mNode; |
354 | 0 | }; |
355 | 0 |
|
356 | 0 | InputNode& input = destination->mInputNodes[aInputIndex]; |
357 | 0 | if (input.mInputNode != this) { |
358 | 0 | return false; |
359 | 0 | } |
360 | 0 | |
361 | 0 | // Remove one instance of 'dest' from mOutputNodes. There could be |
362 | 0 | // others, and it's not correct to remove them all since some of them |
363 | 0 | // could be for different output ports. |
364 | 0 | RefPtr<AudioNode> output = mOutputNodes[aOutputNodeIndex].forget(); |
365 | 0 | mOutputNodes.RemoveElementAt(aOutputNodeIndex); |
366 | 0 | // Destroying the InputNode here sends a message to the graph thread |
367 | 0 | // to disconnect the streams, which should be sent before the |
368 | 0 | // RunAfterPendingUpdates() call below. |
369 | 0 | destination->mInputNodes.RemoveElementAt(aInputIndex); |
370 | 0 | output->NotifyInputsChanged(); |
371 | 0 | if (mStream) { |
372 | 0 | nsCOMPtr<nsIRunnable> runnable = new RunnableRelease(output.forget()); |
373 | 0 | mStream->RunAfterPendingUpdates(runnable.forget()); |
374 | 0 | } |
375 | 0 | return true; |
376 | 0 | } |
377 | | |
378 | | template<> |
379 | | bool |
380 | | AudioNode::DisconnectFromOutputIfConnected<AudioParam>(uint32_t aOutputParamIndex, |
381 | | uint32_t aInputIndex) |
382 | 0 | { |
383 | 0 | MOZ_ASSERT(aOutputParamIndex < mOutputParams.Length()); |
384 | 0 |
|
385 | 0 | AudioParam* destination = mOutputParams[aOutputParamIndex]; |
386 | 0 |
|
387 | 0 | MOZ_ASSERT(aInputIndex < destination->InputNodes().Length()); |
388 | 0 |
|
389 | 0 | const InputNode& input = destination->InputNodes()[aInputIndex]; |
390 | 0 | if (input.mInputNode != this) { |
391 | 0 | return false; |
392 | 0 | } |
393 | 0 | destination->RemoveInputNode(aInputIndex); |
394 | 0 | // Remove one instance of 'dest' from mOutputParams. There could be |
395 | 0 | // others, and it's not correct to remove them all since some of them |
396 | 0 | // could be for different output ports. |
397 | 0 | mOutputParams.RemoveElementAt(aOutputParamIndex); |
398 | 0 | return true; |
399 | 0 | } |
400 | | |
401 | | template<> |
402 | | const nsTArray<AudioNode::InputNode>& |
403 | 0 | AudioNode::InputsForDestination<AudioNode>(uint32_t aOutputNodeIndex) const { |
404 | 0 | return mOutputNodes[aOutputNodeIndex]->InputNodes(); |
405 | 0 | } |
406 | | |
407 | | template<> |
408 | | const nsTArray<AudioNode::InputNode>& |
409 | 0 | AudioNode::InputsForDestination<AudioParam>(uint32_t aOutputNodeIndex) const { |
410 | 0 | return mOutputParams[aOutputNodeIndex]->InputNodes(); |
411 | 0 | } |
412 | | |
413 | | template<typename DestinationType, typename Predicate> |
414 | | bool |
415 | | AudioNode::DisconnectMatchingDestinationInputs(uint32_t aDestinationIndex, |
416 | | Predicate aPredicate) |
417 | 0 | { |
418 | 0 | bool wasConnected = false; |
419 | 0 | uint32_t inputCount = |
420 | 0 | InputsForDestination<DestinationType>(aDestinationIndex).Length(); |
421 | 0 |
|
422 | 0 | for (int32_t inputIndex = inputCount - 1; inputIndex >= 0; --inputIndex) { |
423 | 0 | const InputNode& input = |
424 | 0 | InputsForDestination<DestinationType>(aDestinationIndex)[inputIndex]; |
425 | 0 | if (aPredicate(input)) { |
426 | 0 | if (DisconnectFromOutputIfConnected<DestinationType>(aDestinationIndex, |
427 | 0 | inputIndex)) { |
428 | 0 | wasConnected = true; |
429 | 0 | break; |
430 | 0 | } |
431 | 0 | } |
432 | 0 | } |
433 | 0 | return wasConnected; |
434 | 0 | } Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioNode, mozilla::dom::AudioNode::Disconnect(mozilla::ErrorResult&)::$_5>(unsigned int, mozilla::dom::AudioNode::Disconnect(mozilla::ErrorResult&)::$_5) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioParam, mozilla::dom::AudioNode::Disconnect(mozilla::ErrorResult&)::$_6>(unsigned int, mozilla::dom::AudioNode::Disconnect(mozilla::ErrorResult&)::$_6) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioNode, mozilla::dom::AudioNode::Disconnect(unsigned int, mozilla::ErrorResult&)::$_7>(unsigned int, mozilla::dom::AudioNode::Disconnect(unsigned int, mozilla::ErrorResult&)::$_7) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioParam, mozilla::dom::AudioNode::Disconnect(unsigned int, mozilla::ErrorResult&)::$_8>(unsigned int, mozilla::dom::AudioNode::Disconnect(unsigned int, mozilla::ErrorResult&)::$_8) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioNode, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioNode&, mozilla::ErrorResult&)::$_9>(unsigned int, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioNode&, mozilla::ErrorResult&)::$_9) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioNode, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioNode&, unsigned int, mozilla::ErrorResult&)::$_10>(unsigned int, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioNode&, unsigned int, mozilla::ErrorResult&)::$_10) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioNode, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioNode&, unsigned int, unsigned int, mozilla::ErrorResult&)::$_11>(unsigned int, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioNode&, unsigned int, unsigned int, mozilla::ErrorResult&)::$_11) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioParam, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioParam&, mozilla::ErrorResult&)::$_12>(unsigned int, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioParam&, mozilla::ErrorResult&)::$_12) Unexecuted instantiation: Unified_cpp_dom_media_webaudio0.cpp:bool mozilla::dom::AudioNode::DisconnectMatchingDestinationInputs<mozilla::dom::AudioParam, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioParam&, unsigned int, mozilla::ErrorResult&)::$_13>(unsigned int, mozilla::dom::AudioNode::Disconnect(mozilla::dom::AudioParam&, unsigned int, mozilla::ErrorResult&)::$_13) |
435 | | |
436 | | void |
437 | | AudioNode::Disconnect(ErrorResult& aRv) |
438 | 0 | { |
439 | 0 | for (int32_t outputIndex = mOutputNodes.Length() - 1; |
440 | 0 | outputIndex >= 0; --outputIndex) { |
441 | 0 | DisconnectMatchingDestinationInputs<AudioNode>(outputIndex, |
442 | 0 | [](const InputNode&) { |
443 | 0 | return true; |
444 | 0 | }); |
445 | 0 | } |
446 | 0 |
|
447 | 0 | for (int32_t outputIndex = mOutputParams.Length() - 1; |
448 | 0 | outputIndex >= 0; --outputIndex) { |
449 | 0 | DisconnectMatchingDestinationInputs<AudioParam>(outputIndex, |
450 | 0 | [](const InputNode&) { |
451 | 0 | return true; |
452 | 0 | }); |
453 | 0 | } |
454 | 0 | } |
455 | | |
456 | | void |
457 | | AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv) |
458 | 0 | { |
459 | 0 | if (aOutput >= NumberOfOutputs()) { |
460 | 0 | aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
461 | 0 | return; |
462 | 0 | } |
463 | 0 | |
464 | 0 | for (int32_t outputIndex = mOutputNodes.Length() - 1; |
465 | 0 | outputIndex >= 0; --outputIndex) { |
466 | 0 | DisconnectMatchingDestinationInputs<AudioNode>( |
467 | 0 | outputIndex, |
468 | 0 | [aOutput](const InputNode& aInputNode) { |
469 | 0 | return aInputNode.mOutputPort == aOutput; |
470 | 0 | }); |
471 | 0 | } |
472 | 0 |
|
473 | 0 | for (int32_t outputIndex = mOutputParams.Length() - 1; |
474 | 0 | outputIndex >= 0; --outputIndex) { |
475 | 0 | DisconnectMatchingDestinationInputs<AudioParam>( |
476 | 0 | outputIndex, |
477 | 0 | [aOutput](const InputNode& aInputNode) { |
478 | 0 | return aInputNode.mOutputPort == aOutput; |
479 | 0 | }); |
480 | 0 | } |
481 | 0 | } |
482 | | |
483 | | void |
484 | | AudioNode::Disconnect(AudioNode& aDestination, ErrorResult& aRv) |
485 | 0 | { |
486 | 0 | bool wasConnected = false; |
487 | 0 |
|
488 | 0 | for (int32_t outputIndex = mOutputNodes.Length() - 1; |
489 | 0 | outputIndex >= 0; --outputIndex) { |
490 | 0 | if (mOutputNodes[outputIndex] != &aDestination) { |
491 | 0 | continue; |
492 | 0 | } |
493 | 0 | wasConnected |= |
494 | 0 | DisconnectMatchingDestinationInputs<AudioNode>(outputIndex, |
495 | 0 | [](const InputNode&) { |
496 | 0 | return true; |
497 | 0 | }); |
498 | 0 | } |
499 | 0 |
|
500 | 0 | if (!wasConnected) { |
501 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
502 | 0 | return; |
503 | 0 | } |
504 | 0 | } |
505 | | |
506 | | void |
507 | | AudioNode::Disconnect(AudioNode& aDestination, |
508 | | uint32_t aOutput, |
509 | | ErrorResult& aRv) |
510 | 0 | { |
511 | 0 | if (aOutput >= NumberOfOutputs()) { |
512 | 0 | aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
513 | 0 | return; |
514 | 0 | } |
515 | 0 | |
516 | 0 | bool wasConnected = false; |
517 | 0 |
|
518 | 0 | for (int32_t outputIndex = mOutputNodes.Length() - 1; |
519 | 0 | outputIndex >= 0; --outputIndex) { |
520 | 0 | if (mOutputNodes[outputIndex] != &aDestination) { |
521 | 0 | continue; |
522 | 0 | } |
523 | 0 | wasConnected |= |
524 | 0 | DisconnectMatchingDestinationInputs<AudioNode>( |
525 | 0 | outputIndex, |
526 | 0 | [aOutput](const InputNode& aInputNode) { |
527 | 0 | return aInputNode.mOutputPort == aOutput; |
528 | 0 | }); |
529 | 0 | } |
530 | 0 |
|
531 | 0 | if (!wasConnected) { |
532 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
533 | 0 | return; |
534 | 0 | } |
535 | 0 | } |
536 | | |
537 | | void |
538 | | AudioNode::Disconnect(AudioNode& aDestination, |
539 | | uint32_t aOutput, |
540 | | uint32_t aInput, |
541 | | ErrorResult& aRv) |
542 | 0 | { |
543 | 0 | if (aOutput >= NumberOfOutputs()) { |
544 | 0 | aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
545 | 0 | return; |
546 | 0 | } |
547 | 0 | |
548 | 0 | if (aInput >= aDestination.NumberOfInputs()) { |
549 | 0 | aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
550 | 0 | return; |
551 | 0 | } |
552 | 0 | |
553 | 0 | bool wasConnected = false; |
554 | 0 |
|
555 | 0 | for (int32_t outputIndex = mOutputNodes.Length() - 1; |
556 | 0 | outputIndex >= 0; --outputIndex) { |
557 | 0 | if (mOutputNodes[outputIndex] != &aDestination) { |
558 | 0 | continue; |
559 | 0 | } |
560 | 0 | wasConnected |= |
561 | 0 | DisconnectMatchingDestinationInputs<AudioNode>( |
562 | 0 | outputIndex, |
563 | 0 | [aOutput, aInput](const InputNode& aInputNode) { |
564 | 0 | return aInputNode.mOutputPort == aOutput && |
565 | 0 | aInputNode.mInputPort == aInput; |
566 | 0 | }); |
567 | 0 | } |
568 | 0 |
|
569 | 0 | if (!wasConnected) { |
570 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
571 | 0 | return; |
572 | 0 | } |
573 | 0 | } |
574 | | |
575 | | void |
576 | | AudioNode::Disconnect(AudioParam& aDestination, ErrorResult& aRv) |
577 | 0 | { |
578 | 0 | bool wasConnected = false; |
579 | 0 |
|
580 | 0 | for (int32_t outputIndex = mOutputParams.Length() - 1; |
581 | 0 | outputIndex >= 0; --outputIndex) { |
582 | 0 | if (mOutputParams[outputIndex] != &aDestination) { |
583 | 0 | continue; |
584 | 0 | } |
585 | 0 | wasConnected |= |
586 | 0 | DisconnectMatchingDestinationInputs<AudioParam>(outputIndex, |
587 | 0 | [](const InputNode&) { |
588 | 0 | return true; |
589 | 0 | }); |
590 | 0 | } |
591 | 0 |
|
592 | 0 | if (!wasConnected) { |
593 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
594 | 0 | return; |
595 | 0 | } |
596 | 0 | } |
597 | | |
598 | | void |
599 | | AudioNode::Disconnect(AudioParam& aDestination, |
600 | | uint32_t aOutput, |
601 | | ErrorResult& aRv) |
602 | 0 | { |
603 | 0 | if (aOutput >= NumberOfOutputs()) { |
604 | 0 | aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); |
605 | 0 | return; |
606 | 0 | } |
607 | 0 | |
608 | 0 | bool wasConnected = false; |
609 | 0 |
|
610 | 0 | for (int32_t outputIndex = mOutputParams.Length() - 1; |
611 | 0 | outputIndex >= 0; --outputIndex) { |
612 | 0 | if (mOutputParams[outputIndex] != &aDestination) { |
613 | 0 | continue; |
614 | 0 | } |
615 | 0 | wasConnected |= |
616 | 0 | DisconnectMatchingDestinationInputs<AudioParam>( |
617 | 0 | outputIndex, |
618 | 0 | [aOutput](const InputNode& aInputNode) { |
619 | 0 | return aInputNode.mOutputPort == aOutput; |
620 | 0 | }); |
621 | 0 | } |
622 | 0 |
|
623 | 0 | if (!wasConnected) { |
624 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
625 | 0 | return; |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | | void |
630 | | AudioNode::DestroyMediaStream() |
631 | 0 | { |
632 | 0 | if (mStream) { |
633 | 0 | // Remove the node pointer on the engine. |
634 | 0 | AudioNodeStream* ns = mStream; |
635 | 0 | MOZ_ASSERT(ns, "How come we don't have a stream here?"); |
636 | 0 | MOZ_ASSERT(ns->Engine()->NodeMainThread() == this, |
637 | 0 | "Invalid node reference"); |
638 | 0 | ns->Engine()->ClearNode(); |
639 | 0 |
|
640 | 0 | mStream->Destroy(); |
641 | 0 | mStream = nullptr; |
642 | 0 |
|
643 | 0 | nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
644 | 0 | if (obs) { |
645 | 0 | nsAutoString id; |
646 | 0 | id.AppendPrintf("%u", mId); |
647 | 0 | obs->NotifyObservers(nullptr, "webaudio-node-demise", id.get()); |
648 | 0 | } |
649 | 0 | } |
650 | 0 | } |
651 | | |
652 | | void |
653 | | AudioNode::RemoveOutputParam(AudioParam* aParam) |
654 | 0 | { |
655 | 0 | mOutputParams.RemoveElement(aParam); |
656 | 0 | } |
657 | | |
658 | | bool |
659 | | AudioNode::PassThrough() const |
660 | 0 | { |
661 | 0 | MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1); |
662 | 0 | return mPassThrough; |
663 | 0 | } |
664 | | |
665 | | void |
666 | | AudioNode::SetPassThrough(bool aPassThrough) |
667 | 0 | { |
668 | 0 | MOZ_ASSERT(NumberOfInputs() <= 1 && NumberOfOutputs() == 1); |
669 | 0 | mPassThrough = aPassThrough; |
670 | 0 | if (mStream) { |
671 | 0 | mStream->SetPassThrough(mPassThrough); |
672 | 0 | } |
673 | 0 | } |
674 | | |
675 | | } // namespace dom |
676 | | } // namespace mozilla |