Line data Source code
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 : #include "MediaStreamTrack.h"
7 :
8 : #include "DOMMediaStream.h"
9 : #include "MediaStreamError.h"
10 : #include "MediaStreamGraph.h"
11 : #include "MediaStreamListener.h"
12 : #include "mozilla/dom/Promise.h"
13 : #include "nsContentUtils.h"
14 : #include "nsIUUIDGenerator.h"
15 : #include "nsServiceManagerUtils.h"
16 : #include "systemservices/MediaUtils.h"
17 :
18 : #ifdef LOG
19 : #undef LOG
20 : #endif
21 :
22 : static mozilla::LazyLogModule gMediaStreamTrackLog("MediaStreamTrack");
23 : #define LOG(type, msg) MOZ_LOG(gMediaStreamTrackLog, type, msg)
24 :
25 : using namespace mozilla::media;
26 :
27 : namespace mozilla {
28 : namespace dom {
29 :
30 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamTrackSource)
31 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamTrackSource)
32 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackSource)
33 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
34 0 : NS_INTERFACE_MAP_END
35 :
36 : NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource)
37 :
38 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaStreamTrackSource)
39 0 : tmp->Destroy();
40 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
41 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
42 :
43 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaStreamTrackSource)
44 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
45 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
46 :
47 : auto
48 0 : MediaStreamTrackSource::ApplyConstraints(
49 : nsPIDOMWindowInner* aWindow,
50 : const dom::MediaTrackConstraints& aConstraints,
51 : CallerType aCallerType) -> already_AddRefed<PledgeVoid>
52 : {
53 0 : RefPtr<PledgeVoid> p = new PledgeVoid();
54 0 : p->Reject(new MediaStreamError(aWindow,
55 0 : NS_LITERAL_STRING("OverconstrainedError"),
56 0 : NS_LITERAL_STRING("")));
57 0 : return p.forget();
58 : }
59 :
60 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamTrackConsumer)
61 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamTrackConsumer)
62 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackConsumer)
63 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
64 0 : NS_INTERFACE_MAP_END
65 :
66 0 : NS_IMPL_CYCLE_COLLECTION_0(MediaStreamTrackConsumer)
67 :
68 : /**
69 : * PrincipalHandleListener monitors changes in PrincipalHandle of the media flowing
70 : * through the MediaStreamGraph.
71 : *
72 : * When the main thread principal for a MediaStreamTrack changes, its principal
73 : * will be set to the combination of the previous principal and the new one.
74 : *
75 : * As a PrincipalHandle change later happens on the MediaStreamGraph thread, we will
76 : * be notified. If the latest principal on main thread matches the PrincipalHandle
77 : * we just saw on MSG thread, we will set the track's principal to the new one.
78 : *
79 : * We know at this point that the old principal has been flushed out and data
80 : * under it cannot leak to consumers.
81 : *
82 : * In case of multiple changes to the main thread state, the track's principal
83 : * will be a combination of its old principal and all the new ones until the
84 : * latest main thread principal matches the PrincipalHandle on the MSG thread.
85 : */
86 0 : class MediaStreamTrack::PrincipalHandleListener : public MediaStreamTrackListener
87 : {
88 : public:
89 0 : explicit PrincipalHandleListener(MediaStreamTrack* aTrack)
90 0 : : mTrack(aTrack)
91 0 : {}
92 :
93 0 : void Forget()
94 : {
95 0 : MOZ_ASSERT(NS_IsMainThread());
96 0 : mTrack = nullptr;
97 0 : }
98 :
99 0 : void DoNotifyPrincipalHandleChanged(const PrincipalHandle& aNewPrincipalHandle)
100 : {
101 0 : MOZ_ASSERT(NS_IsMainThread());
102 :
103 0 : if (!mTrack) {
104 0 : return;
105 : }
106 :
107 0 : mTrack->NotifyPrincipalHandleChanged(aNewPrincipalHandle);
108 : }
109 :
110 0 : void NotifyPrincipalHandleChanged(MediaStreamGraph* aGraph,
111 : const PrincipalHandle& aNewPrincipalHandle) override
112 : {
113 0 : aGraph->DispatchToMainThreadAfterStreamStateUpdate(
114 0 : NewRunnableMethod<StoreCopyPassByConstLRef<PrincipalHandle>>(
115 : "dom::MediaStreamTrack::PrincipalHandleListener::"
116 : "DoNotifyPrincipalHandleChanged",
117 : this,
118 : &PrincipalHandleListener::DoNotifyPrincipalHandleChanged,
119 0 : aNewPrincipalHandle));
120 0 : }
121 :
122 : protected:
123 : // These fields may only be accessed on the main thread
124 : MediaStreamTrack* mTrack;
125 : };
126 :
127 0 : MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
128 : TrackID aInputTrackID,
129 : MediaStreamTrackSource* aSource,
130 0 : const MediaTrackConstraints& aConstraints)
131 : : mOwningStream(aStream), mTrackID(aTrackID),
132 : mInputTrackID(aInputTrackID), mSource(aSource),
133 : mPrincipal(aSource->GetPrincipal()),
134 : mReadyState(MediaStreamTrackState::Live),
135 0 : mEnabled(true), mConstraints(aConstraints)
136 : {
137 0 : GetSource().RegisterSink(this);
138 :
139 0 : if (GetOwnedStream()) {
140 0 : mPrincipalHandleListener = new PrincipalHandleListener(this);
141 0 : AddListener(mPrincipalHandleListener);
142 : }
143 :
144 : nsresult rv;
145 : nsCOMPtr<nsIUUIDGenerator> uuidgen =
146 0 : do_GetService("@mozilla.org/uuid-generator;1", &rv);
147 :
148 : nsID uuid;
149 0 : memset(&uuid, 0, sizeof(uuid));
150 0 : if (uuidgen) {
151 0 : uuidgen->GenerateUUIDInPlace(&uuid);
152 : }
153 :
154 : char chars[NSID_LENGTH];
155 0 : uuid.ToProvidedString(chars);
156 0 : mID = NS_ConvertASCIItoUTF16(chars);
157 0 : }
158 :
159 0 : MediaStreamTrack::~MediaStreamTrack()
160 : {
161 0 : Destroy();
162 0 : }
163 :
164 : void
165 0 : MediaStreamTrack::Destroy()
166 : {
167 0 : if (mSource) {
168 0 : mSource->UnregisterSink(this);
169 : }
170 0 : if (mPrincipalHandleListener) {
171 0 : if (GetOwnedStream()) {
172 0 : RemoveListener(mPrincipalHandleListener);
173 : }
174 0 : mPrincipalHandleListener->Forget();
175 0 : mPrincipalHandleListener = nullptr;
176 : }
177 0 : for (auto l : mTrackListeners) {
178 0 : RemoveListener(l);
179 : }
180 0 : for (auto l : mDirectTrackListeners) {
181 0 : RemoveDirectListener(l);
182 : }
183 0 : }
184 :
185 : NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack)
186 :
187 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaStreamTrack,
188 : DOMEventTargetHelper)
189 0 : tmp->Destroy();
190 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsumers)
191 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningStream)
192 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
193 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalTrack)
194 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
195 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPrincipal)
196 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
197 :
198 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaStreamTrack,
199 : DOMEventTargetHelper)
200 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsumers)
201 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwningStream)
202 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
203 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalTrack)
204 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
205 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPrincipal)
206 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
207 :
208 0 : NS_IMPL_ADDREF_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
209 0 : NS_IMPL_RELEASE_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
210 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamTrack)
211 0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
212 :
213 : nsPIDOMWindowInner*
214 0 : MediaStreamTrack::GetParentObject() const
215 : {
216 0 : MOZ_RELEASE_ASSERT(mOwningStream);
217 0 : return mOwningStream->GetParentObject();
218 : }
219 :
220 : void
221 0 : MediaStreamTrack::GetId(nsAString& aID) const
222 : {
223 0 : aID = mID;
224 0 : }
225 :
226 : void
227 0 : MediaStreamTrack::SetEnabled(bool aEnabled)
228 : {
229 0 : LOG(LogLevel::Info, ("MediaStreamTrack %p %s",
230 : this, aEnabled ? "Enabled" : "Disabled"));
231 :
232 0 : mEnabled = aEnabled;
233 0 : GetOwnedStream()->SetTrackEnabled(mTrackID, mEnabled ? DisabledTrackMode::ENABLED
234 0 : : DisabledTrackMode::SILENCE_BLACK);
235 0 : }
236 :
237 : void
238 0 : MediaStreamTrack::Stop()
239 : {
240 0 : LOG(LogLevel::Info, ("MediaStreamTrack %p Stop()", this));
241 :
242 0 : if (Ended()) {
243 0 : LOG(LogLevel::Warning, ("MediaStreamTrack %p Already ended", this));
244 0 : return;
245 : }
246 :
247 0 : if (!mSource) {
248 0 : MOZ_ASSERT(false);
249 : return;
250 : }
251 :
252 0 : mSource->UnregisterSink(this);
253 :
254 0 : MOZ_ASSERT(mOwningStream, "Every MediaStreamTrack needs an owning DOMMediaStream");
255 0 : DOMMediaStream::TrackPort* port = mOwningStream->FindOwnedTrackPort(*this);
256 0 : MOZ_ASSERT(port, "A MediaStreamTrack must exist in its owning DOMMediaStream");
257 0 : RefPtr<Pledge<bool>> p = port->BlockSourceTrackId(mInputTrackID, BlockingMode::CREATION);
258 : Unused << p;
259 :
260 0 : mReadyState = MediaStreamTrackState::Ended;
261 :
262 0 : NotifyEnded();
263 : }
264 :
265 : void
266 0 : MediaStreamTrack::GetConstraints(dom::MediaTrackConstraints& aResult)
267 : {
268 0 : aResult = mConstraints;
269 0 : }
270 :
271 : void
272 0 : MediaStreamTrack::GetSettings(dom::MediaTrackSettings& aResult)
273 : {
274 0 : GetSource().GetSettings(aResult);
275 0 : }
276 :
277 : already_AddRefed<Promise>
278 0 : MediaStreamTrack::ApplyConstraints(const MediaTrackConstraints& aConstraints,
279 : CallerType aCallerType,
280 : ErrorResult &aRv)
281 : {
282 0 : if (MOZ_LOG_TEST(gMediaStreamTrackLog, LogLevel::Info)) {
283 0 : nsString str;
284 0 : aConstraints.ToJSON(str);
285 :
286 0 : LOG(LogLevel::Info, ("MediaStreamTrack %p ApplyConstraints() with "
287 : "constraints %s", this, NS_ConvertUTF16toUTF8(str).get()));
288 : }
289 :
290 : typedef media::Pledge<bool, MediaStreamError*> PledgeVoid;
291 :
292 0 : nsPIDOMWindowInner* window = mOwningStream->GetParentObject();
293 :
294 0 : nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window);
295 0 : RefPtr<Promise> promise = Promise::Create(go, aRv);
296 :
297 : // Forward constraints to the source.
298 : //
299 : // After GetSource().ApplyConstraints succeeds (after it's been to media-thread
300 : // and back), and no sooner, do we set mConstraints to the newly applied values.
301 :
302 : // Keep a reference to this, to make sure it's still here when we get back.
303 0 : RefPtr<MediaStreamTrack> that = this;
304 0 : RefPtr<PledgeVoid> p = GetSource().ApplyConstraints(window, aConstraints,
305 0 : aCallerType);
306 0 : p->Then([this, that, promise, aConstraints](bool& aDummy) mutable {
307 0 : mConstraints = aConstraints;
308 0 : promise->MaybeResolve(false);
309 0 : }, [promise](MediaStreamError*& reason) mutable {
310 0 : promise->MaybeReject(reason);
311 0 : });
312 0 : return promise.forget();
313 : }
314 :
315 : MediaStreamGraph*
316 0 : MediaStreamTrack::Graph()
317 : {
318 0 : return GetOwnedStream()->Graph();
319 : }
320 :
321 : MediaStreamGraphImpl*
322 0 : MediaStreamTrack::GraphImpl()
323 : {
324 0 : return GetOwnedStream()->GraphImpl();
325 : }
326 :
327 : void
328 0 : MediaStreamTrack::SetPrincipal(nsIPrincipal* aPrincipal)
329 : {
330 0 : if (aPrincipal == mPrincipal) {
331 0 : return;
332 : }
333 0 : mPrincipal = aPrincipal;
334 :
335 0 : LOG(LogLevel::Info, ("MediaStreamTrack %p principal changed to %p. Now: "
336 : "null=%d, codebase=%d, expanded=%d, system=%d",
337 : this, mPrincipal.get(),
338 : mPrincipal->GetIsNullPrincipal(),
339 : mPrincipal->GetIsCodebasePrincipal(),
340 : mPrincipal->GetIsExpandedPrincipal(),
341 : mPrincipal->GetIsSystemPrincipal()));
342 0 : for (PrincipalChangeObserver<MediaStreamTrack>* observer
343 0 : : mPrincipalChangeObservers) {
344 0 : observer->PrincipalChanged(this);
345 : }
346 : }
347 :
348 : void
349 0 : MediaStreamTrack::PrincipalChanged()
350 : {
351 0 : mPendingPrincipal = GetSource().GetPrincipal();
352 0 : nsCOMPtr<nsIPrincipal> newPrincipal = mPrincipal;
353 0 : LOG(LogLevel::Info, ("MediaStreamTrack %p Principal changed on main thread "
354 : "to %p (pending). Combining with existing principal %p.",
355 : this, mPendingPrincipal.get(), mPrincipal.get()));
356 0 : if (nsContentUtils::CombineResourcePrincipals(&newPrincipal,
357 : mPendingPrincipal)) {
358 0 : SetPrincipal(newPrincipal);
359 : }
360 0 : }
361 :
362 : void
363 0 : MediaStreamTrack::NotifyPrincipalHandleChanged(const PrincipalHandle& aNewPrincipalHandle)
364 : {
365 0 : PrincipalHandle handle(aNewPrincipalHandle);
366 0 : LOG(LogLevel::Info, ("MediaStreamTrack %p principalHandle changed on "
367 : "MediaStreamGraph thread to %p. Current principal: %p, "
368 : "pending: %p",
369 : this, GetPrincipalFromHandle(handle),
370 : mPrincipal.get(), mPendingPrincipal.get()));
371 0 : if (PrincipalHandleMatches(handle, mPendingPrincipal)) {
372 0 : SetPrincipal(mPendingPrincipal);
373 0 : mPendingPrincipal = nullptr;
374 : }
375 0 : }
376 :
377 : void
378 0 : MediaStreamTrack::NotifyEnded()
379 : {
380 0 : MOZ_ASSERT(mReadyState == MediaStreamTrackState::Ended);
381 :
382 0 : for (int32_t i = mConsumers.Length() - 1; i >= 0; --i) {
383 : // Loop backwards by index in case the consumer removes itself in the
384 : // callback.
385 0 : mConsumers[i]->NotifyEnded(this);
386 : }
387 0 : }
388 :
389 : bool
390 0 : MediaStreamTrack::AddPrincipalChangeObserver(
391 : PrincipalChangeObserver<MediaStreamTrack>* aObserver)
392 : {
393 0 : return mPrincipalChangeObservers.AppendElement(aObserver) != nullptr;
394 : }
395 :
396 : bool
397 0 : MediaStreamTrack::RemovePrincipalChangeObserver(
398 : PrincipalChangeObserver<MediaStreamTrack>* aObserver)
399 : {
400 0 : return mPrincipalChangeObservers.RemoveElement(aObserver);
401 : }
402 :
403 : void
404 0 : MediaStreamTrack::AddConsumer(MediaStreamTrackConsumer* aConsumer)
405 : {
406 0 : MOZ_ASSERT(!mConsumers.Contains(aConsumer));
407 0 : mConsumers.AppendElement(aConsumer);
408 0 : }
409 :
410 : void
411 0 : MediaStreamTrack::RemoveConsumer(MediaStreamTrackConsumer* aConsumer)
412 : {
413 0 : mConsumers.RemoveElement(aConsumer);
414 0 : }
415 :
416 : already_AddRefed<MediaStreamTrack>
417 0 : MediaStreamTrack::Clone()
418 : {
419 : // MediaStreamTracks are currently governed by streams, so we need a dummy
420 : // DOMMediaStream to own our track clone. The dummy will never see any
421 : // dynamically created tracks (no input stream) so no need for a SourceGetter.
422 : RefPtr<DOMMediaStream> newStream =
423 0 : new DOMMediaStream(mOwningStream->GetParentObject(), nullptr);
424 :
425 0 : MediaStreamGraph* graph = Graph();
426 0 : newStream->InitOwnedStreamCommon(graph);
427 0 : newStream->InitPlaybackStreamCommon(graph);
428 :
429 0 : return newStream->CloneDOMTrack(*this, mTrackID);
430 : }
431 :
432 : void
433 0 : MediaStreamTrack::SetReadyState(MediaStreamTrackState aState)
434 : {
435 0 : MOZ_ASSERT(!(mReadyState == MediaStreamTrackState::Ended &&
436 : aState == MediaStreamTrackState::Live),
437 : "We don't support overriding the ready state from ended to live");
438 :
439 0 : if (mReadyState == MediaStreamTrackState::Live &&
440 0 : aState == MediaStreamTrackState::Ended &&
441 0 : mSource) {
442 0 : mSource->UnregisterSink(this);
443 : }
444 :
445 0 : mReadyState = aState;
446 0 : }
447 :
448 : void
449 0 : MediaStreamTrack::OverrideEnded()
450 : {
451 0 : MOZ_ASSERT(NS_IsMainThread());
452 :
453 0 : if (Ended()) {
454 0 : return;
455 : }
456 :
457 0 : LOG(LogLevel::Info, ("MediaStreamTrack %p ended", this));
458 :
459 0 : if (!mSource) {
460 0 : MOZ_ASSERT(false);
461 : return;
462 : }
463 :
464 0 : mSource->UnregisterSink(this);
465 :
466 0 : mReadyState = MediaStreamTrackState::Ended;
467 :
468 0 : NotifyEnded();
469 :
470 0 : DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
471 : }
472 :
473 : DOMMediaStream*
474 0 : MediaStreamTrack::GetInputDOMStream()
475 : {
476 : MediaStreamTrack* originalTrack =
477 0 : mOriginalTrack ? mOriginalTrack.get() : this;
478 0 : MOZ_RELEASE_ASSERT(originalTrack->mOwningStream);
479 0 : return originalTrack->mOwningStream;
480 : }
481 :
482 : MediaStream*
483 0 : MediaStreamTrack::GetInputStream()
484 : {
485 0 : DOMMediaStream* inputDOMStream = GetInputDOMStream();
486 0 : MOZ_RELEASE_ASSERT(inputDOMStream->GetInputStream());
487 0 : return inputDOMStream->GetInputStream();
488 : }
489 :
490 : ProcessedMediaStream*
491 0 : MediaStreamTrack::GetOwnedStream()
492 : {
493 0 : if (!mOwningStream)
494 : {
495 0 : return nullptr;
496 : }
497 :
498 0 : return mOwningStream->GetOwnedStream();
499 : }
500 :
501 : void
502 0 : MediaStreamTrack::AddListener(MediaStreamTrackListener* aListener)
503 : {
504 0 : LOG(LogLevel::Debug, ("MediaStreamTrack %p adding listener %p",
505 : this, aListener));
506 0 : MOZ_ASSERT(GetOwnedStream());
507 :
508 0 : GetOwnedStream()->AddTrackListener(aListener, mTrackID);
509 0 : mTrackListeners.AppendElement(aListener);
510 0 : }
511 :
512 : void
513 0 : MediaStreamTrack::RemoveListener(MediaStreamTrackListener* aListener)
514 : {
515 0 : LOG(LogLevel::Debug, ("MediaStreamTrack %p removing listener %p",
516 : this, aListener));
517 :
518 0 : if (GetOwnedStream()) {
519 0 : GetOwnedStream()->RemoveTrackListener(aListener, mTrackID);
520 0 : mTrackListeners.RemoveElement(aListener);
521 : }
522 0 : }
523 :
524 : void
525 0 : MediaStreamTrack::AddDirectListener(DirectMediaStreamTrackListener *aListener)
526 : {
527 0 : LOG(LogLevel::Debug, ("MediaStreamTrack %p (%s) adding direct listener %p to "
528 : "stream %p, track %d",
529 : this, AsAudioStreamTrack() ? "audio" : "video",
530 : aListener, GetOwnedStream(), mTrackID));
531 0 : MOZ_ASSERT(GetOwnedStream());
532 :
533 0 : GetOwnedStream()->AddDirectTrackListener(aListener, mTrackID);
534 0 : mDirectTrackListeners.AppendElement(aListener);
535 0 : }
536 :
537 : void
538 0 : MediaStreamTrack::RemoveDirectListener(DirectMediaStreamTrackListener *aListener)
539 : {
540 0 : LOG(LogLevel::Debug, ("MediaStreamTrack %p removing direct listener %p from stream %p",
541 : this, aListener, GetOwnedStream()));
542 :
543 0 : if (GetOwnedStream()) {
544 0 : GetOwnedStream()->RemoveDirectTrackListener(aListener, mTrackID);
545 0 : mDirectTrackListeners.RemoveElement(aListener);
546 : }
547 0 : }
548 :
549 : already_AddRefed<MediaInputPort>
550 0 : MediaStreamTrack::ForwardTrackContentsTo(ProcessedMediaStream* aStream,
551 : TrackID aDestinationTrackID)
552 : {
553 0 : MOZ_ASSERT(NS_IsMainThread());
554 0 : MOZ_RELEASE_ASSERT(aStream);
555 : RefPtr<MediaInputPort> port =
556 0 : aStream->AllocateInputPort(GetOwnedStream(), mTrackID, aDestinationTrackID);
557 0 : return port.forget();
558 : }
559 :
560 : bool
561 0 : MediaStreamTrack::IsForwardedThrough(MediaInputPort* aPort)
562 : {
563 0 : MOZ_ASSERT(NS_IsMainThread());
564 0 : MOZ_ASSERT(aPort);
565 0 : if (!aPort) {
566 0 : return false;
567 : }
568 0 : return aPort->GetSource() == GetOwnedStream() &&
569 0 : aPort->PassTrackThrough(mTrackID);
570 : }
571 :
572 : } // namespace dom
573 : } // namespace mozilla
|