Merge "MediaPlayer2Impl: pack source info into subclass"

This commit is contained in:
Robert Shih
2018-11-14 03:38:52 +00:00
committed by Android (Google) Code Review

View File

@@ -56,15 +56,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
@@ -94,17 +99,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);
@@ -227,7 +226,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
@@ -268,9 +275,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);
}
}
});
@@ -283,10 +289,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();
}
@@ -309,9 +313,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();
}
@@ -323,22 +328,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;
}
}
@@ -707,34 +705,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();
}
}
@@ -749,19 +742,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;
mCurrentSourceInfo = mNextSourceInfos.poll();
long srcId = mCurrentSrcId;
long srcId = mCurrentSourceInfo.mId;
try {
nativePlayNextDataSource(srcId);
} catch (Exception e) {
@@ -776,9 +764,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();
}
}
@@ -1073,12 +1060,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();
}
synchronized (mTaskLock) {
@@ -1532,20 +1515,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:
@@ -1561,14 +1535,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();
}
}
@@ -1621,7 +1597,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) {
@@ -1632,11 +1608,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();
@@ -1667,13 +1645,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;
}
@@ -1751,7 +1727,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
});
if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
if (isCurrentSrcId) {
if (isCurrentSource(srcId)) {
prepareNextDataSource();
}
}
@@ -1854,6 +1830,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
}
}
}
/*
@@ -2130,7 +2107,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public void notify(DrmEventCallback callback) {
callback.onDrmPrepared(
MediaPlayer2Impl.this, mCurrentDSD, prepareDrmStatus);
MediaPlayer2Impl.this, getCurrentDataSource(), prepareDrmStatus);
}
});
@@ -2196,7 +2173,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) {
@@ -2817,7 +2794,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public void notify(DrmEventCallback callback) {
callback.onDrmPrepared(
mediaPlayer, mCurrentDSD, status);
mediaPlayer, getCurrentDataSource(), status);
}
});
@@ -3084,9 +3061,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
} catch (Exception e) {
status = CALL_STATUS_ERROR_UNKNOWN;
}
synchronized (mSrcLock) {
mDSD = mCurrentDSD;
}
mDSD = getCurrentDataSource();
if (mMediaCallType != CALL_COMPLETED_SEEK_TO) {
synchronized (mTaskLock) {
@@ -3129,4 +3104,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;
}
}