Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f0503a4 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "MediaPlayer2: use ParcelFileDescriptor"

parents f912513f da21c3d3
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -20,9 +20,11 @@ import android.annotation.NonNull;


/**
/**
 * @hide
 * @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.
 * to set data source for playback.
 *
 *
 * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}.
 * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}.
+17 −2
Original line number Original line Diff line number Diff line
@@ -22,7 +22,9 @@ import android.annotation.NonNull;
 * @hide
 * @hide
 * Base class of data source descriptor.
 * 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.
 * to set data source for playback.
 *
 *
 * <p>Users should use subclasses' builder to change {@link DataSourceDesc}.
 * <p>Users should use subclasses' builder to change {@link DataSourceDesc}.
@@ -30,7 +32,7 @@ import android.annotation.NonNull;
 */
 */
public class DataSourceDesc {
public class DataSourceDesc {
    // intentionally less than long.MAX_VALUE
    // intentionally less than long.MAX_VALUE
    public static final long LONG_MAX = 0x7ffffffffffffffL;
    static final long LONG_MAX = 0x7ffffffffffffffL;


    // keep consistent with native code
    // keep consistent with native code
    public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000;
    public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000;
@@ -45,6 +47,19 @@ public class DataSourceDesc {
    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.
     * @return the media Id of data source
     * @return the media Id of data source
+74 −33
Original line number Original line Diff line number Diff line
@@ -17,20 +17,26 @@
package android.media;
package android.media;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.os.ParcelFileDescriptor;
import android.util.Log;


import java.io.FileDescriptor;
import java.io.IOException;


/**
/**
 * @hide
 * @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.
 * to set data source for playback.
 *
 *
 * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}.
 * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}.
 *
 *
 */
 */
public class FileDataSourceDesc extends DataSourceDesc {
public class FileDataSourceDesc extends DataSourceDesc {
    private static final String TAG = "FileDataSourceDesc";

    /**
    /**
     * Used when the length of file descriptor is unknown.
     * Used when the length of file descriptor is unknown.
     *
     *
@@ -38,34 +44,61 @@ public class FileDataSourceDesc extends DataSourceDesc {
     */
     */
    public static final long FD_LENGTH_UNKNOWN = LONG_MAX;
    public static final long FD_LENGTH_UNKNOWN = LONG_MAX;


    private FileDescriptor mFD;
    private ParcelFileDescriptor mPFD;
    private long mOffset = 0;
    private long mOffset = 0;
    private long mLength = FD_LENGTH_UNKNOWN;
    private long mLength = FD_LENGTH_UNKNOWN;


    private FileDataSourceDesc() {
    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 ParcelFileDescriptor of this data source.
     * @return the FileDescriptor of this data source
     * @return the ParcelFileDescriptor of this data source
     */
     */
    public FileDescriptor getFileDescriptor() {
    public ParcelFileDescriptor getParcelFileDescriptor() {
        return mFD;
        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}.
     * 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() {
    public long getOffset() {
        return mOffset;
        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.
     * {@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() {
    public long getLength() {
        return mLength;
        return mLength;
@@ -78,7 +111,7 @@ public class FileDataSourceDesc extends DataSourceDesc {
     *
     *
     * <pre class="prettyprint">
     * <pre class="prettyprint">
     * FileDataSourceDesc newDSD = new FileDataSourceDesc.Builder()
     * FileDataSourceDesc newDSD = new FileDataSourceDesc.Builder()
     *         .setDataSource(fd, 0, srcLength)
     *         .setDataSource(pfd, 0, srcLength)
     *         .setStartPosition(1000)
     *         .setStartPosition(1000)
     *         .setEndPosition(15000)
     *         .setEndPosition(15000)
     *         .build();
     *         .build();
@@ -86,7 +119,7 @@ public class FileDataSourceDesc extends DataSourceDesc {
     * </pre>
     * </pre>
     */
     */
    public static class Builder extends BuilderBase<Builder> {
    public static class Builder extends BuilderBase<Builder> {
        private FileDescriptor mFD;
        private ParcelFileDescriptor mPFD;
        private long mOffset = 0;
        private long mOffset = 0;
        private long mLength = FD_LENGTH_UNKNOWN;
        private long mLength = FD_LENGTH_UNKNOWN;


@@ -107,7 +140,7 @@ public class FileDataSourceDesc extends DataSourceDesc {
            if (dsd == null) {
            if (dsd == null) {
                return;  // use default
                return;  // use default
            }
            }
            mFD = dsd.mFD;
            mPFD = dsd.mPFD;
            mOffset = dsd.mOffset;
            mOffset = dsd.mOffset;
            mLength = dsd.mLength;
            mLength = dsd.mLength;
        }
        }
@@ -122,7 +155,7 @@ public class FileDataSourceDesc extends DataSourceDesc {
        public @NonNull FileDataSourceDesc build() {
        public @NonNull FileDataSourceDesc build() {
            FileDataSourceDesc dsd = new FileDataSourceDesc();
            FileDataSourceDesc dsd = new FileDataSourceDesc();
            super.build(dsd);
            super.build(dsd);
            dsd.mFD = mFD;
            dsd.mPFD = mPFD;
            dsd.mOffset = mOffset;
            dsd.mOffset = mOffset;
            dsd.mLength = mLength;
            dsd.mLength = mLength;


@@ -130,38 +163,46 @@ public class FileDataSourceDesc extends DataSourceDesc {
        }
        }


        /**
        /**
         * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
         * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
         * to close the file descriptor after the source has been used.
         * 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.
         * @return the same Builder instance.
         * @throws NullPointerException if fd is null.
         * @throws NullPointerException if pfd is null.
         */
         */
        public @NonNull Builder setDataSource(@NonNull FileDescriptor fd) {
        public @NonNull Builder setDataSource(@NonNull ParcelFileDescriptor pfd) {
            Media2Utils.checkArgument(fd != null, "fd cannot be null.");
            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
            resetDataSource();
            resetDataSource();
            mFD = fd;
            mPFD = pfd;
            return this;
            return this;
        }
        }


        /**
        /**
         * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
         * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
         * to close the file descriptor after the source has been used.
         * 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 offset is treated as 0.
         * Any negative number for length is treated as maximum length of the data source.
         * 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 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
         * @param length the length in bytes of the data to be played
         * @return the same Builder instance.
         * @return the same Builder instance.
         * @throws NullPointerException if fd is null.
         * @throws NullPointerException if pfd is null.
         */
         */
        public @NonNull Builder setDataSource(
        public @NonNull Builder setDataSource(
                @NonNull FileDescriptor fd, long offset, long length) {
                @NonNull ParcelFileDescriptor pfd, long offset, long length) {
            Media2Utils.checkArgument(fd != null, "fd cannot be null.");
            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
            if (offset < 0) {
            if (offset < 0) {
                offset = 0;
                offset = 0;
            }
            }
@@ -169,14 +210,14 @@ public class FileDataSourceDesc extends DataSourceDesc {
                length = FD_LENGTH_UNKNOWN;
                length = FD_LENGTH_UNKNOWN;
            }
            }
            resetDataSource();
            resetDataSource();
            mFD = fd;
            mPFD = pfd;
            mOffset = offset;
            mOffset = offset;
            mLength = length;
            mLength = length;
            return this;
            return this;
        }
        }


        private void resetDataSource() {
        private void resetDataSource() {
            mFD = null;
            mPFD = null;
            mOffset = 0;
            mOffset = 0;
            mLength = FD_LENGTH_UNKNOWN;
            mLength = FD_LENGTH_UNKNOWN;
        }
        }
+75 −28
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.PowerManager;
import android.util.Log;
import android.util.Log;
@@ -412,6 +413,9 @@ public class MediaPlayer2 implements AutoCloseable
            mHandlerThread = null;
            mHandlerThread = null;
        }
        }


        setCurrentSourceInfo(null);
        clearNextSourceInfos();

        // Modular DRM clean up
        // Modular DRM clean up
        mOnDrmConfigHelper = null;
        mOnDrmConfigHelper = null;
        synchronized (mDrmEventCbLock) {
        synchronized (mDrmEventCbLock) {
@@ -457,10 +461,8 @@ public class MediaPlayer2 implements AutoCloseable
        synchronized (mDrmEventCbLock) {
        synchronized (mDrmEventCbLock) {
            mDrmEventCallbackRecords.clear();
            mDrmEventCallbackRecords.clear();
        }
        }
        synchronized (mSrcLock) {
        setCurrentSourceInfo(null);
            mCurrentSourceInfo = null;
        clearNextSourceInfos();
            mNextSourceInfos.clear();
        }


        synchronized (mTaskLock) {
        synchronized (mTaskLock) {
            mPendingTasks.clear();
            mPendingTasks.clear();
@@ -685,6 +687,8 @@ public class MediaPlayer2 implements AutoCloseable


    /**
    /**
     * Sets the data source as described by a DataSourceDesc.
     * 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
     * @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}.
     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
@@ -696,14 +700,18 @@ public class MediaPlayer2 implements AutoCloseable
            void process() throws IOException {
            void process() throws IOException {
                Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
                Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
                int state = getState();
                int state = getState();
                try {
                    if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) {
                    if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) {
                        throw new IllegalStateException("called in wrong state " + state);
                        throw new IllegalStateException("called in wrong state " + state);
                    }
                    }


                    synchronized (mSrcLock) {
                    synchronized (mSrcLock) {
                    mCurrentSourceInfo = new SourceInfo(dsd);
                        setCurrentSourceInfo(new SourceInfo(dsd));
                        handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId);
                        handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId);
                    }
                    }
                } finally {
                    dsd.close();
                }
            }
            }
        });
        });
    }
    }
@@ -711,6 +719,8 @@ public class MediaPlayer2 implements AutoCloseable
    /**
    /**
     * Sets a single data source as described by a DataSourceDesc which will be played
     * Sets a single data source as described by a DataSourceDesc which will be played
     * after current data source is finished.
     * 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
     * @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}.
     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
@@ -722,7 +732,7 @@ public class MediaPlayer2 implements AutoCloseable
            void process() {
            void process() {
                Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
                Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
                synchronized (mSrcLock) {
                synchronized (mSrcLock) {
                    mNextSourceInfos.clear();
                    clearNextSourceInfos();
                    mNextSourceInfos.add(new SourceInfo(dsd));
                    mNextSourceInfos.add(new SourceInfo(dsd));
                }
                }
                prepareNextDataSource();
                prepareNextDataSource();
@@ -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.
     * 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
     * @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}.
     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
@@ -744,17 +756,15 @@ public class MediaPlayer2 implements AutoCloseable
                if (dsds == null || dsds.size() == 0) {
                if (dsds == null || dsds.size() == 0) {
                    throw new IllegalArgumentException("data source list cannot be null or empty.");
                    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) {
                synchronized (mSrcLock) {
                    mNextSourceInfos.clear();
                    clearNextSourceInfos();
                    for (DataSourceDesc dsd : dsds) {
                    for (DataSourceDesc dsd : dsds) {
                        if (dsd != null) {
                            mNextSourceInfos.add(new SourceInfo(dsd));
                            mNextSourceInfos.add(new SourceInfo(dsd));
                        } else {
                            Log.w(TAG, "DataSourceDesc in the source list shall not be null.");
                        }
                    }
                    }
                }
                }
                prepareNextDataSource();
                prepareNextDataSource();
@@ -771,7 +781,7 @@ public class MediaPlayer2 implements AutoCloseable
        return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) {
        return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) {
            @Override
            @Override
            void process() {
            void process() {
                mNextSourceInfos.clear();
                clearNextSourceInfos();
            }
            }
        });
        });
    }
    }
@@ -802,7 +812,7 @@ public class MediaPlayer2 implements AutoCloseable
            FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd;
            FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd;
            handleDataSource(isCurrent,
            handleDataSource(isCurrent,
                             srcId,
                             srcId,
                             fileDSD.getFileDescriptor(),
                             fileDSD.getParcelFileDescriptor(),
                             fileDSD.getOffset(),
                             fileDSD.getOffset(),
                             fileDSD.getLength(),
                             fileDSD.getLength(),
                             fileDSD.getStartPosition(),
                             fileDSD.getStartPosition(),
@@ -886,7 +896,7 @@ public class MediaPlayer2 implements AutoCloseable
            if (afd.getDeclaredLength() < 0) {
            if (afd.getDeclaredLength() < 0) {
                handleDataSource(isCurrent,
                handleDataSource(isCurrent,
                        srcId,
                        srcId,
                        afd.getFileDescriptor(),
                        ParcelFileDescriptor.dup(afd.getFileDescriptor()),
                        0,
                        0,
                        DataSourceDesc.LONG_MAX,
                        DataSourceDesc.LONG_MAX,
                        startPos,
                        startPos,
@@ -894,7 +904,7 @@ public class MediaPlayer2 implements AutoCloseable
            } else {
            } else {
                handleDataSource(isCurrent,
                handleDataSource(isCurrent,
                        srcId,
                        srcId,
                        afd.getFileDescriptor(),
                        ParcelFileDescriptor.dup(afd.getFileDescriptor()),
                        afd.getStartOffset(),
                        afd.getStartOffset(),
                        afd.getDeclaredLength(),
                        afd.getDeclaredLength(),
                        startPos,
                        startPos,
@@ -960,7 +970,8 @@ public class MediaPlayer2 implements AutoCloseable
        if (file.exists()) {
        if (file.exists()) {
            FileInputStream is = new FileInputStream(file);
            FileInputStream is = new FileInputStream(file);
            FileDescriptor fd = is.getFD();
            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();
            is.close();
        } else {
        } else {
            throw new IOException("handleDataSource failed.");
            throw new IOException("handleDataSource failed.");
@@ -984,9 +995,10 @@ public class MediaPlayer2 implements AutoCloseable
     */
     */
    private void handleDataSource(
    private void handleDataSource(
            boolean isCurrent, long srcId,
            boolean isCurrent, long srcId,
            FileDescriptor fd, long offset, long length,
            ParcelFileDescriptor pfd, long offset, long length,
            long startPos, long endPos) throws IOException {
            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,
    private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
@@ -1037,7 +1049,10 @@ public class MediaPlayer2 implements AutoCloseable
                        MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null);
                        MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null);
                mTaskHandler.handleMessage(msg, nextSource.mId);
                mTaskHandler.handleMessage(msg, nextSource.mId);


                mNextSourceInfos.poll();
                SourceInfo nextSourceInfo = mNextSourceInfos.poll();
                if (nextSource != null) {
                    nextSourceInfo.close();
                }
                return prepareNextDataSource();
                return prepareNextDataSource();
            }
            }
        }
        }
@@ -1058,7 +1073,7 @@ public class MediaPlayer2 implements AutoCloseable
                SourceInfo nextSourceInfo = mNextSourceInfos.peek();
                SourceInfo nextSourceInfo = mNextSourceInfos.peek();
                if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) {
                if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) {
                    // Switch to next source only when it has been prepared.
                    // Switch to next source only when it has been prepared.
                    mCurrentSourceInfo = mNextSourceInfos.poll();
                    setCurrentSourceInfo(mNextSourceInfos.poll());


                    long srcId = mCurrentSourceInfo.mId;
                    long srcId = mCurrentSourceInfo.mId;
                    try {
                    try {
@@ -4490,6 +4505,7 @@ public class MediaPlayer2 implements AutoCloseable
        final DataSourceDesc mDSD;
        final DataSourceDesc mDSD;
        final long mId = mSrcIdGenerator.getAndIncrement();
        final long mId = mSrcIdGenerator.getAndIncrement();
        AtomicInteger mBufferedPercentage = new AtomicInteger(0);
        AtomicInteger mBufferedPercentage = new AtomicInteger(0);
        boolean mClosed = false;


        // m*AsNextSource (below) only applies to pending data sources in the playlist;
        // m*AsNextSource (below) only applies to pending data sources in the playlist;
        // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource}
        // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource}
@@ -4501,6 +4517,17 @@ public class MediaPlayer2 implements AutoCloseable
            this.mDSD = dsd;
            this.mDSD = dsd;
        }
        }


        void close() {
            synchronized (this) {
                if (!mClosed) {
                    if (mDSD != null) {
                        mDSD.close();
                    }
                    mClosed = true;
                }
            }
        }

        @Override
        @Override
        public String toString() {
        public String toString() {
            return String.format("%s(%d)", SourceInfo.class.getName(), mId);
            return String.format("%s(%d)", SourceInfo.class.getName(), mId);
@@ -4531,6 +4558,26 @@ public class MediaPlayer2 implements AutoCloseable
        return nextSourceInfo != null && nextSourceInfo.mId == srcId;
        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 {
    public static final class MetricsConstants {
        private MetricsConstants() {}
        private MetricsConstants() {}


+4 −2
Original line number Original line Diff line number Diff line
@@ -31,9 +31,11 @@ import java.util.Map;


/**
/**
 * @hide
 * @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.
 * to set data source for playback.
 *
 *
 * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}.
 * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}.