Coverage Report

Created: 2018-09-25 14:53

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