Bug 1257318: Move MediaRecorder to use DirectListeners wherever possible. r=roc a=ritu
authorRandell Jesup <rjesup@jesup.org>
Sat, 19 Mar 2016 16:53:51 -0400
changeset 351355 49207e06538f84689dc6ff388621b9f754c2ca91
parent 351354 a4481ccef67e4732e005b3538df8d8e61890bcdc
child 351356 99dc7c2f51eb03463f2f60e7fc2f9e0e7c579ca9
push id15502
push userahunt@mozilla.com
push dateThu, 14 Apr 2016 20:27:48 +0000
reviewersroc, ritu
bugs1257318
milestone47.0a2
Bug 1257318: Move MediaRecorder to use DirectListeners wherever possible. r=roc a=ritu
dom/media/MediaRecorder.cpp
dom/media/encoder/MediaEncoder.cpp
dom/media/encoder/MediaEncoder.h
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -320,17 +320,17 @@ class MediaRecorder::Session: public nsI
   public:
     explicit DestroyRunnable(Session* aSession)
       : mSession(aSession) {}
 
     NS_IMETHODIMP Run()
     {
       LOG(LogLevel::Debug, ("Session.DestroyRunnable session refcnt = (%d) stopIssued %d s=(%p)",
                          (int)mSession->mRefCnt, mSession->mStopIssued, mSession.get()));
-      MOZ_ASSERT(NS_IsMainThread() && mSession.get());
+      MOZ_ASSERT(NS_IsMainThread() && mSession);
       RefPtr<MediaRecorder> recorder = mSession->mRecorder;
       if (!recorder) {
         return NS_OK;
       }
       // SourceMediaStream is ended, and send out TRACK_EVENT_END notification.
       // Read Thread will be terminate soon.
       // We need to switch MediaRecorder to "Stop" state first to make sure
       // MediaRecorder is not associated with this Session anymore, then, it's
@@ -625,16 +625,26 @@ private:
     // The Session::stop would clean the mTrackUnionStream. If the AfterTracksAdded
     // comes after stop command, this function would crash.
     if (!mTrackUnionStream) {
       LOG(LogLevel::Debug, ("Session.InitEncoder !mTrackUnionStream %p", this));
       DoSessionEndTask(NS_OK);
       return;
     }
     mTrackUnionStream->AddListener(mEncoder);
+    // Try to use direct listeners if possible
+    DOMMediaStream* domStream = mRecorder->Stream();
+    if (domStream) {
+      mInputStream = domStream->GetInputStream()->AsSourceStream();
+      if (mInputStream) {
+        mInputStream->AddDirectListener(mEncoder);
+        mEncoder->SetDirectConnect(true);
+      }
+    }
+
     // Create a thread to read encode media data from MediaEncoder.
     if (!mReadThread) {
       nsresult rv = NS_NewNamedThread("Media_Encoder", getter_AddRefs(mReadThread));
       if (NS_FAILED(rv)) {
         LOG(LogLevel::Debug, ("Session.InitEncoder !mReadThread %p", this));
         DoSessionEndTask(rv);
         return;
       }
@@ -677,22 +687,31 @@ private:
     }
     if (NS_FAILED(NS_DispatchToMainThread(new DestroyRunnable(this)))) {
       MOZ_ASSERT(false, "NS_DispatchToMainThread DestroyRunnable failed");
     }
     mNeedSessionEndTask = false;
   }
   void CleanupStreams()
   {
-    if (mInputPort.get()) {
+    if (mInputStream) {
+      if (mEncoder) {
+        mInputStream->RemoveDirectListener(mEncoder);
+      }
+      mInputStream = nullptr;
+    }
+    if (mInputPort) {
       mInputPort->Destroy();
       mInputPort = nullptr;
     }
 
-    if (mTrackUnionStream.get()) {
+    if (mTrackUnionStream) {
+      if (mEncoder) {
+        mTrackUnionStream->RemoveListener(mEncoder);
+      }
       mTrackUnionStream->Destroy();
       mTrackUnionStream = nullptr;
     }
   }
 
   NS_IMETHODIMP Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) override
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -724,16 +743,17 @@ private:
 private:
   // Hold reference to MediaRecoder that ensure MediaRecorder is alive
   // if there is an active session. Access ONLY on main thread.
   RefPtr<MediaRecorder> mRecorder;
 
   // Receive track data from source and dispatch to Encoder.
   // Pause/ Resume controller.
   RefPtr<ProcessedMediaStream> mTrackUnionStream;
+  RefPtr<SourceMediaStream> mInputStream;
   RefPtr<MediaInputPort> mInputPort;
 
   // Runnable thread for read data from MediaEncode.
   nsCOMPtr<nsIThread> mReadThread;
   // MediaEncoder pipeline.
   RefPtr<MediaEncoder> mEncoder;
   // A buffer to cache encoded meda data.
   nsAutoPtr<EncodedBufferCache> mEncodedBufferCache;
--- a/dom/media/encoder/MediaEncoder.cpp
+++ b/dom/media/encoder/MediaEncoder.cpp
@@ -32,35 +32,54 @@
 #endif
 
 mozilla::LazyLogModule gMediaEncoderLog("MediaEncoder");
 #define LOG(type, msg) MOZ_LOG(gMediaEncoderLog, type, msg)
 
 namespace mozilla {
 
 void
+MediaEncoder::SetDirectConnect(bool aConnected)
+{
+  fprintf(stderr, "****** direct connect: %s\n", aConnected ? "true" : "false");
+  mDirectConnected = aConnected;
+}
+
+void
+MediaEncoder::NotifyRealtimeData(MediaStreamGraph* aGraph,
+                                 TrackID aID,
+                                 StreamTime aTrackOffset,
+                                 uint32_t aTrackEvents,
+                                 const MediaSegment& aRealtimeMedia)
+{
+  // Process the incoming raw track data from MediaStreamGraph, called on the
+  // thread of MediaStreamGraph.
+  if (mAudioEncoder && aRealtimeMedia.GetType() == MediaSegment::AUDIO) {
+    mAudioEncoder->NotifyQueuedTrackChanges(aGraph, aID,
+                                            aTrackOffset, aTrackEvents,
+                                            aRealtimeMedia);
+
+  } else if (mVideoEncoder && aRealtimeMedia.GetType() == MediaSegment::VIDEO) {
+    mVideoEncoder->NotifyQueuedTrackChanges(aGraph, aID,
+                                            aTrackOffset, aTrackEvents,
+                                            aRealtimeMedia);
+  }
+}
+
+void
 MediaEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
                                        TrackID aID,
                                        StreamTime aTrackOffset,
                                        uint32_t aTrackEvents,
                                        const MediaSegment& aQueuedMedia,
                                        MediaStream* aInputStream,
                                        TrackID aInputTrackID)
 {
-  // Process the incoming raw track data from MediaStreamGraph, called on the
-  // thread of MediaStreamGraph.
-  if (mAudioEncoder && aQueuedMedia.GetType() == MediaSegment::AUDIO) {
-    mAudioEncoder->NotifyQueuedTrackChanges(aGraph, aID,
-                                            aTrackOffset, aTrackEvents,
-                                            aQueuedMedia);
-
-  } else if (mVideoEncoder && aQueuedMedia.GetType() == MediaSegment::VIDEO) {
-      mVideoEncoder->NotifyQueuedTrackChanges(aGraph, aID,
-                                              aTrackOffset, aTrackEvents,
-                                              aQueuedMedia);
+  if (!mDirectConnected) {
+    NotifyRealtimeData(aGraph, aID, aTrackOffset, aTrackEvents, aQueuedMedia);
   }
 }
 
 void
 MediaEncoder::NotifyEvent(MediaStreamGraph* aGraph,
                           MediaStreamListener::MediaStreamGraphEvent event)
 {
   // In case that MediaEncoder does not receive a TRACK_EVENT_ENDED event.
--- a/dom/media/encoder/MediaEncoder.h
+++ b/dom/media/encoder/MediaEncoder.h
@@ -44,17 +44,17 @@ namespace mozilla {
  * 2) Dispatch the task GetEncodedData() to a worker thread.
  *
  * 3) To start encoding, add this component to its source stream.
  *    => sourceStream->AddListener(encoder);
  *
  * 4) To stop encoding, remove this component from its source stream.
  *    => sourceStream->RemoveListener(encoder);
  */
-class MediaEncoder : public MediaStreamListener
+class MediaEncoder : public MediaStreamDirectListener
 {
 public :
   enum {
     ENCODE_METADDATA,
     ENCODE_TRACK,
     ENCODE_DONE,
     ENCODE_ERROR,
   };
@@ -69,21 +69,36 @@ public :
     : mWriter(aWriter)
     , mAudioEncoder(aAudioEncoder)
     , mVideoEncoder(aVideoEncoder)
     , mStartTime(TimeStamp::Now())
     , mMIMEType(aMIMEType)
     , mSizeOfBuffer(0)
     , mState(MediaEncoder::ENCODE_METADDATA)
     , mShutdown(false)
+    , mDirectConnected(false)
   {}
 
   ~MediaEncoder() {};
 
   /**
+   * Tells us which Notify to pay attention to for media
+   */
+  void SetDirectConnect(bool aConnected);
+
+  /**
+   * Notified by the AppendToTrack in MediaStreamGraph; aRealtimeMedia is the raw
+   * track data in form of MediaSegment.
+   */
+  void NotifyRealtimeData(MediaStreamGraph* aGraph, TrackID aID,
+                          StreamTime aTrackOffset,
+                          uint32_t aTrackEvents,
+                          const MediaSegment& aRealtimeMedia) override;
+
+  /**
    * Notified by the control loop of MediaStreamGraph; aQueueMedia is the raw
    * track data in form of MediaSegment.
    */
   void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
                                 StreamTime aTrackOffset,
                                 uint32_t aTrackEvents,
                                 const MediaSegment& aQueuedMedia,
                                 MediaStream* aInputStream,
@@ -164,16 +179,17 @@ private:
   nsAutoPtr<ContainerWriter> mWriter;
   nsAutoPtr<AudioTrackEncoder> mAudioEncoder;
   nsAutoPtr<VideoTrackEncoder> mVideoEncoder;
   TimeStamp mStartTime;
   nsString mMIMEType;
   int64_t mSizeOfBuffer;
   int mState;
   bool mShutdown;
+  bool mDirectConnected;
   // Get duration from create encoder, for logging purpose
   double GetEncodeTimeStamp()
   {
     TimeDuration decodeTime;
     decodeTime = TimeStamp::Now() - mStartTime;
     return decodeTime.ToMilliseconds();
   }
 };