Bug 1652884 - Propagate disabled mode to consumer tracks in the graph. r=karlt
authorAndreas Pehrson <apehrson@mozilla.com>
Wed, 19 Aug 2020 22:18:44 +0000
changeset 545445 cca31f035f1817199990b8fa196c6cb2ae706dee
parent 545444 b16a8e267157a82ba9a01b6e235462c989c8a8ac
child 545446 46132c70fae0d4045f1de8b8c495a4eaa4a1ddaf
push id37713
push userabutkovits@mozilla.com
push dateThu, 20 Aug 2020 09:32:09 +0000
treeherdermozilla-central@8cb700c12bd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1652884
milestone81.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1652884 - Propagate disabled mode to consumer tracks in the graph. r=karlt This enables a use case where MediaManager disables a MediaStreamTrack's input track, and all listeners of NotifyEnabledStateChanged on the MediaStreamTrack's main track will get notified. There can be 1 input track for N MediaStreamTracks, so this simplifies how many tracks will need to be tracked by MediaManager and explicitly disabled in the graph. Depends on D86072 Differential Revision: https://phabricator.services.mozilla.com/D86925
dom/media/ForwardedInputTrack.cpp
dom/media/ForwardedInputTrack.h
dom/media/MediaTrackGraph.cpp
dom/media/MediaTrackGraph.h
--- a/dom/media/ForwardedInputTrack.cpp
+++ b/dom/media/ForwardedInputTrack.cpp
@@ -61,34 +61,45 @@ void ForwardedInputTrack::RemoveInput(Me
   for (const auto& listener : mOwnedDirectListeners) {
     MediaTrack* source = mInputPort->GetSource();
     TRACK_LOG(LogLevel::Debug,
               ("ForwardedInputTrack %p removing direct listener "
                "%p. Forwarding to input track %p.",
                this, listener.get(), aPort->GetSource()));
     source->RemoveDirectListenerImpl(listener);
   }
+
+  DisabledTrackMode oldMode = CombinedDisabledMode();
+  mInputDisabledMode = DisabledTrackMode::ENABLED;
+  NotifyIfDisabledModeChangedFrom(oldMode);
+
   mInputPort = nullptr;
   ProcessedMediaTrack::RemoveInput(aPort);
 }
 
 void ForwardedInputTrack::SetInput(MediaInputPort* aPort) {
   MOZ_ASSERT(aPort);
   MOZ_ASSERT(aPort->GetSource());
   MOZ_ASSERT(aPort->GetSource()->GetData());
   MOZ_ASSERT(!mInputPort);
+  MOZ_ASSERT(mInputDisabledMode == DisabledTrackMode::ENABLED);
+
   mInputPort = aPort;
 
   for (const auto& listener : mOwnedDirectListeners) {
     MediaTrack* source = mInputPort->GetSource();
     TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p adding direct listener "
                                 "%p. Forwarding to input track %p.",
                                 this, listener.get(), aPort->GetSource()));
     source->AddDirectListenerImpl(do_AddRef(listener));
   }
+
+  DisabledTrackMode oldMode = CombinedDisabledMode();
+  mInputDisabledMode = mInputPort->GetSource()->CombinedDisabledMode();
+  NotifyIfDisabledModeChangedFrom(oldMode);
 }
 
 void ForwardedInputTrack::ProcessInputImpl(MediaTrack* aSource,
                                            MediaSegment* aSegment,
                                            GraphTime aFrom, GraphTime aTo,
                                            uint32_t aFlags) {
   GraphTime next;
   for (GraphTime t = aFrom; t < aTo; t = next) {
@@ -165,16 +176,28 @@ void ForwardedInputTrack::ProcessInput(G
     MOZ_CRASH("Unknown segment type");
   }
 
   if (mEnded) {
     RemoveAllDirectListenersImpl();
   }
 }
 
+DisabledTrackMode ForwardedInputTrack::CombinedDisabledMode() const {
+  if (mDisabledMode == DisabledTrackMode::SILENCE_BLACK ||
+      mInputDisabledMode == DisabledTrackMode::SILENCE_BLACK) {
+    return DisabledTrackMode::SILENCE_BLACK;
+  }
+  if (mDisabledMode == DisabledTrackMode::SILENCE_FREEZE ||
+      mInputDisabledMode == DisabledTrackMode::SILENCE_FREEZE) {
+    return DisabledTrackMode::SILENCE_FREEZE;
+  }
+  return DisabledTrackMode::ENABLED;
+}
+
 void ForwardedInputTrack::SetDisabledTrackModeImpl(DisabledTrackMode aMode) {
   bool enabled = aMode == DisabledTrackMode::ENABLED;
   TRACK_LOG(LogLevel::Info, ("ForwardedInputTrack %p was explicitly %s", this,
                              enabled ? "enabled" : "disabled"));
   for (DirectMediaTrackListener* listener : mOwnedDirectListeners) {
     DisabledTrackMode oldMode = mDisabledMode;
     bool oldEnabled = oldMode == DisabledTrackMode::ENABLED;
     if (!oldEnabled && enabled) {
@@ -187,16 +210,31 @@ void ForwardedInputTrack::SetDisabledTra
                                   "direct listener disabled",
                                   this));
       listener->IncreaseDisabled(aMode);
     }
   }
   MediaTrack::SetDisabledTrackModeImpl(aMode);
 }
 
+void ForwardedInputTrack::OnInputDisabledModeChanged(
+    DisabledTrackMode aInputMode) {
+  MOZ_ASSERT(mInputs.Length() == 1);
+  MOZ_ASSERT(mInputs[0]->GetSource());
+  DisabledTrackMode oldMode = CombinedDisabledMode();
+  if (mInputDisabledMode == DisabledTrackMode::SILENCE_BLACK &&
+      aInputMode == DisabledTrackMode::SILENCE_FREEZE) {
+    // Don't allow demoting from SILENCE_BLACK to SILENCE_FREEZE. Frames will
+    // remain black so we shouldn't notify that the track got enabled.
+    aInputMode = DisabledTrackMode::SILENCE_BLACK;
+  }
+  mInputDisabledMode = aInputMode;
+  NotifyIfDisabledModeChangedFrom(oldMode);
+}
+
 void ForwardedInputTrack::AddDirectListenerImpl(
     already_AddRefed<DirectMediaTrackListener> aListener) {
   RefPtr<DirectMediaTrackListener> listener = aListener;
   mOwnedDirectListeners.AppendElement(listener);
 
   DisabledTrackMode currentMode = mDisabledMode;
   if (currentMode != DisabledTrackMode::ENABLED) {
     listener->IncreaseDisabled(currentMode);
--- a/dom/media/ForwardedInputTrack.h
+++ b/dom/media/ForwardedInputTrack.h
@@ -21,17 +21,19 @@ class ForwardedInputTrack : public Proce
 
   virtual ForwardedInputTrack* AsForwardedInputTrack() override { return this; }
   friend class DOMMediaStream;
 
   void AddInput(MediaInputPort* aPort) override;
   void RemoveInput(MediaInputPort* aPort) override;
   void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
 
+  DisabledTrackMode CombinedDisabledMode() const override;
   void SetDisabledTrackModeImpl(DisabledTrackMode aMode) override;
+  void OnInputDisabledModeChanged(DisabledTrackMode aInputMode) override;
 
   friend class MediaTrackGraphImpl;
 
  protected:
   // Set up this track from a specific input.
   void SetInput(MediaInputPort* aPort);
 
   // MediaSegment-agnostic ProcessInput.
@@ -47,13 +49,18 @@ class ForwardedInputTrack : public Proce
   // ForwardedInputTrack-track. While an input is set, these are forwarded to
   // the input track. We will update these when this track's disabled status
   // changes.
   nsTArray<RefPtr<DirectMediaTrackListener>> mOwnedDirectListeners;
 
   // Set if an input has been added, nullptr otherwise. Adding more than one
   // input is an error.
   MediaInputPort* mInputPort = nullptr;
+
+  // This track's input's associated disabled mode. ENABLED if there is no
+  // input. This is used with MediaTrackListener::NotifyEnabledStateChanged(),
+  // which affects only video tracks. This is set only on ForwardedInputTracks.
+  DisabledTrackMode mInputDisabledMode = DisabledTrackMode::ENABLED;
 };
 
 }  // namespace mozilla
 
 #endif /* MOZILLA_FORWARDEDINPUTTRACK_H_ */
--- a/dom/media/MediaTrackGraph.cpp
+++ b/dom/media/MediaTrackGraph.cpp
@@ -2176,17 +2176,17 @@ void MediaTrack::AddListenerImpl(
   mTrackListeners.AppendElement(move(l));
 
   PrincipalHandle lastPrincipalHandle = mSegment->GetLastPrincipalHandle();
   mTrackListeners.LastElement()->NotifyPrincipalHandleChanged(
       Graph(), lastPrincipalHandle);
   if (mNotifiedEnded) {
     mTrackListeners.LastElement()->NotifyEnded(Graph());
   }
-  if (mDisabledMode == DisabledTrackMode::SILENCE_BLACK) {
+  if (CombinedDisabledMode() == DisabledTrackMode::SILENCE_BLACK) {
     mTrackListeners.LastElement()->NotifyEnabledStateChanged(Graph(), false);
   }
 }
 
 void MediaTrack::AddListener(MediaTrackListener* aListener) {
   class Message : public ControlMessage {
    public:
     Message(MediaTrack* aTrack, MediaTrackListener* aListener)
@@ -2312,32 +2312,23 @@ void MediaTrack::RunAfterPendingUpdates(
 
   if (mMainThreadDestroyed) {
     return;
   }
   graph->AppendMessage(MakeUnique<Message>(this, runnable.forget()));
 }
 
 void MediaTrack::SetDisabledTrackModeImpl(DisabledTrackMode aMode) {
-  if (aMode == DisabledTrackMode::ENABLED) {
-    mDisabledMode = DisabledTrackMode::ENABLED;
-    for (const auto& l : mTrackListeners) {
-      l->NotifyEnabledStateChanged(Graph(), true);
-    }
-  } else {
-    MOZ_DIAGNOSTIC_ASSERT(
-        mDisabledMode == DisabledTrackMode::ENABLED,
-        "Changing disabled track mode for a track is not allowed");
-    mDisabledMode = aMode;
-    if (aMode == DisabledTrackMode::SILENCE_BLACK) {
-      for (const auto& l : mTrackListeners) {
-        l->NotifyEnabledStateChanged(Graph(), false);
-      }
-    }
-  }
+  MOZ_DIAGNOSTIC_ASSERT(
+      aMode == DisabledTrackMode::ENABLED ||
+          mDisabledMode == DisabledTrackMode::ENABLED,
+      "Changing disabled track mode for a track is not allowed");
+  DisabledTrackMode oldMode = CombinedDisabledMode();
+  mDisabledMode = aMode;
+  NotifyIfDisabledModeChangedFrom(oldMode);
 }
 
 void MediaTrack::SetDisabledTrackMode(DisabledTrackMode aMode) {
   class Message : public ControlMessage {
    public:
     Message(MediaTrack* aTrack, DisabledTrackMode aMode)
         : ControlMessage(aTrack), mMode(aMode) {}
     void Run() override { mTrack->SetDisabledTrackModeImpl(mMode); }
@@ -2419,16 +2410,34 @@ void MediaTrack::AdvanceTimeVaryingValue
   if (time < mForgottenTime + minChunkSize) {
     return;
   }
 
   mForgottenTime = std::min(GetEnd() - 1, time);
   mSegment->ForgetUpTo(mForgottenTime);
 }
 
+void MediaTrack::NotifyIfDisabledModeChangedFrom(DisabledTrackMode aOldMode) {
+  DisabledTrackMode mode = CombinedDisabledMode();
+  if (aOldMode == mode) {
+    return;
+  }
+
+  for (const auto& listener : mTrackListeners) {
+    listener->NotifyEnabledStateChanged(
+        Graph(), mode != DisabledTrackMode::SILENCE_BLACK);
+  }
+
+  for (const auto& c : mConsumers) {
+    if (c->GetDestination()) {
+      c->GetDestination()->OnInputDisabledModeChanged(mode);
+    }
+  }
+}
+
 SourceMediaTrack::SourceMediaTrack(MediaSegment::Type aType,
                                    TrackRate aSampleRate)
     : MediaTrack(aSampleRate, aType,
                  aType == MediaSegment::AUDIO
                      ? static_cast<MediaSegment*>(new AudioSegment())
                      : static_cast<MediaSegment*>(new VideoSegment())),
       mMutex("mozilla::media::SourceMediaTrack") {
   mUpdateTrack = MakeUnique<TrackData>();
--- a/dom/media/MediaTrackGraph.h
+++ b/dom/media/MediaTrackGraph.h
@@ -415,16 +415,22 @@ class MediaTrack : public mozilla::Linke
 
   void AddConsumer(MediaInputPort* aPort) { mConsumers.AppendElement(aPort); }
   void RemoveConsumer(MediaInputPort* aPort) {
     mConsumers.RemoveElement(aPort);
   }
   GraphTime StartTime() const { return mStartTime; }
   bool Ended() const { return mEnded; }
 
+  // The DisabledTrackMode after combining the explicit mode and that of the
+  // input, if any.
+  virtual DisabledTrackMode CombinedDisabledMode() const {
+    return mDisabledMode;
+  }
+
   template <class SegmentType>
   SegmentType* GetData() const {
     if (!mSegment) {
       return nullptr;
     }
     if (mSegment->GetType() != SegmentType::StaticType()) {
       return nullptr;
     }
@@ -521,16 +527,20 @@ class MediaTrack : public mozilla::Linke
     if (!mMainThreadEnded || mEndedNotificationSent) {
       return false;
     }
 
     mEndedNotificationSent = true;
     return true;
   }
 
+  // Notifies listeners and consumers of the change in disabled mode when the
+  // current combined mode is different from aMode.
+  void NotifyIfDisabledModeChangedFrom(DisabledTrackMode aOldMode);
+
   // This state is all initialized on the main thread but
   // otherwise modified only on the media graph thread.
 
   // Buffered data. The start of the buffer corresponds to mStartTime.
   // Conceptually the buffer contains everything this track has ever played,
   // but we forget some prefix of the buffered data to bound the space usage.
   // Note that this may be null for tracks that never contain data, like
   // non-external AudioNodeTracks.
@@ -956,16 +966,19 @@ class ProcessedMediaTrack : public Media
                             uint32_t aFlags) = 0;
   void SetAutoendImpl(bool aAutoend) { mAutoend = aAutoend; }
 
   // Only valid after MediaTrackGraphImpl::UpdateTrackOrder() has run.
   // A DelayNode is considered to break a cycle and so this will not return
   // true for echo loops, only for muted cycles.
   bool InMutedCycle() const { return mCycleMarker; }
 
+  // Used by ForwardedInputTrack to propagate the disabled mode along the graph.
+  virtual void OnInputDisabledModeChanged(DisabledTrackMode aMode) {}
+
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override {
     size_t amount = MediaTrack::SizeOfExcludingThis(aMallocSizeOf);
     // Not owned:
     // - mInputs elements
     // - mSuspendedInputs elements
     amount += mInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
     amount += mSuspendedInputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
     return amount;