Loading media/java/android/media/CallbackDataSourceDesc.java +4 −2 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ import android.annotation.NonNull; /** * @hide * Structure for file data source descriptor. * Structure of data source descriptor for sources using callback. * * Used by {@link MediaPlayer2#setDataSource(CallbackDataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}. Loading media/java/android/media/DataSourceDesc.java +17 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ import android.annotation.NonNull; * @hide * Base class of data source descriptor. * * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use subclasses' builder to change {@link DataSourceDesc}. Loading @@ -30,7 +32,7 @@ import android.annotation.NonNull; */ public class DataSourceDesc { // intentionally less than long.MAX_VALUE public static final long LONG_MAX = 0x7ffffffffffffffL; static final long LONG_MAX = 0x7ffffffffffffffL; // keep consistent with native code public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000; Loading @@ -45,6 +47,19 @@ public class DataSourceDesc { DataSourceDesc() { } /** * Releases the resources held by this {@code DataSourceDesc} object. */ void close() { } // Have to declare protected for finalize() since it is protected // in the base class Object. @Override protected void finalize() throws Throwable { close(); } /** * Return the media Id of data source. * @return the media Id of data source Loading media/java/android/media/FileDataSourceDesc.java +74 −33 Original line number Diff line number Diff line Loading @@ -17,20 +17,26 @@ package android.media; import android.annotation.NonNull; import android.os.ParcelFileDescriptor; import android.util.Log; import java.io.FileDescriptor; import java.io.IOException; /** * @hide * Structure for data source descriptor. * Structure of data source descriptor for sources using file descriptor. * * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}. * */ public class FileDataSourceDesc extends DataSourceDesc { private static final String TAG = "FileDataSourceDesc"; /** * Used when the length of file descriptor is unknown. * Loading @@ -38,34 +44,61 @@ public class FileDataSourceDesc extends DataSourceDesc { */ public static final long FD_LENGTH_UNKNOWN = LONG_MAX; private FileDescriptor mFD; private ParcelFileDescriptor mPFD; private long mOffset = 0; private long mLength = FD_LENGTH_UNKNOWN; private FileDataSourceDesc() { super(); } /** * Releases the resources held by this {@code FileDataSourceDesc} object. */ @Override void close() { super.close(); closeFD(); } /** * Releases the file descriptor held by this {@code FileDataSourceDesc} object. */ void closeFD() { synchronized (this) { if (mPFD != null) { try { mPFD.close(); } catch (IOException e) { Log.e(TAG, "failed to close pfd: " + e); } mPFD = null; } } } /** * Return the FileDescriptor of this data source. * @return the FileDescriptor of this data source * Return the ParcelFileDescriptor of this data source. * @return the ParcelFileDescriptor of this data source */ public FileDescriptor getFileDescriptor() { return mFD; public ParcelFileDescriptor getParcelFileDescriptor() { return mPFD; } /** * Return the offset associated with the FileDescriptor of this data source. * Return the offset associated with the ParcelFileDescriptor of this data source. * It's meaningful only when it has been set by the {@link Builder}. * @return the offset associated with the FileDescriptor of this data source * @return the offset associated with the ParcelFileDescriptor of this data source */ public long getOffset() { return mOffset; } /** * Return the content length associated with the FileDescriptor of this data source. * Return the content length associated with the ParcelFileDescriptor of this data source. * {@link #FD_LENGTH_UNKNOWN} means same as the length of source content. * @return the content length associated with the FileDescriptor of this data source * @return the content length associated with the ParcelFileDescriptor of this data source */ public long getLength() { return mLength; Loading @@ -78,7 +111,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * * <pre class="prettyprint"> * FileDataSourceDesc newDSD = new FileDataSourceDesc.Builder() * .setDataSource(fd, 0, srcLength) * .setDataSource(pfd, 0, srcLength) * .setStartPosition(1000) * .setEndPosition(15000) * .build(); Loading @@ -86,7 +119,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * </pre> */ public static class Builder extends BuilderBase<Builder> { private FileDescriptor mFD; private ParcelFileDescriptor mPFD; private long mOffset = 0; private long mLength = FD_LENGTH_UNKNOWN; Loading @@ -107,7 +140,7 @@ public class FileDataSourceDesc extends DataSourceDesc { if (dsd == null) { return; // use default } mFD = dsd.mFD; mPFD = dsd.mPFD; mOffset = dsd.mOffset; mLength = dsd.mLength; } Loading @@ -122,7 +155,7 @@ public class FileDataSourceDesc extends DataSourceDesc { public @NonNull FileDataSourceDesc build() { FileDataSourceDesc dsd = new FileDataSourceDesc(); super.build(dsd); dsd.mFD = mFD; dsd.mPFD = mPFD; dsd.mOffset = mOffset; dsd.mLength = mLength; Loading @@ -130,38 +163,46 @@ public class FileDataSourceDesc extends DataSourceDesc { } /** * Sets the data source (FileDescriptor) to use. The FileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility * to close the file descriptor after the source has been used. * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc} * created by this builder is passed to {@link MediaPlayer2} via * {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} or * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)}, MediaPlayer2 will * close the ParcelFileDescriptor. * * @param fd the FileDescriptor for the file to play * @param pfd the ParcelFileDescriptor for the file to play * @return the same Builder instance. * @throws NullPointerException if fd is null. * @throws NullPointerException if pfd is null. */ public @NonNull Builder setDataSource(@NonNull FileDescriptor fd) { Media2Utils.checkArgument(fd != null, "fd cannot be null."); public @NonNull Builder setDataSource(@NonNull ParcelFileDescriptor pfd) { Media2Utils.checkArgument(pfd != null, "pfd cannot be null."); resetDataSource(); mFD = fd; mPFD = pfd; return this; } /** * Sets the data source (FileDescriptor) to use. The FileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility * to close the file descriptor after the source has been used. * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc} * created by this builder is passed to {@link MediaPlayer2} via * {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} or * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)}, MediaPlayer2 will * close the ParcelFileDescriptor. * * Any negative number for offset is treated as 0. * Any negative number for length is treated as maximum length of the data source. * * @param fd the FileDescriptor for the file to play * @param pfd the ParcelFileDescriptor for the file to play * @param offset the offset into the file where the data to be played starts, in bytes * @param length the length in bytes of the data to be played * @return the same Builder instance. * @throws NullPointerException if fd is null. * @throws NullPointerException if pfd is null. */ public @NonNull Builder setDataSource( @NonNull FileDescriptor fd, long offset, long length) { Media2Utils.checkArgument(fd != null, "fd cannot be null."); @NonNull ParcelFileDescriptor pfd, long offset, long length) { Media2Utils.checkArgument(pfd != null, "pfd cannot be null."); if (offset < 0) { offset = 0; } Loading @@ -169,14 +210,14 @@ public class FileDataSourceDesc extends DataSourceDesc { length = FD_LENGTH_UNKNOWN; } resetDataSource(); mFD = fd; mPFD = pfd; mOffset = offset; mLength = length; return this; } private void resetDataSource() { mFD = null; mPFD = null; mOffset = 0; mLength = FD_LENGTH_UNKNOWN; } Loading media/java/android/media/MediaPlayer2.java +75 −28 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.PowerManager; import android.util.Log; Loading Loading @@ -412,6 +413,9 @@ public class MediaPlayer2 implements AutoCloseable mHandlerThread = null; } setCurrentSourceInfo(null); clearNextSourceInfos(); // Modular DRM clean up mOnDrmConfigHelper = null; synchronized (mDrmEventCbLock) { Loading Loading @@ -457,10 +461,8 @@ public class MediaPlayer2 implements AutoCloseable synchronized (mDrmEventCbLock) { mDrmEventCallbackRecords.clear(); } synchronized (mSrcLock) { mCurrentSourceInfo = null; mNextSourceInfos.clear(); } setCurrentSourceInfo(null); clearNextSourceInfos(); synchronized (mTaskLock) { mPendingTasks.clear(); Loading Loading @@ -685,6 +687,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets the data source as described by a DataSourceDesc. * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsd the descriptor of data source you want to play * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. Loading @@ -696,14 +700,18 @@ public class MediaPlayer2 implements AutoCloseable void process() throws IOException { Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null"); int state = getState(); try { if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) { throw new IllegalStateException("called in wrong state " + state); } synchronized (mSrcLock) { mCurrentSourceInfo = new SourceInfo(dsd); setCurrentSourceInfo(new SourceInfo(dsd)); handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId); } } finally { dsd.close(); } } }); } Loading @@ -711,6 +719,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets a single data source as described by a DataSourceDesc which will be played * after current data source is finished. * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsd the descriptor of data source you want to play after current one * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. Loading @@ -722,7 +732,7 @@ public class MediaPlayer2 implements AutoCloseable void process() { Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null"); synchronized (mSrcLock) { mNextSourceInfos.clear(); clearNextSourceInfos(); mNextSourceInfos.add(new SourceInfo(dsd)); } prepareNextDataSource(); Loading @@ -732,6 +742,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets a list of data sources to be played sequentially after current data source is done. * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsds the list of data sources you want to play after current one * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. Loading @@ -744,17 +756,15 @@ public class MediaPlayer2 implements AutoCloseable if (dsds == null || dsds.size() == 0) { throw new IllegalArgumentException("data source list cannot be null or empty."); } for (DataSourceDesc dsd : dsds) { if (dsd == null) { throw new IllegalArgumentException( "DataSourceDesc in the source list cannot be null."); } } synchronized (mSrcLock) { mNextSourceInfos.clear(); clearNextSourceInfos(); 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."); } } } prepareNextDataSource(); Loading @@ -771,7 +781,7 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) { @Override void process() { mNextSourceInfos.clear(); clearNextSourceInfos(); } }); } Loading Loading @@ -802,7 +812,7 @@ public class MediaPlayer2 implements AutoCloseable FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd; handleDataSource(isCurrent, srcId, fileDSD.getFileDescriptor(), fileDSD.getParcelFileDescriptor(), fileDSD.getOffset(), fileDSD.getLength(), fileDSD.getStartPosition(), Loading Loading @@ -886,7 +896,7 @@ public class MediaPlayer2 implements AutoCloseable if (afd.getDeclaredLength() < 0) { handleDataSource(isCurrent, srcId, afd.getFileDescriptor(), ParcelFileDescriptor.dup(afd.getFileDescriptor()), 0, DataSourceDesc.LONG_MAX, startPos, Loading @@ -894,7 +904,7 @@ public class MediaPlayer2 implements AutoCloseable } else { handleDataSource(isCurrent, srcId, afd.getFileDescriptor(), ParcelFileDescriptor.dup(afd.getFileDescriptor()), afd.getStartOffset(), afd.getDeclaredLength(), startPos, Loading Loading @@ -960,7 +970,8 @@ public class MediaPlayer2 implements AutoCloseable if (file.exists()) { FileInputStream is = new FileInputStream(file); FileDescriptor fd = is.getFD(); handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX, startPos, endPos); handleDataSource(isCurrent, srcId, ParcelFileDescriptor.dup(fd), 0, DataSourceDesc.LONG_MAX, startPos, endPos); is.close(); } else { throw new IOException("handleDataSource failed."); Loading @@ -984,9 +995,10 @@ public class MediaPlayer2 implements AutoCloseable */ private void handleDataSource( boolean isCurrent, long srcId, FileDescriptor fd, long offset, long length, ParcelFileDescriptor pfd, long offset, long length, long startPos, long endPos) throws IOException { nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length, startPos, endPos); nativeHandleDataSourceFD(isCurrent, srcId, pfd.getFileDescriptor(), offset, length, startPos, endPos); } private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId, Loading Loading @@ -1037,7 +1049,10 @@ public class MediaPlayer2 implements AutoCloseable MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null); mTaskHandler.handleMessage(msg, nextSource.mId); mNextSourceInfos.poll(); SourceInfo nextSourceInfo = mNextSourceInfos.poll(); if (nextSource != null) { nextSourceInfo.close(); } return prepareNextDataSource(); } } Loading @@ -1058,7 +1073,7 @@ public class MediaPlayer2 implements AutoCloseable SourceInfo nextSourceInfo = mNextSourceInfos.peek(); if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) { // Switch to next source only when it has been prepared. mCurrentSourceInfo = mNextSourceInfos.poll(); setCurrentSourceInfo(mNextSourceInfos.poll()); long srcId = mCurrentSourceInfo.mId; try { Loading Loading @@ -4490,6 +4505,7 @@ public class MediaPlayer2 implements AutoCloseable final DataSourceDesc mDSD; final long mId = mSrcIdGenerator.getAndIncrement(); AtomicInteger mBufferedPercentage = new AtomicInteger(0); boolean mClosed = false; // m*AsNextSource (below) only applies to pending data sources in the playlist; // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource} Loading @@ -4501,6 +4517,17 @@ public class MediaPlayer2 implements AutoCloseable this.mDSD = dsd; } void close() { synchronized (this) { if (!mClosed) { if (mDSD != null) { mDSD.close(); } mClosed = true; } } } @Override public String toString() { return String.format("%s(%d)", SourceInfo.class.getName(), mId); Loading Loading @@ -4531,6 +4558,26 @@ public class MediaPlayer2 implements AutoCloseable return nextSourceInfo != null && nextSourceInfo.mId == srcId; } private void setCurrentSourceInfo(SourceInfo newSourceInfo) { synchronized (mSrcLock) { if (mCurrentSourceInfo != null) { mCurrentSourceInfo.close(); } mCurrentSourceInfo = newSourceInfo; } } private void clearNextSourceInfos() { synchronized (mSrcLock) { for (SourceInfo sourceInfo : mNextSourceInfos) { if (sourceInfo != null) { sourceInfo.close(); } } mNextSourceInfos.clear(); } } public static final class MetricsConstants { private MetricsConstants() {} Loading media/java/android/media/UriDataSourceDesc.java +4 −2 Original line number Diff line number Diff line Loading @@ -31,9 +31,11 @@ import java.util.Map; /** * @hide * Structure for data source descriptor. * Structure of data source descriptor for sources using URI. * * Used by {@link MediaPlayer2#setDataSource(UriDataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}. Loading Loading
media/java/android/media/CallbackDataSourceDesc.java +4 −2 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ import android.annotation.NonNull; /** * @hide * Structure for file data source descriptor. * Structure of data source descriptor for sources using callback. * * Used by {@link MediaPlayer2#setDataSource(CallbackDataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}. Loading
media/java/android/media/DataSourceDesc.java +17 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ import android.annotation.NonNull; * @hide * Base class of data source descriptor. * * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use subclasses' builder to change {@link DataSourceDesc}. Loading @@ -30,7 +32,7 @@ import android.annotation.NonNull; */ public class DataSourceDesc { // intentionally less than long.MAX_VALUE public static final long LONG_MAX = 0x7ffffffffffffffL; static final long LONG_MAX = 0x7ffffffffffffffL; // keep consistent with native code public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000; Loading @@ -45,6 +47,19 @@ public class DataSourceDesc { DataSourceDesc() { } /** * Releases the resources held by this {@code DataSourceDesc} object. */ void close() { } // Have to declare protected for finalize() since it is protected // in the base class Object. @Override protected void finalize() throws Throwable { close(); } /** * Return the media Id of data source. * @return the media Id of data source Loading
media/java/android/media/FileDataSourceDesc.java +74 −33 Original line number Diff line number Diff line Loading @@ -17,20 +17,26 @@ package android.media; import android.annotation.NonNull; import android.os.ParcelFileDescriptor; import android.util.Log; import java.io.FileDescriptor; import java.io.IOException; /** * @hide * Structure for data source descriptor. * Structure of data source descriptor for sources using file descriptor. * * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}. * */ public class FileDataSourceDesc extends DataSourceDesc { private static final String TAG = "FileDataSourceDesc"; /** * Used when the length of file descriptor is unknown. * Loading @@ -38,34 +44,61 @@ public class FileDataSourceDesc extends DataSourceDesc { */ public static final long FD_LENGTH_UNKNOWN = LONG_MAX; private FileDescriptor mFD; private ParcelFileDescriptor mPFD; private long mOffset = 0; private long mLength = FD_LENGTH_UNKNOWN; private FileDataSourceDesc() { super(); } /** * Releases the resources held by this {@code FileDataSourceDesc} object. */ @Override void close() { super.close(); closeFD(); } /** * Releases the file descriptor held by this {@code FileDataSourceDesc} object. */ void closeFD() { synchronized (this) { if (mPFD != null) { try { mPFD.close(); } catch (IOException e) { Log.e(TAG, "failed to close pfd: " + e); } mPFD = null; } } } /** * Return the FileDescriptor of this data source. * @return the FileDescriptor of this data source * Return the ParcelFileDescriptor of this data source. * @return the ParcelFileDescriptor of this data source */ public FileDescriptor getFileDescriptor() { return mFD; public ParcelFileDescriptor getParcelFileDescriptor() { return mPFD; } /** * Return the offset associated with the FileDescriptor of this data source. * Return the offset associated with the ParcelFileDescriptor of this data source. * It's meaningful only when it has been set by the {@link Builder}. * @return the offset associated with the FileDescriptor of this data source * @return the offset associated with the ParcelFileDescriptor of this data source */ public long getOffset() { return mOffset; } /** * Return the content length associated with the FileDescriptor of this data source. * Return the content length associated with the ParcelFileDescriptor of this data source. * {@link #FD_LENGTH_UNKNOWN} means same as the length of source content. * @return the content length associated with the FileDescriptor of this data source * @return the content length associated with the ParcelFileDescriptor of this data source */ public long getLength() { return mLength; Loading @@ -78,7 +111,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * * <pre class="prettyprint"> * FileDataSourceDesc newDSD = new FileDataSourceDesc.Builder() * .setDataSource(fd, 0, srcLength) * .setDataSource(pfd, 0, srcLength) * .setStartPosition(1000) * .setEndPosition(15000) * .build(); Loading @@ -86,7 +119,7 @@ public class FileDataSourceDesc extends DataSourceDesc { * </pre> */ public static class Builder extends BuilderBase<Builder> { private FileDescriptor mFD; private ParcelFileDescriptor mPFD; private long mOffset = 0; private long mLength = FD_LENGTH_UNKNOWN; Loading @@ -107,7 +140,7 @@ public class FileDataSourceDesc extends DataSourceDesc { if (dsd == null) { return; // use default } mFD = dsd.mFD; mPFD = dsd.mPFD; mOffset = dsd.mOffset; mLength = dsd.mLength; } Loading @@ -122,7 +155,7 @@ public class FileDataSourceDesc extends DataSourceDesc { public @NonNull FileDataSourceDesc build() { FileDataSourceDesc dsd = new FileDataSourceDesc(); super.build(dsd); dsd.mFD = mFD; dsd.mPFD = mPFD; dsd.mOffset = mOffset; dsd.mLength = mLength; Loading @@ -130,38 +163,46 @@ public class FileDataSourceDesc extends DataSourceDesc { } /** * Sets the data source (FileDescriptor) to use. The FileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility * to close the file descriptor after the source has been used. * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc} * created by this builder is passed to {@link MediaPlayer2} via * {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} or * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)}, MediaPlayer2 will * close the ParcelFileDescriptor. * * @param fd the FileDescriptor for the file to play * @param pfd the ParcelFileDescriptor for the file to play * @return the same Builder instance. * @throws NullPointerException if fd is null. * @throws NullPointerException if pfd is null. */ public @NonNull Builder setDataSource(@NonNull FileDescriptor fd) { Media2Utils.checkArgument(fd != null, "fd cannot be null."); public @NonNull Builder setDataSource(@NonNull ParcelFileDescriptor pfd) { Media2Utils.checkArgument(pfd != null, "pfd cannot be null."); resetDataSource(); mFD = fd; mPFD = pfd; return this; } /** * Sets the data source (FileDescriptor) to use. The FileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility * to close the file descriptor after the source has been used. * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc} * created by this builder is passed to {@link MediaPlayer2} via * {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} or * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)}, MediaPlayer2 will * close the ParcelFileDescriptor. * * Any negative number for offset is treated as 0. * Any negative number for length is treated as maximum length of the data source. * * @param fd the FileDescriptor for the file to play * @param pfd the ParcelFileDescriptor for the file to play * @param offset the offset into the file where the data to be played starts, in bytes * @param length the length in bytes of the data to be played * @return the same Builder instance. * @throws NullPointerException if fd is null. * @throws NullPointerException if pfd is null. */ public @NonNull Builder setDataSource( @NonNull FileDescriptor fd, long offset, long length) { Media2Utils.checkArgument(fd != null, "fd cannot be null."); @NonNull ParcelFileDescriptor pfd, long offset, long length) { Media2Utils.checkArgument(pfd != null, "pfd cannot be null."); if (offset < 0) { offset = 0; } Loading @@ -169,14 +210,14 @@ public class FileDataSourceDesc extends DataSourceDesc { length = FD_LENGTH_UNKNOWN; } resetDataSource(); mFD = fd; mPFD = pfd; mOffset = offset; mLength = length; return this; } private void resetDataSource() { mFD = null; mPFD = null; mOffset = 0; mLength = FD_LENGTH_UNKNOWN; } Loading
media/java/android/media/MediaPlayer2.java +75 −28 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.PowerManager; import android.util.Log; Loading Loading @@ -412,6 +413,9 @@ public class MediaPlayer2 implements AutoCloseable mHandlerThread = null; } setCurrentSourceInfo(null); clearNextSourceInfos(); // Modular DRM clean up mOnDrmConfigHelper = null; synchronized (mDrmEventCbLock) { Loading Loading @@ -457,10 +461,8 @@ public class MediaPlayer2 implements AutoCloseable synchronized (mDrmEventCbLock) { mDrmEventCallbackRecords.clear(); } synchronized (mSrcLock) { mCurrentSourceInfo = null; mNextSourceInfos.clear(); } setCurrentSourceInfo(null); clearNextSourceInfos(); synchronized (mTaskLock) { mPendingTasks.clear(); Loading Loading @@ -685,6 +687,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets the data source as described by a DataSourceDesc. * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsd the descriptor of data source you want to play * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. Loading @@ -696,14 +700,18 @@ public class MediaPlayer2 implements AutoCloseable void process() throws IOException { Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null"); int state = getState(); try { if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) { throw new IllegalStateException("called in wrong state " + state); } synchronized (mSrcLock) { mCurrentSourceInfo = new SourceInfo(dsd); setCurrentSourceInfo(new SourceInfo(dsd)); handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId); } } finally { dsd.close(); } } }); } Loading @@ -711,6 +719,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets a single data source as described by a DataSourceDesc which will be played * after current data source is finished. * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsd the descriptor of data source you want to play after current one * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. Loading @@ -722,7 +732,7 @@ public class MediaPlayer2 implements AutoCloseable void process() { Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null"); synchronized (mSrcLock) { mNextSourceInfos.clear(); clearNextSourceInfos(); mNextSourceInfos.add(new SourceInfo(dsd)); } prepareNextDataSource(); Loading @@ -732,6 +742,8 @@ public class MediaPlayer2 implements AutoCloseable /** * Sets a list of data sources to be played sequentially after current data source is done. * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor} * in the {@link FileDataSourceDesc} will be closed by the player. * * @param dsds the list of data sources you want to play after current one * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. Loading @@ -744,17 +756,15 @@ public class MediaPlayer2 implements AutoCloseable if (dsds == null || dsds.size() == 0) { throw new IllegalArgumentException("data source list cannot be null or empty."); } for (DataSourceDesc dsd : dsds) { if (dsd == null) { throw new IllegalArgumentException( "DataSourceDesc in the source list cannot be null."); } } synchronized (mSrcLock) { mNextSourceInfos.clear(); clearNextSourceInfos(); 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."); } } } prepareNextDataSource(); Loading @@ -771,7 +781,7 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) { @Override void process() { mNextSourceInfos.clear(); clearNextSourceInfos(); } }); } Loading Loading @@ -802,7 +812,7 @@ public class MediaPlayer2 implements AutoCloseable FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd; handleDataSource(isCurrent, srcId, fileDSD.getFileDescriptor(), fileDSD.getParcelFileDescriptor(), fileDSD.getOffset(), fileDSD.getLength(), fileDSD.getStartPosition(), Loading Loading @@ -886,7 +896,7 @@ public class MediaPlayer2 implements AutoCloseable if (afd.getDeclaredLength() < 0) { handleDataSource(isCurrent, srcId, afd.getFileDescriptor(), ParcelFileDescriptor.dup(afd.getFileDescriptor()), 0, DataSourceDesc.LONG_MAX, startPos, Loading @@ -894,7 +904,7 @@ public class MediaPlayer2 implements AutoCloseable } else { handleDataSource(isCurrent, srcId, afd.getFileDescriptor(), ParcelFileDescriptor.dup(afd.getFileDescriptor()), afd.getStartOffset(), afd.getDeclaredLength(), startPos, Loading Loading @@ -960,7 +970,8 @@ public class MediaPlayer2 implements AutoCloseable if (file.exists()) { FileInputStream is = new FileInputStream(file); FileDescriptor fd = is.getFD(); handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX, startPos, endPos); handleDataSource(isCurrent, srcId, ParcelFileDescriptor.dup(fd), 0, DataSourceDesc.LONG_MAX, startPos, endPos); is.close(); } else { throw new IOException("handleDataSource failed."); Loading @@ -984,9 +995,10 @@ public class MediaPlayer2 implements AutoCloseable */ private void handleDataSource( boolean isCurrent, long srcId, FileDescriptor fd, long offset, long length, ParcelFileDescriptor pfd, long offset, long length, long startPos, long endPos) throws IOException { nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length, startPos, endPos); nativeHandleDataSourceFD(isCurrent, srcId, pfd.getFileDescriptor(), offset, length, startPos, endPos); } private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId, Loading Loading @@ -1037,7 +1049,10 @@ public class MediaPlayer2 implements AutoCloseable MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null); mTaskHandler.handleMessage(msg, nextSource.mId); mNextSourceInfos.poll(); SourceInfo nextSourceInfo = mNextSourceInfos.poll(); if (nextSource != null) { nextSourceInfo.close(); } return prepareNextDataSource(); } } Loading @@ -1058,7 +1073,7 @@ public class MediaPlayer2 implements AutoCloseable SourceInfo nextSourceInfo = mNextSourceInfos.peek(); if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) { // Switch to next source only when it has been prepared. mCurrentSourceInfo = mNextSourceInfos.poll(); setCurrentSourceInfo(mNextSourceInfos.poll()); long srcId = mCurrentSourceInfo.mId; try { Loading Loading @@ -4490,6 +4505,7 @@ public class MediaPlayer2 implements AutoCloseable final DataSourceDesc mDSD; final long mId = mSrcIdGenerator.getAndIncrement(); AtomicInteger mBufferedPercentage = new AtomicInteger(0); boolean mClosed = false; // m*AsNextSource (below) only applies to pending data sources in the playlist; // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource} Loading @@ -4501,6 +4517,17 @@ public class MediaPlayer2 implements AutoCloseable this.mDSD = dsd; } void close() { synchronized (this) { if (!mClosed) { if (mDSD != null) { mDSD.close(); } mClosed = true; } } } @Override public String toString() { return String.format("%s(%d)", SourceInfo.class.getName(), mId); Loading Loading @@ -4531,6 +4558,26 @@ public class MediaPlayer2 implements AutoCloseable return nextSourceInfo != null && nextSourceInfo.mId == srcId; } private void setCurrentSourceInfo(SourceInfo newSourceInfo) { synchronized (mSrcLock) { if (mCurrentSourceInfo != null) { mCurrentSourceInfo.close(); } mCurrentSourceInfo = newSourceInfo; } } private void clearNextSourceInfos() { synchronized (mSrcLock) { for (SourceInfo sourceInfo : mNextSourceInfos) { if (sourceInfo != null) { sourceInfo.close(); } } mNextSourceInfos.clear(); } } public static final class MetricsConstants { private MetricsConstants() {} Loading
media/java/android/media/UriDataSourceDesc.java +4 −2 Original line number Diff line number Diff line Loading @@ -31,9 +31,11 @@ import java.util.Map; /** * @hide * Structure for data source descriptor. * Structure of data source descriptor for sources using URI. * * Used by {@link MediaPlayer2#setDataSource(UriDataSourceDesc)} * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}, * {@link MediaPlayer2#setNextDataSource(DataSourceDesc)} and * {@link MediaPlayer2#setNextDataSources(List<DataSourceDesc>)} * to set data source for playback. * * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}. Loading