summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java225
1 files changed, 123 insertions, 102 deletions
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 2b5dea157c90..38975d081074 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -57,15 +57,20 @@ import java.net.URL;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.UUID;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
/**
* @hide
@@ -95,17 +100,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private final Object mSrcLock = new Object();
//--- guarded by |mSrcLock| start
- private long mSrcIdGenerator = 0;
- private DataSourceDesc mCurrentDSD;
- private long mCurrentSrcId = mSrcIdGenerator++;
- private List<DataSourceDesc> mNextDSDs;
- private long mNextSrcId = mSrcIdGenerator++;
- private int mNextSourceState = NEXT_SOURCE_STATE_INIT;
- private boolean mNextSourcePlayPending = false;
+ private SourceInfo mCurrentSourceInfo;
+ private final Queue<SourceInfo> mNextSourceInfos = new ConcurrentLinkedQueue<>();
//--- guarded by |mSrcLock| end
+ private final AtomicLong mSrcIdGenerator = new AtomicLong(0);
- private AtomicInteger mBufferedPercentageCurrent = new AtomicInteger(0);
- private AtomicInteger mBufferedPercentageNext = new AtomicInteger(0);
private volatile float mVolume = 1.0f;
private VideoSize mVideoSize = new VideoSize(0, 0);
@@ -221,7 +220,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public long getBufferedPosition() {
// Use cached buffered percent for now.
- return getDuration() * mBufferedPercentageCurrent.get() / 100;
+ int bufferedPercentage;
+ synchronized (mSrcLock) {
+ if (mCurrentSourceInfo == null) {
+ bufferedPercentage = 0;
+ } else {
+ bufferedPercentage = mCurrentSourceInfo.mBufferedPercentage.get();
+ }
+ }
+ return getDuration() * bufferedPercentage / 100;
}
@Override
@@ -263,9 +270,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
synchronized (mSrcLock) {
- mCurrentDSD = dsd;
- mCurrentSrcId = mSrcIdGenerator++;
- handleDataSource(true /* isCurrent */, dsd, mCurrentSrcId);
+ mCurrentSourceInfo = new SourceInfo(dsd);
+ handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId);
}
}
});
@@ -278,10 +284,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
void process() {
checkArgument(dsd != null, "the DataSourceDesc cannot be null");
synchronized (mSrcLock) {
- mNextDSDs = new ArrayList<DataSourceDesc>(1);
- mNextDSDs.add(dsd);
- mNextSrcId = mSrcIdGenerator++;
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mNextSourceInfos.clear();
+ mNextSourceInfos.add(new SourceInfo(dsd));
}
prepareNextDataSource();
}
@@ -304,9 +308,10 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
synchronized (mSrcLock) {
- mNextDSDs = new ArrayList(dsds);
- mNextSrcId = mSrcIdGenerator++;
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mNextSourceInfos.clear();
+ for (DataSourceDesc dsd : dsds) {
+ mNextSourceInfos.add(new SourceInfo(dsd));
+ }
}
prepareNextDataSource();
}
@@ -318,22 +323,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) {
@Override
void process() {
- synchronized (mSrcLock) {
- if (mNextDSDs != null) {
- mNextDSDs.clear();
- mNextDSDs = null;
- }
- mNextSrcId = mSrcIdGenerator++;
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
- }
+ mNextSourceInfos.clear();
}
});
}
@Override
- public @NonNull DataSourceDesc getCurrentDataSource() {
+ public DataSourceDesc getCurrentDataSource() {
synchronized (mSrcLock) {
- return mCurrentDSD;
+ return mCurrentSourceInfo == null ? null : mCurrentSourceInfo.mDSD;
}
}
@@ -702,34 +700,29 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
boolean hasNextDSD;
- synchronized (mSrcLock) {
- hasNextDSD = (mNextDSDs != null && !mNextDSDs.isEmpty());
- }
-
int state = getState();
- if (state == PLAYER_STATE_ERROR || state == PLAYER_STATE_IDLE) {
- // Current source has not been prepared yet.
- return hasNextDSD;
- }
-
synchronized (mSrcLock) {
- if (!hasNextDSD || mNextSourceState != NEXT_SOURCE_STATE_INIT) {
+ hasNextDSD = !mNextSourceInfos.isEmpty();
+ if (state == PLAYER_STATE_ERROR || state == PLAYER_STATE_IDLE) {
+ // Current source has not been prepared yet.
+ return hasNextDSD;
+ }
+
+ SourceInfo nextSource = mNextSourceInfos.peek();
+ if (!hasNextDSD || nextSource.mStateAsNextSource != NEXT_SOURCE_STATE_INIT) {
// There is no next source or it's in preparing or prepared state.
return hasNextDSD;
}
try {
- mNextSourceState = NEXT_SOURCE_STATE_PREPARING;
- handleDataSource(false /* isCurrent */, mNextDSDs.get(0), mNextSrcId);
+ nextSource.mStateAsNextSource = NEXT_SOURCE_STATE_PREPARING;
+ handleDataSource(false /* isCurrent */, nextSource.mDSD, nextSource.mId);
} catch (Exception e) {
Message msg = mTaskHandler.obtainMessage(
MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null);
- mTaskHandler.handleMessage(msg, mNextSrcId);
+ mTaskHandler.handleMessage(msg, nextSource.mId);
- mNextDSDs.remove(0);
- // make a new SrcId to obsolete notification for previous one.
- mNextSrcId = mSrcIdGenerator++;
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mNextSourceInfos.poll();
return prepareNextDataSource();
}
}
@@ -744,19 +737,14 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
boolean hasNextDSD = false;
synchronized (mSrcLock) {
- if (mNextDSDs != null && !mNextDSDs.isEmpty()) {
+ if (!mNextSourceInfos.isEmpty()) {
hasNextDSD = true;
- if (mNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
+ SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+ if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) {
// Switch to next source only when it has been prepared.
- mCurrentDSD = mNextDSDs.get(0);
- mCurrentSrcId = mNextSrcId;
- mBufferedPercentageCurrent.set(mBufferedPercentageNext.get());
- mNextDSDs.remove(0);
- mNextSrcId = mSrcIdGenerator++; // make it different from |mCurrentSrcId|
- mBufferedPercentageNext.set(0);
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
-
- long srcId = mCurrentSrcId;
+ mCurrentSourceInfo = mNextSourceInfos.poll();
+
+ long srcId = mCurrentSourceInfo.mId;
try {
nativePlayNextDataSource(srcId);
} catch (Exception e) {
@@ -771,9 +759,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
// Now a new current src is playing.
// Wait for MEDIA_INFO_DATA_SOURCE_START to prepare next source.
- mNextSourcePlayPending = false;
}
- } else if (mNextSourceState == NEXT_SOURCE_STATE_INIT) {
+ } else if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_INIT) {
hasNextDSD = prepareNextDataSource();
}
}
@@ -1180,12 +1167,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
mDrmEventCallbackRecords.clear();
}
synchronized (mSrcLock) {
- if (mNextDSDs != null) {
- mNextDSDs.clear();
- mNextDSDs = null;
- }
- mNextSrcId = mSrcIdGenerator++;
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mCurrentSourceInfo = null;
+ mNextSourceInfos.clear();
}
stayAwake(false);
@@ -1637,20 +1620,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
final int what = msg.arg1;
final int extra = msg.arg2;
- final DataSourceDesc dsd;
- boolean isCurrentSrcId = false;
- boolean isNextSrcId = false;
- synchronized (mSrcLock) {
- if (srcId == mCurrentSrcId) {
- dsd = mCurrentDSD;
- isCurrentSrcId = true;
- } else if (mNextDSDs != null && !mNextDSDs.isEmpty() && srcId == mNextSrcId) {
- dsd = mNextDSDs.get(0);
- isNextSrcId = true;
- } else {
- return;
- }
+ final SourceInfo sourceInfo = getSourceInfoById(srcId);
+ if (sourceInfo == null) {
+ return;
}
+ final DataSourceDesc dsd = sourceInfo.mDSD;
switch(msg.what) {
case MEDIA_PREPARED:
@@ -1666,14 +1640,16 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
synchronized (mSrcLock) {
+ SourceInfo nextSourceInfo = mNextSourceInfos.peek();
Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
- + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
+ + ", curSrc=" + mCurrentSourceInfo
+ + ", nextSrc=" + nextSourceInfo);
- if (isCurrentSrcId) {
+ if (isCurrentSource(srcId)) {
prepareNextDataSource();
- } else if (isNextSrcId) {
- mNextSourceState = NEXT_SOURCE_STATE_PREPARED;
- if (mNextSourcePlayPending) {
+ } else if (isNextSource(srcId)) {
+ nextSourceInfo.mStateAsNextSource = NEXT_SOURCE_STATE_PREPARED;
+ if (nextSourceInfo.mPlayPendingAsNextSource) {
playNextDataSource();
}
}
@@ -1726,7 +1702,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_PLAYBACK_COMPLETE:
{
- if (isCurrentSrcId) {
+ if (isCurrentSource(srcId)) {
sendEvent(new EventNotifier() {
@Override
public void notify(EventCallback callback) {
@@ -1737,11 +1713,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
stayAwake(false);
synchronized (mSrcLock) {
- mNextSourcePlayPending = true;
-
+ SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+ if (nextSourceInfo != null) {
+ nextSourceInfo.mPlayPendingAsNextSource = true;
+ }
Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
- + ", currentSrcId=" + mCurrentSrcId
- + ", nextSrcId=" + mNextSrcId);
+ + ", curSrc=" + mCurrentSourceInfo
+ + ", nextSrc=" + nextSourceInfo);
}
playNextDataSource();
@@ -1772,13 +1750,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
});
- synchronized (mSrcLock) {
- if (isCurrentSrcId) {
- mBufferedPercentageCurrent.set(percent);
- } else if (isNextSrcId) {
- mBufferedPercentageNext.set(percent);
- }
+ SourceInfo src = getSourceInfoById(srcId);
+ if (src != null) {
+ src.mBufferedPercentage.set(percent);
}
+
return;
}
@@ -1850,7 +1826,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
});
if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
- if (isCurrentSrcId) {
+ if (isCurrentSource(srcId)) {
prepareNextDataSource();
}
}
@@ -1965,6 +1941,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
}
}
+
}
/*
@@ -2241,7 +2218,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public void notify(DrmEventCallback callback) {
callback.onDrmPrepared(
- MediaPlayer2Impl.this, mCurrentDSD, prepareDrmStatus);
+ MediaPlayer2Impl.this, getCurrentDataSource(), prepareDrmStatus);
}
});
@@ -2307,7 +2284,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
// call the callback outside the lock
if (mOnDrmConfigHelper != null) {
- mOnDrmConfigHelper.onDrmConfig(this, mCurrentDSD);
+ mOnDrmConfigHelper.onDrmConfig(this, getCurrentDataSource());
}
synchronized (mDrmLock) {
@@ -2956,7 +2933,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public void notify(DrmEventCallback callback) {
callback.onDrmPrepared(
- mediaPlayer, mCurrentDSD, status);
+ mediaPlayer, getCurrentDataSource(), status);
}
});
@@ -3223,9 +3200,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
} catch (Exception e) {
status = CALL_STATUS_ERROR_UNKNOWN;
}
- synchronized (mSrcLock) {
- mDSD = mCurrentDSD;
- }
+ mDSD = getCurrentDataSource();
// TODO: Make native implementations asynchronous and let them send notifications.
if (!mNeedToWaitForEventToComplete || status != CALL_STATUS_NO_ERROR) {
@@ -3262,4 +3237,50 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
super(detailMessage);
}
};
+
+ private final class SourceInfo {
+ final DataSourceDesc mDSD;
+ final long mId = mSrcIdGenerator.getAndIncrement();
+ AtomicInteger mBufferedPercentage = new AtomicInteger(0);
+
+ // m*AsNextSource (below) only applies to pending data sources in the playlist;
+ // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource}
+ // are undefined.
+ int mStateAsNextSource = NEXT_SOURCE_STATE_INIT;
+ boolean mPlayPendingAsNextSource = false;
+
+ SourceInfo(DataSourceDesc dsd) {
+ this.mDSD = dsd;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s(%d)", SourceInfo.class.getName(), mId);
+ }
+
+ }
+
+ private SourceInfo getSourceInfoById(long srcId) {
+ synchronized (mSrcLock) {
+ if (isCurrentSource(srcId)) {
+ return mCurrentSourceInfo;
+ }
+ if (isNextSource(srcId)) {
+ return mNextSourceInfos.peek();
+ }
+ }
+ return null;
+ }
+
+ private boolean isCurrentSource(long srcId) {
+ synchronized (mSrcLock) {
+ return mCurrentSourceInfo != null && mCurrentSourceInfo.mId == srcId;
+ }
+ }
+
+ private boolean isNextSource(long srcId) {
+ SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+ return nextSourceInfo != null && nextSourceInfo.mId == srcId;
+ }
+
}