Bug 827007: Implement Stop for UserMediaStreams; add NotifyRemoved for MediaStream listeners r=roc
authorRandell Jesup <rjesup@jesup.org>
Sun, 06 Jan 2013 21:31:30 -0500
changeset 126983 f141d1e00ceb94e9982b2a9a2b9eb213d462bc8e
parent 126982 36467bcc46ada793724af4005deaf3ae36f9dda7
child 126984 177d8769bb85b2a2895b04903ca039868896c4ab
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs827007
milestone20.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 827007: Implement Stop for UserMediaStreams; add NotifyRemoved for MediaStream listeners r=roc
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraph.h
dom/media/MediaManager.cpp
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1772,18 +1772,30 @@ MediaStream::GraphTimeToStreamTime(Graph
 
 void
 MediaStream::FinishOnGraphThread()
 {
   GraphImpl()->FinishStream(this);
 }
 
 void
+MediaStream::RemoveAllListenersImpl()
+{
+  for (int32_t i = mListeners.Length() - 1; i >= 0; --i) {
+    nsRefPtr<MediaStreamListener> listener = mListeners[i].forget();
+    listener->NotifyRemoved(GraphImpl());
+  }
+  mListeners.Clear();
+}
+
+void
 MediaStream::DestroyImpl()
 {
+  RemoveAllListenersImpl();
+
   for (int32_t i = mConsumers.Length() - 1; i >= 0; --i) {
     mConsumers[i]->Disconnect();
   }
   for (uint32_t i = 0; i < mAudioOutputStreams.Length(); ++i) {
     mAudioOutputStreams[i].mStream->Shutdown();
   }
   mAudioOutputStreams.Clear();
 }
@@ -1957,16 +1969,25 @@ MediaStream::AddListener(MediaStreamList
       mStream->AddListenerImpl(mListener.forget());
     }
     nsRefPtr<MediaStreamListener> mListener;
   };
   GraphImpl()->AppendMessage(new Message(this, aListener));
 }
 
 void
+MediaStream::RemoveListenerImpl(MediaStreamListener* aListener)
+{ 
+  // wouldn't need this if we could do it in the opposite order
+  nsRefPtr<MediaStreamListener> listener(aListener);
+  mListeners.RemoveElement(aListener);
+  listener->NotifyRemoved(GraphImpl());
+}
+
+void
 MediaStream::RemoveListener(MediaStreamListener* aListener)
 {
   class Message : public ControlMessage {
   public:
     Message(MediaStream* aStream, MediaStreamListener* aListener) :
       ControlMessage(aStream), mListener(aListener) {}
     virtual void Run()
     {
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -138,16 +138,22 @@ public:
    */
   virtual void NotifyOutput(MediaStreamGraph* aGraph) {}
 
   /**
    * Notify that the stream finished.
    */
   virtual void NotifyFinished(MediaStreamGraph* aGraph) {}
 
+  /**
+   * Notify that your listener has been removed, either due to RemoveListener(),
+   * or due to the stream being destroyed.  You will get no further notifications.
+   */
+  virtual void NotifyRemoved(MediaStreamGraph* aGraph) {}
+
   enum {
     TRACK_EVENT_CREATED = 0x01,
     TRACK_EVENT_ENDED = 0x02
   };
   /**
    * Notify that changes to one of the stream tracks have been queued.
    * aTrackEvents can be any combination of TRACK_EVENT_CREATED and
    * TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
@@ -358,20 +364,19 @@ public:
   {
     mVideoOutputs.RemoveElement(aContainer);
   }
   void ChangeExplicitBlockerCountImpl(StreamTime aTime, int32_t aDelta)
   {
     mExplicitBlockerCount.SetAtAndAfter(aTime, mExplicitBlockerCount.GetAt(aTime) + aDelta);
   }
   void AddListenerImpl(already_AddRefed<MediaStreamListener> aListener);
-  void RemoveListenerImpl(MediaStreamListener* aListener)
-  {
-    mListeners.RemoveElement(aListener);
-  }
+  void RemoveListenerImpl(MediaStreamListener* aListener);
+  void RemoveAllListenersImpl();
+
   void AddConsumer(MediaInputPort* aPort)
   {
     mConsumers.AppendElement(aPort);
   }
   void RemoveConsumer(MediaInputPort* aPort)
   {
     mConsumers.RemoveElement(aPort);
   }
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -236,24 +236,34 @@ public:
   {
     nsRefPtr<nsDOMUserMediaStream> stream = new nsDOMUserMediaStream();
     stream->InitTrackUnionStream(aHintContents);
     return stream.forget();
   }
 
   virtual ~nsDOMUserMediaStream()
   {
+    Stop();
+
     if (mPort) {
       mPort->Destroy();
     }
     if (mSourceStream) {
       mSourceStream->Destroy();
     }
   }
 
+  NS_IMETHODIMP Stop()
+  {
+    if (mSourceStream) {
+      mSourceStream->EndAllTrackAndFinish();
+    }
+    return NS_OK;
+  }
+
   // The actual MediaStream is a TrackUnionStream. But these resources need to be
   // explicitly destroyed too.
   nsRefPtr<SourceMediaStream> mSourceStream;
   nsRefPtr<MediaInputPort> mPort;
 };
 
 /**
  * Creates a MediaStream, attaches a listener and fires off a success callback