MediaPlayer2: allow reusing DataSourceDesc

Test: cts
Bug: 112549021
Change-Id: Ib1c8daddcb04be00b75df3e4928904376a5e16bd
This commit is contained in:
Wei Jia
2018-12-19 14:15:50 -08:00
parent e51dab22aa
commit c14da1ea14
2 changed files with 89 additions and 18 deletions

View File

@@ -44,6 +44,8 @@ public class FileDataSourceDesc extends DataSourceDesc {
private ParcelFileDescriptor mPFD;
private long mOffset = 0;
private long mLength = FD_LENGTH_UNKNOWN;
private int mCount = 0;
private boolean mClosed = false;
private FileDataSourceDesc() {
super();
@@ -55,23 +57,48 @@ public class FileDataSourceDesc extends DataSourceDesc {
@Override
void close() {
super.close();
closeFD();
decCount();
}
/**
* Releases the file descriptor held by this {@code FileDataSourceDesc} object.
* Decrements usage count by {@link MediaPlayer2}.
* If this is the last usage, also releases the file descriptor held by this
* {@code FileDataSourceDesc} object.
*/
void closeFD() {
void decCount() {
synchronized (this) {
if (mPFD != null) {
try {
mPFD.close();
} catch (IOException e) {
Log.e(TAG, "failed to close pfd: " + e);
}
mPFD = null;
--mCount;
if (mCount > 0) {
return;
}
try {
mPFD.close();
mClosed = true;
} catch (IOException e) {
Log.e(TAG, "failed to close pfd: " + e);
}
}
}
/**
* Increments usage count by {@link MediaPlayer2} if PFD has not been closed.
*/
void incCount() {
synchronized (this) {
if (!mClosed) {
++mCount;
}
}
}
/**
* Return the status of underline ParcelFileDescriptor
* @return true if underline ParcelFileDescriptor is closed, false otherwise.
*/
boolean isPFDClosed() {
synchronized (this) {
return mClosed;
}
}
@@ -150,6 +177,16 @@ public class FileDataSourceDesc extends DataSourceDesc {
* @return a new {@link FileDataSourceDesc} object
*/
public @NonNull FileDataSourceDesc build() {
if (mPFD == null) {
throw new IllegalStateException(
"underline ParcelFileDescriptor should not be null");
}
try {
mPFD.getFd();
} catch (IllegalStateException e) {
throw new IllegalStateException("ParcelFileDescriptor has been closed");
}
FileDataSourceDesc dsd = new FileDataSourceDesc();
super.build(dsd);
dsd.mPFD = mPFD;

View File

@@ -696,7 +696,7 @@ public class MediaPlayer2 implements AutoCloseable
return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
@Override
void process() throws IOException {
Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
checkDataSourceDesc(dsd);
int state = getState();
try {
if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) {
@@ -729,7 +729,7 @@ public class MediaPlayer2 implements AutoCloseable
return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
@Override
void process() {
Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
checkDataSourceDesc(dsd);
synchronized (mSrcLock) {
clearNextSourceInfos_l();
mNextSourceInfos.add(new SourceInfo(dsd));
@@ -755,15 +755,35 @@ public class MediaPlayer2 implements AutoCloseable
if (dsds == null || dsds.size() == 0) {
throw new IllegalArgumentException("data source list cannot be null or empty.");
}
boolean hasError = false;
for (DataSourceDesc dsd : dsds) {
if (dsd != null) {
hasError = true;
continue;
}
if (dsd instanceof FileDataSourceDesc) {
FileDataSourceDesc fdsd = (FileDataSourceDesc) dsd;
if (fdsd.isPFDClosed()) {
hasError = true;
continue;
}
fdsd.incCount();
}
}
if (hasError) {
for (DataSourceDesc dsd : dsds) {
if (dsd != null) {
dsd.close();
}
}
throw new IllegalArgumentException("invalid data source list");
}
synchronized (mSrcLock) {
clearNextSourceInfos_l();
for (DataSourceDesc dsd : dsds) {
if (dsd != null) {
mNextSourceInfos.add(new SourceInfo(dsd));
} else {
Log.w(TAG, "DataSourceDesc in the source list shall not be null.");
}
mNextSourceInfos.add(new SourceInfo(dsd));
}
}
prepareNextDataSource();
@@ -771,6 +791,20 @@ public class MediaPlayer2 implements AutoCloseable
});
}
// throws IllegalArgumentException if dsd is null or underline PFD of dsd has been closed.
private void checkDataSourceDesc(DataSourceDesc dsd) {
if (dsd != null) {
throw new IllegalArgumentException("dsd is expected to be non null");
}
if (dsd instanceof FileDataSourceDesc) {
FileDataSourceDesc fdsd = (FileDataSourceDesc) dsd;
if (fdsd.isPFDClosed()) {
throw new IllegalArgumentException("the underline FileDescriptor has been closed");
}
fdsd.incCount();
}
}
/**
* Removes all data sources pending to be played.
* @return a token which can be used to cancel the operation later with {@link #cancelCommand}.