Bug 1379856 - Provide a HandlerThread for GeckoHlsPlayer instead of using Gecko's MainThread. r=jolin

Gecko's mainthread message queue is getting more tasks along with each creation of GeckoHlsPlayer. We should avoid adding extra work load to gecko's main thread.

MozReview-Commit-ID: 2c5fnmG2hfS

--HG--
extra : rebase_source : 892290a6e4d2c9b120b6dec9d0aae51d0dc0c05d
This commit is contained in:
Kilik Kuo 2017-07-13 00:23:04 +08:00
Родитель 9a920e6268
Коммит cd0796d840
1 изменённых файлов: 55 добавлений и 14 удалений

Просмотреть файл

@ -7,6 +7,7 @@ package org.mozilla.gecko.media;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import com.google.android.exoplayer2.C;
@ -63,6 +64,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
private DataSource.Factory mMediaDataSourceFactory;
private Handler mMainHandler;
private HandlerThread mThread;
private ExoPlayer mPlayer;
private GeckoHlsRendererBase[] mRenderers;
private DefaultTrackSelector mTrackSelector;
@ -70,7 +72,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
private ComponentListener mComponentListener;
private ComponentEventDispatcher mComponentEventDispatcher;
private boolean mIsTimelineStatic = false;
private volatile boolean mIsTimelineStatic = false;
private long mDurationUs;
private GeckoHlsVideoRenderer mVRenderer = null;
@ -156,6 +158,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
public final class ComponentEventDispatcher {
// Called on GeckoHlsPlayerThread from GeckoHls{Audio,Video}Renderer/ExoPlayer
public void onDataArrived(final int trackType) {
assertTrue(mMainHandler != null);
assertTrue(mComponentListener != null);
@ -172,6 +175,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread from GeckoHls{Audio,Video}Renderer
public void onVideoInputFormatChanged(final Format format) {
assertTrue(mMainHandler != null);
assertTrue(mComponentListener != null);
@ -188,6 +192,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread from GeckoHls{Audio,Video}Renderer
public void onAudioInputFormatChanged(final Format format) {
assertTrue(mMainHandler != null);
assertTrue(mComponentListener != null);
@ -208,6 +213,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
public final class ComponentListener {
// General purpose implementation
// Called on GeckoHlsPlayerThread
public void onDataArrived(int trackType) {
synchronized (GeckoHlsPlayer.this) {
if (DEBUG) { Log.d(LOGTAG, "[CB][onDataArrived] id " + mPlayerId); }
@ -228,6 +234,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread
public void onVideoInputFormatChanged(Format format) {
synchronized (GeckoHlsPlayer.this) {
if (DEBUG) {
@ -250,6 +257,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread
public void onAudioInputFormatChanged(Format format) {
synchronized (GeckoHlsPlayer.this) {
if (DEBUG) {
@ -305,23 +313,27 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
// Should be only called by GeckoPlayerFactory and GeckoHLSResourceWrapper.
// The mPlayerId is used to make sure that the same GeckoHlsPlayer is used by
// corresponding HLSResource and HLSDemuxer for each media playback.
// Called on Gecko's main thread
@Override
public int getId() {
return mPlayerId;
}
// Called on Gecko's main thread
@Override
public void addResourceWrapperCallbackListener(BaseHlsPlayer.ResourceCallbacks callback) {
if (DEBUG) { Log.d(LOGTAG, " addResourceWrapperCallbackListener ..."); }
mResourceCallbacks = callback;
}
// Called on Gecko's main thread
@Override
public void addDemuxerWrapperCallbackListener(BaseHlsPlayer.DemuxerCallbacks callback) {
if (DEBUG) { Log.d(LOGTAG, " addDemuxerWrapperCallbackListener ..."); }
mDemuxerCallbacks = callback;
}
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public synchronized void onLoadingChanged(boolean isLoading) {
if (DEBUG) { Log.d(LOGTAG, "loading [" + isLoading + "]"); }
@ -331,6 +343,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public synchronized void onPlayerStateChanged(boolean playWhenReady, int state) {
if (DEBUG) { Log.d(LOGTAG, "state [" + playWhenReady + ", " + getStateString(state) + "]"); }
@ -339,11 +352,13 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public void onPositionDiscontinuity() {
if (DEBUG) { Log.d(LOGTAG, "positionDiscontinuity"); }
}
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
if (DEBUG) {
@ -352,6 +367,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public synchronized void onPlayerError(ExoPlaybackException e) {
if (DEBUG) { Log.e(LOGTAG, "playerFailed" , e); }
@ -364,6 +380,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public synchronized void onTracksChanged(TrackGroupArray ignored, TrackSelectionArray trackSelections) {
if (DEBUG) {
@ -442,6 +459,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
mTracksInfo = new HlsMediaTracksInfo(numVideoTracks, numAudioTracks);
}
// Called on GeckoHlsPlayerThread from ExoPlayer
@Override
public synchronized void onTimelineChanged(Timeline timeline, Object manifest) {
// For now, we use the interface ExoPlayer.getDuration() for gecko,
@ -534,21 +552,11 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
return enabled ? "[X]" : "[ ]";
}
// =======================================================================
// API for GeckoHLSResourceWrapper
// =======================================================================
@Override
public synchronized void init(String url) {
if (DEBUG) { Log.d(LOGTAG, " init"); }
assertTrue(mResourceCallbacks != null);
if (mIsPlayerInitDone) {
return;
}
// Called on GeckoHlsPlayerThread
private synchronized void createExoPlayer(final String url) {
Context ctx = GeckoAppShell.getApplicationContext();
mComponentListener = new ComponentListener();
mComponentEventDispatcher = new ComponentEventDispatcher();
mMainHandler = new Handler();
mDurationUs = 0;
// Prepare trackSelector
@ -578,15 +586,37 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
mPlayer.prepare(mMediaSource);
mIsPlayerInitDone = true;
}
// =======================================================================
// API for GeckoHLSResourceWrapper
// =======================================================================
// Called on Gecko Main Thread
@Override
public synchronized void init(final String url) {
if (DEBUG) { Log.d(LOGTAG, " init"); }
assertTrue(mResourceCallbacks != null);
assertTrue(!mIsPlayerInitDone);
mThread = new HandlerThread("GeckoHlsPlayerThread");
mThread.start();
mMainHandler = new Handler(mThread.getLooper());
mMainHandler.post(new Runnable() {
@Override
public void run() {
createExoPlayer(url);
}
});
}
// Called on MDSM's TaskQueue
@Override
public boolean isLiveStream() {
return !mIsTimelineStatic;
}
// =======================================================================
// API for GeckoHLSDemuxerWrapper
// =======================================================================
// Called on HLSDemuxer's TaskQueue
@Override
public ConcurrentLinkedQueue<GeckoHLSSample> getSamples(TrackType trackType,
int number) {
@ -601,6 +631,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
}
}
// Called on MFR's TaskQueue
@Override
public synchronized long getBufferedPosition() {
// Value returned by getBufferedPosition() is in milliseconds.
@ -609,6 +640,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
return bufferedPos;
}
// Called on MFR's TaskQueue
@Override
public synchronized int getNumberOfTracks(TrackType trackType) {
if (DEBUG) { Log.d(LOGTAG, "getNumberOfTracks : type " + trackType); }
@ -622,6 +654,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
return 0;
}
// Called on MFR's TaskQueue
@Override
public GeckoVideoInfo getVideoInfo(int index) {
if (DEBUG) { Log.d(LOGTAG, "getVideoInfo"); }
@ -642,6 +675,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
return vInfo;
}
// Called on MFR's TaskQueue
@Override
public GeckoAudioInfo getAudioInfo(int index) {
if (DEBUG) { Log.d(LOGTAG, "getAudioInfo"); }
@ -670,6 +704,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
return aInfo;
}
// Called on HLSDemuxer's TaskQueue
@Override
public synchronized boolean seek(long positionUs) {
// positionUs : microseconds.
@ -703,6 +738,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
return true;
}
// Called on HLSDemuxer's TaskQueue
@Override
public long getNextKeyFrameTime() {
long nextKeyFrameTime = mVRenderer != null
@ -711,6 +747,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
return nextKeyFrameTime;
}
// Called on Gecko's main thread, when HLSDemuxer or HLSResource destructs.
@Override
public synchronized void release() {
if (DEBUG) { Log.d(LOGTAG, "releasing ... id : " + mPlayerId); }
@ -722,6 +759,10 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
mARenderer = null;
mPlayer = null;
}
if (mThread != null) {
mThread.quit();
mThread = null;
}
mDemuxerCallbacks = null;
mResourceCallbacks = null;
mIsPlayerInitDone = false;