Bug 1336367 - Move AudioTrackEncoder Segment init logic into new method. r?pehrsons draft
authorBryce Van Dyk <bvandyk@mozilla.com>
Thu, 14 Sep 2017 07:19:27 +1200
changeset 664605 d2087d30ea5918b154a93ab87eacf07e6cf49eab
parent 664604 bb61ee31e33a1ebaf190f8e93f52199329895180
child 664606 b75d3513d951b7198ca572e6da496268430df0a0
push id79747
push userbvandyk@mozilla.com
push dateThu, 14 Sep 2017 06:20:16 +0000
reviewerspehrsons
bugs1336367
milestone57.0a1
Bug 1336367 - Move AudioTrackEncoder Segment init logic into new method. r?pehrsons The AudioTrackEncoder has logic to attempt to init when given an AudioSegment. This logic has previously been part of NotifyQueuedTrackChanges. This changeset moves the logic to its own method. This allows for finer testing of the init attempt behaviour. MozReview-Commit-ID: Der1iM9J8fr
dom/media/encoder/TrackEncoder.cpp
dom/media/encoder/TrackEncoder.h
--- a/dom/media/encoder/TrackEncoder.cpp
+++ b/dom/media/encoder/TrackEncoder.cpp
@@ -40,74 +40,89 @@ TrackEncoder::TrackEncoder()
 void TrackEncoder::NotifyEvent(MediaStreamGraph* aGraph,
                  MediaStreamGraphEvent event)
 {
   if (event == MediaStreamGraphEvent::EVENT_REMOVED) {
     NotifyEndOfStream();
   }
 }
 
+nsresult
+AudioTrackEncoder::TryInit(const AudioSegment& aSegment, int aSamplingRate)
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+  if (mInitialized) {
+    return NS_OK;
+  }
+
+  mInitCounter++;
+  TRACK_LOG(LogLevel::Debug, ("Init the audio encoder %d times", mInitCounter));
+  AudioSegment::ConstChunkIterator iter(aSegment);
+  while (!iter.IsEnded()) {
+    AudioChunk chunk = *iter;
+
+    // The number of channels is determined by the first non-null chunk, and
+    // thus the audio encoder is initialized at this time.
+    if (!chunk.IsNull()) {
+      nsresult rv = Init(chunk.mChannelData.Length(), aSamplingRate);
+      if (NS_FAILED(rv)) {
+        TRACK_LOG(LogLevel::Error,
+                  ("[AudioTrackEncoder]: Fail to initialize the encoder!"));
+        NotifyCancel();
+        return rv;
+      }
+      break;
+    }
+
+    iter.Next();
+  }
+
+  mNotInitDuration += aSegment.GetDuration();
+  if (!mInitialized &&
+      (mNotInitDuration / aSamplingRate >= AUDIO_INIT_FAILED_DURATION) &&
+      mInitCounter > 1) {
+    // Perform a best effort initialization since we haven't gotten any
+    // data yet. Motivated by issues like Bug 1336367
+    TRACK_LOG(LogLevel::Warning,
+              ("[AudioTrackEncoder]: Initialize failed "
+               "for %ds. Attempting to init with %d "
+               "(default) channels!",
+               AUDIO_INIT_FAILED_DURATION,
+               DEFAULT_CHANNELS));
+    nsresult rv = Init(DEFAULT_CHANNELS, aSamplingRate);
+    if (NS_FAILED(rv)) {
+      TRACK_LOG(LogLevel::Error,
+                ("[AudioTrackEncoder]: Fail to initialize the encoder!"));
+      NotifyCancel();
+      return rv;
+    }
+  }
+
+  return NS_OK;
+}
+
 void
 AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
                                             TrackID aID,
                                             StreamTime aTrackOffset,
                                             uint32_t aTrackEvents,
                                             const MediaSegment& aQueuedMedia)
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   if (mCanceled) {
     return;
   }
 
   const AudioSegment& audio = static_cast<const AudioSegment&>(aQueuedMedia);
 
-  // Check and initialize parameters for codec encoder.
-  if (!mInitialized) {
-    mInitCounter++;
-    TRACK_LOG(LogLevel::Debug, ("Init the audio encoder %d times", mInitCounter));
-    AudioSegment::ChunkIterator iter(const_cast<AudioSegment&>(audio));
-    while (!iter.IsEnded()) {
-      AudioChunk chunk = *iter;
-
-      // The number of channels is determined by the first non-null chunk, and
-      // thus the audio encoder is initialized at this time.
-      if (!chunk.IsNull()) {
-        nsresult rv = Init(chunk.mChannelData.Length(), aGraph->GraphRate());
-        if (NS_FAILED(rv)) {
-          TRACK_LOG(LogLevel::Error, ("[AudioTrackEncoder]: Fail to initialize the encoder!"));
-          NotifyCancel();
-        }
-        break;
-      }
-
-      iter.Next();
-    }
-
-    mNotInitDuration += aQueuedMedia.GetDuration();
-    if (!mInitialized &&
-        (mNotInitDuration / aGraph->GraphRate() >=
-         AUDIO_INIT_FAILED_DURATION) &&
-        mInitCounter > 1) {
-      // Perform a best effort initialization since we haven't gotten any
-      // data yet. Motivated by issues like Bug 1336367
-      TRACK_LOG(LogLevel::Warning,
-                ("[AudioTrackEncoder]: Initialize failed "
-                 "for %ds. Attempting to init with %d "
-                 "(default) channels!",
-                 AUDIO_INIT_FAILED_DURATION,
-                 DEFAULT_CHANNELS));
-      nsresult rv = Init(DEFAULT_CHANNELS, aGraph->GraphRate());
-      if (NS_FAILED(rv)) {
-        TRACK_LOG(LogLevel::Error,
-                  ("[AudioTrackEncoder]: Fail to initialize the encoder!"));
-        NotifyCancel();
-        return;
-      }
-    }
+  nsresult rv = TryInit(audio, aGraph->GraphRate());
+  if (NS_FAILED(rv)) {
+    return;
   }
 
   // Append and consume this raw segment.
   AppendAudioSegment(audio);
 
 
   // The stream has stopped and reached the end of track.
   if (aTrackEvents == TrackEventCommand::TRACK_EVENT_ENDED) {
--- a/dom/media/encoder/TrackEncoder.h
+++ b/dom/media/encoder/TrackEncoder.h
@@ -197,16 +197,31 @@ protected:
   /**
    * Number of samples per channel in a pcm buffer. This is also the value of
    * frame size required by audio encoder, and mReentrantMonitor will be
    * notified when at least this much data has been added to mRawSegment.
    */
   virtual int GetPacketDuration() { return 0; }
 
   /**
+   * Attempt to initialize the audio encoder. The call of this method is
+   * delayed until we have received the first valid track from
+   * MediaStreamGraph, and the mReentrantMonitor will be notified if other
+   * methods is waiting for encoder to be completely initialized. This method
+   * is called on the MediaStreamGraph thread. This method will attempt to
+   * initialize with best effort if all the following are met:
+   * - it has been called multiple times
+   * - reached a threshold duration of audio data
+   * - the encoder has not yet initialized.
+   * Returns NS_OK on init, as well as when deferring for more data, so check
+   * mInitialized after calling as necessary.
+   */
+  virtual nsresult TryInit(const AudioSegment& aSegment, int aSamplingRate);
+
+  /**
    * Initializes the audio encoder. The call of this method is delayed until we
    * have received the first valid track from MediaStreamGraph, and the
    * mReentrantMonitor will be notified if other methods is waiting for encoder
    * to be completely initialized. This method is called on the MediaStreamGraph
    * thread.
    */
   virtual nsresult Init(int aChannels, int aSamplingRate) = 0;