1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "MediaStreamTrackAudioSourceNode.h"
8 #include "mozilla/dom/MediaStreamTrackAudioSourceNodeBinding.h"
9 #include "AudioNodeEngine.h"
10 #include "AudioNodeExternalInputTrack.h"
11 #include "AudioStreamTrack.h"
12 #include "mozilla/dom/Document.h"
13 #include "nsContentUtils.h"
14 #include "nsIScriptError.h"
16 namespace mozilla::dom
{
18 NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrackAudioSourceNode
)
20 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaStreamTrackAudioSourceNode
)
22 NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputTrack
)
23 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
24 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(AudioNode
)
26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
27 MediaStreamTrackAudioSourceNode
, AudioNode
)
28 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputTrack
)
29 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
31 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackAudioSourceNode
)
32 NS_INTERFACE_MAP_END_INHERITING(AudioNode
)
34 NS_IMPL_ADDREF_INHERITED(MediaStreamTrackAudioSourceNode
, AudioNode
)
35 NS_IMPL_RELEASE_INHERITED(MediaStreamTrackAudioSourceNode
, AudioNode
)
37 MediaStreamTrackAudioSourceNode::MediaStreamTrackAudioSourceNode(
38 AudioContext
* aContext
)
39 : AudioNode(aContext
, 2, ChannelCountMode::Max
,
40 ChannelInterpretation::Speakers
),
41 mTrackListener(this) {}
43 /* static */ already_AddRefed
<MediaStreamTrackAudioSourceNode
>
44 MediaStreamTrackAudioSourceNode::Create(
45 AudioContext
& aAudioContext
,
46 const MediaStreamTrackAudioSourceOptions
& aOptions
, ErrorResult
& aRv
) {
47 // The spec has a pointless check here. See
48 // https://github.com/WebAudio/web-audio-api/issues/2149
49 MOZ_RELEASE_ASSERT(!aAudioContext
.IsOffline(), "Bindings messed up?");
51 if (!aOptions
.mMediaStreamTrack
->Ended() &&
52 aAudioContext
.Graph() != aOptions
.mMediaStreamTrack
->Graph()) {
53 nsCOMPtr
<nsPIDOMWindowInner
> pWindow
= aAudioContext
.GetParentObject();
54 Document
* document
= pWindow
? pWindow
->GetExtantDoc() : nullptr;
55 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
, "Web Audio"_ns
,
56 document
, nsContentUtils::eDOM_PROPERTIES
,
57 "MediaStreamAudioSourceNodeDifferentRate");
58 // This is not a spec-required exception, just a limitation of our
60 aRv
.ThrowNotSupportedError(
61 "Connecting AudioNodes from AudioContexts with different sample-rate "
62 "is currently not supported.");
66 RefPtr
<MediaStreamTrackAudioSourceNode
> node
=
67 new MediaStreamTrackAudioSourceNode(&aAudioContext
);
69 node
->Init(aOptions
.mMediaStreamTrack
, aRv
);
77 void MediaStreamTrackAudioSourceNode::Init(MediaStreamTrack
* aMediaStreamTrack
,
79 MOZ_ASSERT(aMediaStreamTrack
);
81 if (!aMediaStreamTrack
->AsAudioStreamTrack()) {
82 aRv
.ThrowInvalidStateError("\"mediaStreamTrack\" must be an audio track");
86 if (aMediaStreamTrack
->Ended()) {
87 // The track is ended and will never produce any data. Pretend like this is
94 MediaTrackGraph
* graph
= Context()->Graph();
96 AudioNodeEngine
* engine
= new MediaStreamTrackAudioSourceNodeEngine(this);
97 mTrack
= AudioNodeExternalInputTrack::Create(graph
, engine
);
101 mInputTrack
= aMediaStreamTrack
;
102 ProcessedMediaTrack
* outputTrack
=
103 static_cast<ProcessedMediaTrack
*>(mTrack
.get());
104 mInputPort
= mInputTrack
->ForwardTrackContentsTo(outputTrack
);
105 PrincipalChanged(mInputTrack
); // trigger enabling/disabling of the connector
106 mInputTrack
->AddPrincipalChangeObserver(this);
108 mInputTrack
->AddConsumer(&mTrackListener
);
111 void MediaStreamTrackAudioSourceNode::Destroy() {
113 mTrackListener
.NotifyEnded(mInputTrack
);
114 mInputTrack
->RemovePrincipalChangeObserver(this);
115 mInputTrack
->RemoveConsumer(&mTrackListener
);
116 mInputTrack
= nullptr;
120 mInputPort
->Destroy();
121 mInputPort
= nullptr;
125 MediaStreamTrackAudioSourceNode::~MediaStreamTrackAudioSourceNode() {
130 * Changes the principal. Note that this will be called on the main thread, but
131 * changes will be enacted on the MediaTrackGraph thread. If the principal
132 * change results in the document principal losing access to the track, then
133 * there needs to be other measures in place to ensure that any media that is
134 * governed by the new track principal is not available to the MediaTrackGraph
135 * before this change completes. Otherwise, a site could get access to
136 * media that they are not authorized to receive.
138 * One solution is to block the altered content, call this method, then dispatch
139 * another change request to the MediaTrackGraph thread that allows the content
140 * under the new principal to flow. This might be unnecessary if the principal
141 * change is changing to be the document principal.
143 void MediaStreamTrackAudioSourceNode::PrincipalChanged(
144 MediaStreamTrack
* aMediaStreamTrack
) {
145 MOZ_ASSERT(aMediaStreamTrack
== mInputTrack
);
147 bool subsumes
= false;
148 Document
* doc
= nullptr;
149 if (nsPIDOMWindowInner
* parent
= Context()->GetParentObject()) {
150 doc
= parent
->GetExtantDoc();
152 nsIPrincipal
* docPrincipal
= doc
->NodePrincipal();
153 nsIPrincipal
* trackPrincipal
= aMediaStreamTrack
->GetPrincipal();
154 if (!trackPrincipal
||
155 NS_FAILED(docPrincipal
->Subsumes(trackPrincipal
, &subsumes
))) {
160 auto track
= static_cast<AudioNodeExternalInputTrack
*>(mTrack
.get());
161 bool enabled
= subsumes
;
162 track
->SetInt32Parameter(MediaStreamTrackAudioSourceNodeEngine::ENABLE
,
164 fprintf(stderr
, "NOW: %s", enabled
? "enabled" : "disabled");
166 if (!enabled
&& doc
) {
167 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
, "Web Audio"_ns
,
168 doc
, nsContentUtils::eDOM_PROPERTIES
,
169 CrossOriginErrorString());
173 size_t MediaStreamTrackAudioSourceNode::SizeOfExcludingThis(
174 MallocSizeOf aMallocSizeOf
) const {
175 size_t amount
= AudioNode::SizeOfExcludingThis(aMallocSizeOf
);
177 amount
+= mInputPort
->SizeOfIncludingThis(aMallocSizeOf
);
182 size_t MediaStreamTrackAudioSourceNode::SizeOfIncludingThis(
183 MallocSizeOf aMallocSizeOf
) const {
184 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
187 void MediaStreamTrackAudioSourceNode::DestroyMediaTrack() {
189 mInputPort
->Destroy();
190 mInputPort
= nullptr;
192 AudioNode::DestroyMediaTrack();
195 JSObject
* MediaStreamTrackAudioSourceNode::WrapObject(
196 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
197 return MediaStreamTrackAudioSourceNode_Binding::Wrap(aCx
, this, aGivenProto
);
200 } // namespace mozilla::dom