Bug 1382151 - Pause Exoplayer when mediaelement is paused. r=kikuo

MozReview-Commit-ID: 5MDBBP5vfpa

--HG--
extra : rebase_source : 9981585791cd359296ac7fef0fe0d7e900af6c61
This commit is contained in:
James Cheng 2017-07-20 17:47:54 +08:00
Родитель 4e4645bdba
Коммит 4843d195fb
7 изменённых файлов: 163 добавлений и 14 удалений

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

@ -93,4 +93,26 @@ HLSDecoder::Load(MediaResource*)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
nsresult
HLSDecoder::Play()
{
MOZ_ASSERT(NS_IsMainThread());
HLS_DEBUG("HLSDecoder", "MediaElement called Play");
auto resourceWrapper =
static_cast<HLSResource*>(GetResource())->GetResourceWrapper();
resourceWrapper->Play();
return MediaDecoder::Play();
}
void
HLSDecoder::Pause()
{
MOZ_ASSERT(NS_IsMainThread());
HLS_DEBUG("HLSDecoder", "MediaElement called Pause");
auto resourceWrapper =
static_cast<HLSResource*>(GetResource())->GetResourceWrapper();
resourceWrapper->Pause();
return MediaDecoder::Pause();
}
} // namespace mozilla } // namespace mozilla

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

@ -37,6 +37,10 @@ public:
bool aIsPrivateBrowsing, bool aIsPrivateBrowsing,
nsIStreamListener**) override; nsIStreamListener**) override;
nsresult Load(MediaResource*) override; nsresult Load(MediaResource*) override;
nsresult Play() override;
void Pause() override;
}; };
} // namespace mozilla } // namespace mozilla

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

@ -88,5 +88,9 @@ public interface BaseHlsPlayer {
public void resume(); public void resume();
public void play();
public void pause();
public void release(); public void release();
} }

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

@ -79,6 +79,22 @@ public class GeckoHLSResourceWrapper {
} }
} }
@WrapForJNI(calledFrom = "gecko")
public void play() {
if (DEBUG) Log.d(LOGTAG, "GeckoHLSResourceWrapper mediaelement played");
if (mPlayer != null) {
mPlayer.play();
}
}
@WrapForJNI(calledFrom = "gecko")
public void pause() {
if (DEBUG) Log.d(LOGTAG, "GeckoHLSResourceWrapper mediaelement paused");
if (mPlayer != null) {
mPlayer.pause();
}
}
private static void assertTrue(boolean condition) { private static void assertTrue(boolean condition) {
if (DEBUG && !condition) { if (DEBUG && !condition) {
throw new AssertionError("Expected condition to be true"); throw new AssertionError("Expected condition to be true");

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

@ -60,7 +60,8 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
* mPlayerId is a token used for Gecko media pipeline to obtain corresponding player. * mPlayerId is a token used for Gecko media pipeline to obtain corresponding player.
*/ */
private final int mPlayerId; private final int mPlayerId;
private volatile boolean mSuspended = false; private boolean mExoplayerSuspended = false;
private boolean mMediaElementSuspended = false;
private DataSource.Factory mMediaDataSourceFactory; private DataSource.Factory mMediaDataSourceFactory;
private Handler mMainHandler; private Handler mMainHandler;
@ -312,6 +313,9 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
public synchronized void onLoadingChanged(boolean isLoading) { public synchronized void onLoadingChanged(boolean isLoading) {
if (DEBUG) { Log.d(LOGTAG, "loading [" + isLoading + "]"); } if (DEBUG) { Log.d(LOGTAG, "loading [" + isLoading + "]"); }
if (!isLoading) { if (!isLoading) {
if (mMediaElementSuspended) {
suspendExoplayer();
}
// To update buffered position. // To update buffered position.
mComponentEventDispatcher.onDataArrived(C.TRACK_TYPE_DEFAULT); mComponentEventDispatcher.onDataArrived(C.TRACK_TYPE_DEFAULT);
} }
@ -321,8 +325,8 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
@Override @Override
public synchronized void onPlayerStateChanged(boolean playWhenReady, int state) { public synchronized void onPlayerStateChanged(boolean playWhenReady, int state) {
if (DEBUG) { Log.d(LOGTAG, "state [" + playWhenReady + ", " + getStateString(state) + "]"); } if (DEBUG) { Log.d(LOGTAG, "state [" + playWhenReady + ", " + getStateString(state) + "]"); }
if (state == ExoPlayer.STATE_READY && !mSuspended) { if (state == ExoPlayer.STATE_READY && !mExoplayerSuspended && !mMediaElementSuspended) {
mPlayer.setPlayWhenReady(true); resumeExoplayer();
} }
} }
@ -679,6 +683,12 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
// Called on HLSDemuxer's TaskQueue // Called on HLSDemuxer's TaskQueue
@Override @Override
public synchronized boolean seek(long positionUs) { public synchronized boolean seek(long positionUs) {
// Need to temporarily resume Exoplayer to download the chunks for getting the demuxed
// keyframe sample when HTMLMediaElement is paused. Suspend Exoplayer when collecting enough
// samples in onLoadingChanged.
if (mExoplayerSuspended) {
resumeExoplayer();
}
// positionUs : microseconds. // positionUs : microseconds.
// NOTE : 1) It's not possible to seek media by tracktype via ExoPlayer Interface. // NOTE : 1) It's not possible to seek media by tracktype via ExoPlayer Interface.
// 2) positionUs is samples PTS from MFR, we need to re-adjust it // 2) positionUs is samples PTS from MFR, we need to re-adjust it
@ -712,7 +722,7 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
// Called on HLSDemuxer's TaskQueue // Called on HLSDemuxer's TaskQueue
@Override @Override
public long getNextKeyFrameTime() { public synchronized long getNextKeyFrameTime() {
long nextKeyFrameTime = mVRenderer != null long nextKeyFrameTime = mVRenderer != null
? mVRenderer.getNextKeyFrameTime() ? mVRenderer.getNextKeyFrameTime()
: Long.MAX_VALUE; : Long.MAX_VALUE;
@ -722,29 +732,68 @@ public class GeckoHlsPlayer implements BaseHlsPlayer, ExoPlayer.EventListener {
// Called on Gecko's main thread. // Called on Gecko's main thread.
@Override @Override
public synchronized void suspend() { public synchronized void suspend() {
if (mSuspended) { if (mExoplayerSuspended) {
return; return;
} }
if (DEBUG) { Log.d(LOGTAG, "suspend player id : " + mPlayerId); } if (mMediaElementSuspended) {
mSuspended = true; if (DEBUG) {
if (mPlayer != null) { Log.d(LOGTAG, "suspend player id : " + mPlayerId);
mPlayer.setPlayWhenReady(false); }
suspendExoplayer();
} }
} }
// Called on Gecko's main thread. // Called on Gecko's main thread.
@Override @Override
public synchronized void resume() { public synchronized void resume() {
if (!mSuspended) { if (!mExoplayerSuspended) {
return; return;
} }
if (DEBUG) { Log.d(LOGTAG, "resume player id : " + mPlayerId); } if (!mMediaElementSuspended) {
mSuspended = false; if (DEBUG) {
if (mPlayer != null) { Log.d(LOGTAG, "resume player id : " + mPlayerId);
mPlayer.setPlayWhenReady(true); }
resumeExoplayer();
} }
} }
// Called on Gecko's main thread.
@Override
public synchronized void play() {
if (!mMediaElementSuspended) {
return;
}
if (DEBUG) { Log.d(LOGTAG, "mediaElement played."); }
mMediaElementSuspended = false;
resumeExoplayer();
}
// Called on Gecko's main thread.
@Override
public synchronized void pause() {
if (mMediaElementSuspended) {
return;
}
if (DEBUG) { Log.d(LOGTAG, "mediaElement paused."); }
mMediaElementSuspended = true;
suspendExoplayer();
}
private synchronized void suspendExoplayer() {
if (mPlayer != null) {
mExoplayerSuspended = true;
if (DEBUG) { Log.d(LOGTAG, "suspend Exoplayer"); }
mPlayer.setPlayWhenReady(false);
}
}
private synchronized void resumeExoplayer() {
if (mPlayer != null) {
mExoplayerSuspended = false;
if (DEBUG) { Log.d(LOGTAG, "resume Exoplayer"); }
mPlayer.setPlayWhenReady(true);
}
}
// Called on Gecko's main thread, when HLSDemuxer or HLSResource destructs. // Called on Gecko's main thread, when HLSDemuxer or HLSResource destructs.
@Override @Override
public synchronized void release() { public synchronized void release() {

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

@ -2050,6 +2050,22 @@ auto GeckoHLSResourceWrapper::GetPlayerId() const -> int32_t
return mozilla::jni::Method<GetPlayerId_t>::Call(GeckoHLSResourceWrapper::mCtx, nullptr); return mozilla::jni::Method<GetPlayerId_t>::Call(GeckoHLSResourceWrapper::mCtx, nullptr);
} }
constexpr char GeckoHLSResourceWrapper::Pause_t::name[];
constexpr char GeckoHLSResourceWrapper::Pause_t::signature[];
auto GeckoHLSResourceWrapper::Pause() const -> void
{
return mozilla::jni::Method<Pause_t>::Call(GeckoHLSResourceWrapper::mCtx, nullptr);
}
constexpr char GeckoHLSResourceWrapper::Play_t::name[];
constexpr char GeckoHLSResourceWrapper::Play_t::signature[];
auto GeckoHLSResourceWrapper::Play() const -> void
{
return mozilla::jni::Method<Play_t>::Call(GeckoHLSResourceWrapper::mCtx, nullptr);
}
constexpr char GeckoHLSResourceWrapper::Resume_t::name[]; constexpr char GeckoHLSResourceWrapper::Resume_t::name[];
constexpr char GeckoHLSResourceWrapper::Resume_t::signature[]; constexpr char GeckoHLSResourceWrapper::Resume_t::signature[];

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

@ -5879,6 +5879,44 @@ public:
auto GetPlayerId() const -> int32_t; auto GetPlayerId() const -> int32_t;
struct Pause_t {
typedef GeckoHLSResourceWrapper Owner;
typedef void ReturnType;
typedef void SetterType;
typedef mozilla::jni::Args<> Args;
static constexpr char name[] = "pause";
static constexpr char signature[] =
"()V";
static const bool isStatic = false;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::GECKO;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
auto Pause() const -> void;
struct Play_t {
typedef GeckoHLSResourceWrapper Owner;
typedef void ReturnType;
typedef void SetterType;
typedef mozilla::jni::Args<> Args;
static constexpr char name[] = "play";
static constexpr char signature[] =
"()V";
static const bool isStatic = false;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::GECKO;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
auto Play() const -> void;
struct Resume_t { struct Resume_t {
typedef GeckoHLSResourceWrapper Owner; typedef GeckoHLSResourceWrapper Owner;
typedef void ReturnType; typedef void ReturnType;