Bug 1418766 - Fix Crash in java.lang.OutOfMemoryError by making Exoplayer pause by default. draft
authorJames Cheng <jacheng@mozilla.com>
Tue, 21 Nov 2017 17:21:19 +0800
changeset 702370 e44c5bbd6fbdbfae0eb215a4157d42bb87ebc19f
parent 700905 081c06e175b2b4431b7af5ea594ff0373e97b70a
child 702371 c79ba1dc9582c0f719b1f5e611bff6eccf0bcf53
push id90455
push userbmo:jacheng@mozilla.com
push dateThu, 23 Nov 2017 02:44:57 +0000
bugs1418766
milestone59.0a1
Bug 1418766 - Fix Crash in java.lang.OutOfMemoryError by making Exoplayer pause by default. MozReview-Commit-ID: JGIRcYLXtdv
mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoHlsPlayer.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoHlsPlayer.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/GeckoHlsPlayer.java
@@ -56,17 +56,25 @@ public class GeckoHlsPlayer implements B
      *  It will be created and initialized with a URL by HLSResource in
      *  Gecko media pipleine (in cpp). Once HLSDemuxer is created later, we
      *  need to bridge this HLSResource to the created demuxer. And they share
      *  the same GeckoHlsPlayer.
      *  mPlayerId is a token used for Gecko media pipeline to obtain corresponding player.
      */
     private final int mPlayerId;
     private boolean mExoplayerSuspended = false;
-    private boolean mMediaElementSuspended = false;
+
+    private enum MediaDecoderPlayState{
+        PLAY_STATE_PREPARING,
+        PLAY_STATE_PAUSED,
+        PLAY_STATE_PLAYING
+    }
+    // Default value is PLAY_STATE_PREPARING and it will be set to PLAY_STATE_PLAYING
+    // once HTMLMediaElement calls PlayInternal().
+    private MediaDecoderPlayState mMediaDecoderPlayState = MediaDecoderPlayState.PLAY_STATE_PREPARING;
     private DataSource.Factory mMediaDataSourceFactory;
 
     private Handler mMainHandler;
     private HandlerThread mThread;
     private ExoPlayer mPlayer;
     private GeckoHlsRendererBase[] mRenderers;
     private DefaultTrackSelector mTrackSelector;
     private MediaSource mMediaSource;
@@ -308,29 +316,31 @@ public class GeckoHlsPlayer implements B
         mDemuxerCallbacks = callback;
     }
 
     // Called on GeckoHlsPlayerThread from ExoPlayer
     @Override
     public synchronized void onLoadingChanged(boolean isLoading) {
         if (DEBUG) { Log.d(LOGTAG, "loading [" + isLoading + "]"); }
         if (!isLoading) {
-            if (mMediaElementSuspended) {
+            if (mMediaDecoderPlayState != MediaDecoderPlayState.PLAY_STATE_PLAYING) {
                 suspendExoplayer();
             }
             // To update buffered position.
             mComponentEventDispatcher.onDataArrived(C.TRACK_TYPE_DEFAULT);
         }
     }
 
     // Called on GeckoHlsPlayerThread from ExoPlayer
     @Override
     public synchronized void onPlayerStateChanged(boolean playWhenReady, int state) {
         if (DEBUG) { Log.d(LOGTAG, "state [" + playWhenReady + ", " + getStateString(state) + "]"); }
-        if (state == ExoPlayer.STATE_READY && !mExoplayerSuspended && !mMediaElementSuspended) {
+        if (state == ExoPlayer.STATE_READY &&
+            !mExoplayerSuspended &&
+            mMediaDecoderPlayState == MediaDecoderPlayState.PLAY_STATE_PLAYING) {
             resumeExoplayer();
         }
     }
 
     // Called on GeckoHlsPlayerThread from ExoPlayer
     @Override
     public void onPositionDiscontinuity() {
         if (DEBUG) { Log.d(LOGTAG, "positionDiscontinuity"); }
@@ -556,17 +566,17 @@ public class GeckoHlsPlayer implements B
 
         Uri uri = Uri.parse(url);
         mMediaDataSourceFactory = buildDataSourceFactory(ctx, BANDWIDTH_METER);
         mMediaSource = new HlsMediaSource(uri, mMediaDataSourceFactory, mMainHandler, null);
         if (DEBUG) {
             Log.d(LOGTAG, "Uri is " + uri +
                           ", ContentType is " + Util.inferContentType(uri.getLastPathSegment()));
         }
-
+        mPlayer.setPlayWhenReady(false);
         mPlayer.prepare(mMediaSource);
         mIsPlayerInitDone = true;
     }
     // =======================================================================
     // API for GeckoHLSResourceWrapper
     // =======================================================================
     // Called on Gecko Main Thread
     @Override
@@ -735,57 +745,57 @@ public class GeckoHlsPlayer implements B
     }
 
     // Called on Gecko's main thread.
     @Override
     public synchronized void suspend() {
         if (mExoplayerSuspended) {
             return;
         }
-        if (mMediaElementSuspended) {
+        if (mMediaDecoderPlayState != MediaDecoderPlayState.PLAY_STATE_PLAYING) {
             if (DEBUG) {
                 Log.d(LOGTAG, "suspend player id : " + mPlayerId);
             }
             suspendExoplayer();
         }
     }
 
     // Called on Gecko's main thread.
     @Override
     public synchronized void resume() {
         if (!mExoplayerSuspended) {
           return;
         }
-        if (!mMediaElementSuspended) {
+        if (mMediaDecoderPlayState == MediaDecoderPlayState.PLAY_STATE_PLAYING) {
             if (DEBUG) {
                 Log.d(LOGTAG, "resume player id : " + mPlayerId);
             }
             resumeExoplayer();
         }
     }
 
     // Called on Gecko's main thread.
     @Override
     public synchronized void play() {
-        if (!mMediaElementSuspended) {
+        if (mMediaDecoderPlayState == MediaDecoderPlayState.PLAY_STATE_PLAYING) {
             return;
         }
-        if (DEBUG) { Log.d(LOGTAG, "mediaElement played."); }
-        mMediaElementSuspended = false;
+        if (DEBUG) { Log.d(LOGTAG, "MediaDecoder played."); }
+        mMediaDecoderPlayState = MediaDecoderPlayState.PLAY_STATE_PLAYING;
         resumeExoplayer();
     }
 
     // Called on Gecko's main thread.
     @Override
     public synchronized void pause() {
-        if (mMediaElementSuspended) {
+        if (mMediaDecoderPlayState != MediaDecoderPlayState.PLAY_STATE_PLAYING) {
             return;
         }
-        if (DEBUG) { Log.d(LOGTAG, "mediaElement paused."); }
-        mMediaElementSuspended = true;
+        if (DEBUG) { Log.d(LOGTAG, "MediaDecoder paused."); }
+        mMediaDecoderPlayState = MediaDecoderPlayState.PLAY_STATE_PAUSED;
         suspendExoplayer();
     }
 
     private synchronized void suspendExoplayer() {
         if (mPlayer != null) {
             mExoplayerSuspended = true;
             if (DEBUG) { Log.d(LOGTAG, "suspend Exoplayer"); }
             mPlayer.setPlayWhenReady(false);