Implement PlayerEventCallback on MediaPlayer2
Test: ./gradlew media:connectedCheck
Bug: 63934228
Change-Id: I971afdd06167235d5e4c1555b1b0e92ccaa866a6
diff --git a/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java b/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
index a48af14..cc409b7 100644
--- a/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
@@ -53,6 +53,10 @@
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.P)
@@ -1767,7 +1771,7 @@
@Test
@LargeTest
- public void testCallback() throws Throwable {
+ public void testMediaPlayer2Callback() throws Throwable {
final int mp4Duration = 8484;
if (!checkLoadResource(R.raw.testvideo)) {
@@ -1835,6 +1839,150 @@
mPlayer.reset();
}
+ @Test
+ @LargeTest
+ public void testPlayerStates() throws Throwable {
+ final int mp4Duration = 8484;
+
+ if (!checkLoadResource(R.raw.testvideo)) {
+ return; // skip;
+ }
+ mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface());
+
+ final Monitor prepareCompleted = new Monitor();
+ final Monitor playCompleted = new Monitor();
+ final Monitor pauseCompleted = new Monitor();
+
+ MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() {
+ @Override
+ public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) {
+ if (what == MediaPlayer2.CALL_COMPLETED_PREPARE) {
+ prepareCompleted.signal();
+ } else if (what == MediaPlayer2.CALL_COMPLETED_PLAY) {
+ playCompleted.signal();
+ } else if (what == MediaPlayer2.CALL_COMPLETED_PAUSE) {
+ pauseCompleted.signal();
+ }
+ }
+ };
+ synchronized (mEventCbLock) {
+ mEventCallbacks.add(ecb);
+ }
+
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_UNKNOWN, mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_IDLE, mPlayer.getPlayerState());
+ prepareCompleted.reset();
+ mPlayer.prepare();
+ prepareCompleted.waitForSignal();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE,
+ mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_PAUSED, mPlayer.getPlayerState());
+
+ playCompleted.reset();
+ mPlayer.play();
+ playCompleted.waitForSignal();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE,
+ mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_PLAYING, mPlayer.getPlayerState());
+
+ pauseCompleted.reset();
+ mPlayer.pause();
+ pauseCompleted.waitForSignal();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE,
+ mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_PAUSED, mPlayer.getPlayerState());
+
+ mPlayer.reset();
+ assertEquals(MediaPlayerBase.BUFFERING_STATE_UNKNOWN, mPlayer.getBufferingState());
+ assertEquals(MediaPlayerBase.PLAYER_STATE_IDLE, mPlayer.getPlayerState());
+ }
+
+ @Test
+ @LargeTest
+ public void testPlayerEventCallback() throws Throwable {
+ final int mp4Duration = 8484;
+
+ if (!checkLoadResource(R.raw.testvideo)) {
+ return; // skip;
+ }
+
+ mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface());
+
+ final Monitor onPrepareCalled = new Monitor();
+ final Monitor onSeekCompleteCalled = new Monitor();
+ final Monitor onPlayerStateChangedCalled = new Monitor();
+ final AtomicInteger playerState = new AtomicInteger();
+ final Monitor onBufferingStateChangedCalled = new Monitor();
+ final AtomicInteger bufferingState = new AtomicInteger();
+ final Monitor onPlaybackSpeedChanged = new Monitor();
+ final AtomicReference<Float> playbackSpeed = new AtomicReference<>();
+
+ MediaPlayerBase.PlayerEventCallback callback = new MediaPlayerBase.PlayerEventCallback() {
+ // TODO: implement and add test case for onCurrentDataSourceChanged() callback.
+ @Override
+ public void onMediaPrepared(MediaPlayerBase mpb, DataSourceDesc dsd) {
+ onPrepareCalled.signal();
+ }
+
+ @Override
+ public void onPlayerStateChanged(MediaPlayerBase mpb, int state) {
+ playerState.set(state);
+ onPlayerStateChangedCalled.signal();
+ }
+
+ @Override
+ public void onBufferingStateChanged(MediaPlayerBase mpb, DataSourceDesc dsd,
+ int state) {
+ bufferingState.set(state);
+ onBufferingStateChangedCalled.signal();
+ }
+
+ @Override
+ public void onPlaybackSpeedChanged(MediaPlayerBase mpb, float speed) {
+ playbackSpeed.set(speed);
+ onPlaybackSpeedChanged.signal();
+ }
+
+ @Override
+ public void onSeekCompleted(MediaPlayerBase mpb, long position) {
+ onSeekCompleteCalled.signal();
+ }
+ };
+ ExecutorService executor = Executors.newFixedThreadPool(1);
+ mPlayer.registerPlayerEventCallback(executor, callback);
+
+ onPrepareCalled.reset();
+ onPlayerStateChangedCalled.reset();
+ onBufferingStateChangedCalled.reset();
+ mPlayer.prepare();
+ do {
+ assertTrue(onBufferingStateChangedCalled.waitForSignal(1000));
+ } while (bufferingState.get() != MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_STARVED);
+
+ assertTrue(onPrepareCalled.waitForSignal(1000));
+ do {
+ assertTrue(onPlayerStateChangedCalled.waitForSignal(1000));
+ } while (playerState.get() != MediaPlayerBase.PLAYER_STATE_PAUSED);
+ do {
+ assertTrue(onBufferingStateChangedCalled.waitForSignal(1000));
+ } while (bufferingState.get() != MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
+
+ onSeekCompleteCalled.reset();
+ mPlayer.seekTo(mp4Duration >> 1, MediaPlayer2.SEEK_PREVIOUS_SYNC);
+ onSeekCompleteCalled.waitForSignal();
+
+ onPlaybackSpeedChanged.reset();
+ mPlayer.setPlaybackSpeed(0.5f);
+ do {
+ assertTrue(onPlaybackSpeedChanged.waitForSignal(1000));
+ } while (Math.abs(playbackSpeed.get() - 0.5f) > FLOAT_TOLERANCE);
+
+ mPlayer.reset();
+
+ mPlayer.unregisterPlayerEventCallback(callback);
+ executor.shutdown();
+ }
+
public void testRecordAndPlay() throws Exception {
if (!hasMicrophone()) {
return;
diff --git a/media/src/main/java/androidx/media/MediaPlayer2Impl.java b/media/src/main/java/androidx/media/MediaPlayer2Impl.java
index 59056a5..a4bb01e 100644
--- a/media/src/main/java/androidx/media/MediaPlayer2Impl.java
+++ b/media/src/main/java/androidx/media/MediaPlayer2Impl.java
@@ -38,6 +38,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;
@@ -76,7 +77,10 @@
// TODO: This class has too many locks. Use one single lock to protect internal variables.
private MediaPlayer mPlayer;
+ @PlayerState
private int mPlayerState;
+ @BuffState
+ private int mBufferingState;
private AudioAttributesCompat mAudioAttributes;
private final Object mSrcLock = new Object();
@@ -104,8 +108,11 @@
private final Object mEventCbLock = new Object();
@GuardedBy("mEventCbLock")
- private ArrayList<Pair<Executor, MediaPlayer2EventCallback>> mEventCallbackRecords =
+ private ArrayList<Pair<Executor, MediaPlayer2EventCallback>> mMp2EventCallbackRecords =
new ArrayList<>();
+ @GuardedBy("mEventCbLock")
+ private ArrayMap<PlayerEventCallback, Executor> mPlayerEventCallbackMap =
+ new ArrayMap<>();
private final Object mDrmEventCbLock = new Object();
@GuardedBy("mDrmEventCbLock")
@@ -124,7 +131,8 @@
Looper looper = mHandlerThread.getLooper();
mTaskHandler = new Handler(looper);
mPlayer = new MediaPlayer();
- mPlayerState = MediaPlayerBase.PLAYER_STATE_IDLE;
+ mPlayerState = PLAYER_STATE_IDLE;
+ mBufferingState = BUFFERING_STATE_UNKNOWN;
setUpListeners();
}
@@ -170,7 +178,7 @@
@Override
void process() {
mPlayer.start();
- mPlayerState = PLAYER_STATE_PLAYING;
+ setPlayerState(PLAYER_STATE_PLAYING);
}
});
}
@@ -191,6 +199,7 @@
@Override
void process() throws IOException {
mPlayer.prepareAsync();
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_STARVED);
}
});
}
@@ -198,8 +207,7 @@
/**
* Pauses playback. Call play() to resume.
*
- * @throws IllegalStateException if the internal player engine has not been
- * initialized.
+ * @throws IllegalStateException if the internal player engine has not been initialized.
*/
@Override
public void pause() {
@@ -207,7 +215,7 @@
@Override
void process() {
mPlayer.pause();
- mPlayerState = PLAYER_STATE_PAUSED;
+ setPlayerState(PLAYER_STATE_PAUSED);
}
});
}
@@ -241,7 +249,7 @@
* Gets the duration of the file.
*
* @return the duration in milliseconds, if no duration is available
- * (for example, if streaming live content), -1 is returned.
+ * (for example, if streaming live content), -1 is returned.
*/
@Override
public long getDuration() {
@@ -275,8 +283,7 @@
*/
@Override
public @BuffState int getBufferingState() {
- // TODO: use cached state or call native function.
- return BUFFERING_STATE_UNKNOWN;
+ return mBufferingState;
}
/**
@@ -437,7 +444,7 @@
addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_SPEED, false) {
@Override
void process() {
- mPlayer.setPlaybackParams(getPlaybackParams().setSpeed(speed));
+ setPlaybackParamsInternal(getPlaybackParams().setSpeed(speed));
}
});
}
@@ -508,8 +515,17 @@
*/
@Override
public void registerPlayerEventCallback(@NonNull Executor e,
- @NonNull PlayerEventCallback cb) {
- // TODO: implement this.
+ @NonNull PlayerEventCallback cb) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null PlayerEventCallback");
+ }
+ if (e == null) {
+ throw new IllegalArgumentException(
+ "Illegal null Executor for the PlayerEventCallback");
+ }
+ synchronized (mEventCbLock) {
+ mPlayerEventCallbackMap.put(cb, e);
+ }
}
/**
@@ -518,7 +534,12 @@
*/
@Override
public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb) {
- // TODO: implement this.
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null PlayerEventCallback");
+ }
+ synchronized (mEventCbLock) {
+ mPlayerEventCallbackMap.remove(cb);
+ }
}
@Override
@@ -528,7 +549,7 @@
void process() {
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb
- : mEventCallbackRecords) {
+ : mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -690,7 +711,6 @@
* non-zero speed is equivalent to calling play().
*
* @param params the playback params.
- *
* @throws IllegalStateException if the internal player engine has not been
* initialized or has been released.
* @throws IllegalArgumentException if params is not supported.
@@ -700,7 +720,7 @@
addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) {
@Override
void process() {
- mPlayer.setPlaybackParams(params);
+ setPlaybackParamsInternal(params);
}
});
}
@@ -722,7 +742,6 @@
* Sets A/V sync mode.
*
* @param params the A/V sync params to apply
- *
* @throws IllegalStateException if the internal player engine has not been
* initialized.
* @throws IllegalArgumentException if params are not supported.
@@ -741,9 +760,8 @@
* Gets the A/V sync mode.
*
* @return the A/V sync params
- *
* @throws IllegalStateException if the internal player engine has not been
- * initialized.
+ * initialized.
*/
@Override
@NonNull
@@ -805,8 +823,7 @@
* {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
*
* @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
- * is available, e.g. because the media player has not been initialized.
- *
+ * is available, e.g. because the media player has not been initialized.
* @see MediaTimestamp
*/
@Override
@@ -823,6 +840,8 @@
@Override
public void reset() {
mPlayer.reset();
+ setPlayerState(PLAYER_STATE_IDLE);
+ setBufferingState(BUFFERING_STATE_UNKNOWN);
/* FIXME: reset other internal variables. */
}
@@ -1092,11 +1111,11 @@
* In addition, the support for selecting an audio track at runtime is pretty limited
* in that an audio track can only be selected in the <em>Prepared</em> state.
* </p>
+ *
* @param index the index of the track to be selected. The valid range of the index
* is 0..total number of track - 1. The total number of tracks as well as the type of
* each individual track can be found by calling {@link #getTrackInfo()} method.
* @throws IllegalStateException if called in an invalid state.
- *
* @see MediaPlayer2#getTrackInfo
*/
@Override
@@ -1116,11 +1135,11 @@
* deselected. If the timed text track identified by index has not been
* selected before, it throws an exception.
* </p>
+ *
* @param index the index of the track to be deselected. The valid range of the index
* is 0..total number of tracks - 1. The total number of tracks as well as the type of
* each individual track can be found by calling {@link #getTrackInfo()} method.
* @throws IllegalStateException if called in an invalid state.
- *
* @see MediaPlayer2#getTrackInfo
*/
@Override
@@ -1142,7 +1161,7 @@
*/
@Override
public void setMediaPlayer2EventCallback(@NonNull Executor executor,
- @NonNull MediaPlayer2EventCallback eventCallback) {
+ @NonNull MediaPlayer2EventCallback eventCallback) {
if (eventCallback == null) {
throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
}
@@ -1151,7 +1170,7 @@
"Illegal null Executor for the MediaPlayer2EventCallback");
}
synchronized (mEventCbLock) {
- mEventCallbackRecords.add(new Pair(executor, eventCallback));
+ mMp2EventCallbackRecords.add(new Pair(executor, eventCallback));
}
}
@@ -1161,7 +1180,7 @@
@Override
public void clearMediaPlayer2EventCallback() {
synchronized (mEventCbLock) {
- mEventCallbackRecords.clear();
+ mMp2EventCallbackRecords.clear();
}
}
@@ -1257,15 +1276,14 @@
*
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
* from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
- *
- * @throws IllegalStateException if called before prepare(), or the DRM was
- * prepared already
- * @throws UnsupportedSchemeException if the crypto scheme is not supported
- * @throws ResourceBusyException if required DRM resources are in use
- * @throws ProvisioningNetworkErrorException if provisioning is required but failed due to a
- * network error
- * @throws ProvisioningServerErrorException if provisioning is required but failed due to
- * the request denied by the provisioning server
+ * @throws IllegalStateException if called before prepare(), or the DRM was
+ * prepared already
+ * @throws UnsupportedSchemeException if the crypto scheme is not supported
+ * @throws ResourceBusyException if required DRM resources are in use
+ * @throws ProvisioningNetworkErrorException if provisioning is required but failed due to a
+ * network error
+ * @throws ProvisioningServerErrorException if provisioning is required but failed due to
+ * the request denied by the provisioning server
*/
@Override
public void prepareDrm(@NonNull UUID uuid)
@@ -1410,6 +1428,8 @@
/**
* Read a DRM engine plugin String property value, given the property name string.
* <p>
+ *
+
* @param propertyName the property name
*
* Standard fields names are:
@@ -1431,6 +1451,7 @@
/**
* Set a DRM engine plugin String property value.
* <p>
+ *
* @param propertyName the property name
* @param value the property value
*
@@ -1449,14 +1470,73 @@
}
}
+ private void setPlaybackParamsInternal(final PlaybackParams params) {
+ PlaybackParams current = mPlayer.getPlaybackParams();
+ if (Math.abs(current.getSpeed() - params.getSpeed()) > 0.0001f) {
+ synchronized (mEventCbLock) {
+ final int callbackCount = mPlayerEventCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ final Executor executor = mPlayerEventCallbackMap.valueAt(i);
+ final PlayerEventCallback cb = mPlayerEventCallbackMap.keyAt(i);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ cb.onPlaybackSpeedChanged(MediaPlayer2Impl.this, params.getSpeed());
+ }
+ });
+ }
+ }
+ }
+ mPlayer.setPlaybackParams(params);
+ }
+
+ private void setPlayerState(@PlayerState final int state) {
+ if (mPlayerState != state) {
+ synchronized (mEventCbLock) {
+ final int callbackCount = mPlayerEventCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ final Executor executor = mPlayerEventCallbackMap.valueAt(i);
+ final PlayerEventCallback cb = mPlayerEventCallbackMap.keyAt(i);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ cb.onPlayerStateChanged(MediaPlayer2Impl.this, state);
+ }
+ });
+ }
+ }
+ mPlayerState = state;
+ }
+ }
+
+ private void setBufferingState(@BuffState final int state) {
+ if (mBufferingState != state) {
+ synchronized (mEventCbLock) {
+ final int callbackCount = mPlayerEventCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ final Executor executor = mPlayerEventCallbackMap.valueAt(i);
+ final PlayerEventCallback cb = mPlayerEventCallbackMap.keyAt(i);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ cb.onBufferingStateChanged(MediaPlayer2Impl.this, mCurrentDSD, state);
+ }
+ });
+ }
+ }
+ mBufferingState = state;
+ }
+ }
+
private void setUpListeners() {
mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
- mPlayerState = PLAYER_STATE_PAUSED;
+ setPlayerState(PLAYER_STATE_PAUSED);
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1465,6 +1545,17 @@
}
});
}
+ final int callbackCount = mPlayerEventCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ final Executor executor = mPlayerEventCallbackMap.valueAt(i);
+ final PlayerEventCallback cb = mPlayerEventCallbackMap.keyAt(i);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ cb.onMediaPrepared(MediaPlayer2Impl.this, mCurrentDSD);
+ }
+ });
+ }
}
synchronized (mTaskLock) {
if (mCurrentTask != null
@@ -1483,7 +1574,7 @@
public void onVideoSizeChanged(MediaPlayer mp, final int width, final int height) {
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1498,11 +1589,11 @@
mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
- switch(what) {
+ switch (what) {
case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1513,6 +1604,12 @@
}
}
break;
+ case MediaPlayer.MEDIA_INFO_BUFFERING_START:
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_STARVED);
+ break;
+ case MediaPlayer.MEDIA_INFO_BUFFERING_END:
+ setBufferingState(BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
+ break;
}
return false;
}
@@ -1520,10 +1617,10 @@
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
- mPlayerState = PLAYER_STATE_PAUSED;
+ setPlayerState(PLAYER_STATE_PAUSED);
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1538,10 +1635,11 @@
mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, final int what, final int extra) {
- mPlayerState = PLAYER_STATE_ERROR;
+ setPlayerState(PLAYER_STATE_ERROR);
+ setBufferingState(BUFFERING_STATE_UNKNOWN);
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1567,6 +1665,22 @@
processPendingTask_l();
}
}
+ synchronized (mEventCbLock) {
+ final long seekPos = getCurrentPosition();
+ final int callbackCount = mPlayerEventCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ final Executor executor = mPlayerEventCallbackMap.valueAt(i);
+ final PlayerEventCallback cb = mPlayerEventCallbackMap.keyAt(i);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ // TODO: The actual seeked position might be different from the
+ // requested position. Clarify which one is expected here.
+ cb.onSeekCompleted(MediaPlayer2Impl.this, seekPos);
+ }
+ });
+ }
+ }
}
});
mPlayer.setOnTimedMetaDataAvailableListener(
@@ -1575,7 +1689,7 @@
public void onTimedMetaDataAvailable(MediaPlayer mp, final TimedMetaData data) {
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1592,7 +1706,7 @@
public boolean onInfo(MediaPlayer mp, final int what, final int extra) {
synchronized (mEventCbLock) {
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1608,10 +1722,13 @@
mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, final int percent) {
+ if (percent >= 100) {
+ setBufferingState(BUFFERING_STATE_BUFFERING_COMPLETE);
+ }
synchronized (mEventCbLock) {
mBufferedPercentageCurrent.set(percent);
for (final Pair<Executor, MediaPlayer2EventCallback> cb :
- mEventCallbackRecords) {
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {
@@ -1737,9 +1854,9 @@
subset = Arrays.copyOfRange(pssh, i, i + dataLenSize);
int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
? ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16)
- | ((subset[1] & 0xff) << 8) | (subset[0] & 0xff)
+ | ((subset[1] & 0xff) << 8) | (subset[0] & 0xff)
: ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16)
- | ((subset[2] & 0xff) << 8) | (subset[3] & 0xff);
+ | ((subset[2] & 0xff) << 8) | (subset[3] & 0xff);
i += dataLenSize;
len -= dataLenSize;
@@ -1852,7 +1969,8 @@
return;
}
synchronized (mEventCbLock) {
- for (final Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
+ for (final Pair<Executor, MediaPlayer2EventCallback> cb :
+ mMp2EventCallbackRecords) {
cb.first.execute(new Runnable() {
@Override
public void run() {