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

Commit c14da1ea authored by Wei Jia's avatar Wei Jia
Browse files

MediaPlayer2: allow reusing DataSourceDesc

Test: cts
Bug: 112549021
Change-Id: Ib1c8daddcb04be00b75df3e4928904376a5e16bd
parent e51dab22
Loading
Loading
Loading
Loading
+48 −11
Original line number Diff line number Diff line
@@ -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,24 +57,49 @@ 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) {
            --mCount;
            if (mCount > 0) {
                return;
            }

            try {
                mPFD.close();
                mClosed = true;
            } catch (IOException e) {
                Log.e(TAG, "failed to close pfd: " + e);
            }
        }
    }

                mPFD = null;
    /**
     * 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;
+41 −7
Original line number Diff line number Diff line
@@ -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.");
                        }
                    }
                }
                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}.