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

Commit 2e51cefc authored by Marco Nelissen's avatar Marco Nelissen Committed by Gerrit Code Review
Browse files

Merge "Remove MediaPlayer2"

parents f5617abe 845fa764
Loading
Loading
Loading
Loading
+0 −20
Original line number Original line Diff line number Diff line
@@ -61,26 +61,6 @@ filegroup {
    path: "apex/java",
    path: "apex/java",
}
}


filegroup {
    name: "mediaplayer2-srcs",
    srcs: [
        "apex/java/android/media/CloseGuard.java",
        "apex/java/android/media/DataSourceCallback.java",
        "apex/java/android/media/DataSourceDesc.java",
        "apex/java/android/media/UriDataSourceDesc.java",
        "apex/java/android/media/FileDataSourceDesc.java",
        "apex/java/android/media/Media2Utils.java",
        "apex/java/android/media/MediaPlayer2Utils.java",
        "apex/java/android/media/MediaPlayer2.java",
        "apex/java/android/media/Media2HTTPService.java",
        "apex/java/android/media/Media2HTTPConnection.java",
        "apex/java/android/media/RoutingDelegate.java",
        "apex/java/android/media/BufferingParams.java",
        "apex/java/android/media/ProxyDataSourceCallback.java",
    ],
    path: "apex/java",
}

metalava_updatable_media_args = " --error UnhiddenSystemApi " +
metalava_updatable_media_args = " --error UnhiddenSystemApi " +
    "--hide RequiresPermission " +
    "--hide RequiresPermission " +
    "--hide MissingPermission --hide BroadcastBehavior " +
    "--hide MissingPermission --hide BroadcastBehavior " +
+0 −384
Original line number Original line Diff line number Diff line
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Uri;
import android.os.ParcelFileDescriptor;

import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.HttpCookie;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Data source descriptor.
 *
 * Used by {@link MediaPlayer2#setDataSource}, {@link MediaPlayer2#setNextDataSource} and
 * {@link MediaPlayer2#setNextDataSources} to set data source for playback.
 *
 * @hide
 */
public class DataSourceDesc {
    // intentionally less than long.MAX_VALUE
    static final long LONG_MAX = 0x7ffffffffffffffL;

    // keep consistent with native code
    public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000;
    /**
     * @hide
     */
    public static final long LONG_MAX_TIME_US = LONG_MAX_TIME_MS * 1000;

    public static final long POSITION_UNKNOWN = LONG_MAX_TIME_MS;

    private String mMediaId;
    private long mStartPositionMs = 0;
    private long mEndPositionMs = POSITION_UNKNOWN;

    DataSourceDesc(String mediaId, long startPositionMs, long endPositionMs) {
        mMediaId = mediaId;
        mStartPositionMs = startPositionMs;
        mEndPositionMs = endPositionMs;
    }

    /**
     * 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
     */
    public @Nullable String getMediaId() {
        return mMediaId;
    }

    /**
     * Return the position in milliseconds at which the playback will start.
     * @return the position in milliseconds at which the playback will start
     */
    public long getStartPosition() {
        return mStartPositionMs;
    }

    /**
     * Return the position in milliseconds at which the playback will end.
     * {@link #POSITION_UNKNOWN} means ending at the end of source content.
     * @return the position in milliseconds at which the playback will end
     */
    public long getEndPosition() {
        return mEndPositionMs;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("DataSourceDesc{");
        sb.append("mMediaId=").append(mMediaId);
        sb.append(", mStartPositionMs=").append(mStartPositionMs);
        sb.append(", mEndPositionMs=").append(mEndPositionMs);
        sb.append('}');
        return sb.toString();
    }

    /**
     * Builder for {@link DataSourceDesc}.
     * <p>
     * Here is an example where <code>Builder</code> is used to define the
     * {@link DataSourceDesc} to be used by a {@link MediaPlayer2} instance:
     *
     * <pre class="prettyprint">
     * DataSourceDesc newDSD = new DataSourceDesc.Builder()
     *         .setDataSource(context, uri, headers, cookies)
     *         .setStartPosition(1000)
     *         .setEndPosition(15000)
     *         .build();
     * mediaplayer2.setDataSourceDesc(newDSD);
     * </pre>
     */
    public static final class Builder {
        private static final int SOURCE_TYPE_UNKNOWN = 0;
        private static final int SOURCE_TYPE_URI = 1;
        private static final int SOURCE_TYPE_FILE = 2;

        private int mSourceType = SOURCE_TYPE_UNKNOWN;
        private String mMediaId;
        private long mStartPositionMs = 0;
        private long mEndPositionMs = POSITION_UNKNOWN;

        // For UriDataSourceDesc
        private Uri mUri;
        private Map<String, String> mHeader;
        private List<HttpCookie> mCookies;

        // For FileDataSourceDesc
        private ParcelFileDescriptor mPFD;
        private long mOffset = 0;
        private long mLength = FileDataSourceDesc.FD_LENGTH_UNKNOWN;

        /**
         * Constructs a new BuilderBase with the defaults.
         */
        public Builder() {
        }

        /**
         * Constructs a new BuilderBase from a given {@link DataSourceDesc} instance
         * @param dsd the {@link DataSourceDesc} object whose data will be reused
         * in the new BuilderBase.
         */
        public Builder(@Nullable DataSourceDesc dsd) {
            if (dsd == null) {
                return;
            }
            mMediaId = dsd.mMediaId;
            mStartPositionMs = dsd.mStartPositionMs;
            mEndPositionMs = dsd.mEndPositionMs;
            if (dsd instanceof FileDataSourceDesc) {
                mSourceType = SOURCE_TYPE_FILE;
                mPFD = ((FileDataSourceDesc) dsd).getParcelFileDescriptor();
                mOffset = ((FileDataSourceDesc) dsd).getOffset();
                mLength = ((FileDataSourceDesc) dsd).getLength();
            } else if (dsd instanceof UriDataSourceDesc) {
                mSourceType = SOURCE_TYPE_URI;
                mUri = ((UriDataSourceDesc) dsd).getUri();
                mHeader = ((UriDataSourceDesc) dsd).getHeaders();
                mCookies = ((UriDataSourceDesc) dsd).getCookies();
            } else {
                throw new IllegalStateException("Unknown source type:" + mSourceType);
            }
        }

        /**
         * Sets all fields that have been set in the {@link DataSourceDesc} object.
         * <code>IllegalStateException</code> will be thrown if there is conflict between fields.
         *
         * @return {@link DataSourceDesc}
         */
        @NonNull
        public DataSourceDesc build() {
            if (mSourceType == SOURCE_TYPE_UNKNOWN) {
                throw new IllegalStateException("Source is not set.");
            }
            if (mStartPositionMs > mEndPositionMs) {
                throw new IllegalStateException("Illegal start/end position: "
                    + mStartPositionMs + " : " + mEndPositionMs);
            }

            DataSourceDesc desc;
            if (mSourceType == SOURCE_TYPE_FILE) {
                desc = new FileDataSourceDesc(
                        mMediaId, mStartPositionMs, mEndPositionMs, mPFD, mOffset, mLength);
            } else if (mSourceType == SOURCE_TYPE_URI) {
                desc = new UriDataSourceDesc(
                        mMediaId, mStartPositionMs, mEndPositionMs, mUri, mHeader, mCookies);
            } else {
                throw new IllegalStateException("Unknown source type:" + mSourceType);
            }
            return desc;
        }

        /**
         * Sets the media Id of this data source.
         *
         * @param mediaId the media Id of this data source
         * @return the same Builder instance.
         */
        @NonNull
        public Builder setMediaId(@Nullable String mediaId) {
            mMediaId = mediaId;
            return this;
        }

        /**
         * Sets the start position in milliseconds at which the playback will start.
         * Any negative number is treated as 0.
         *
         * @param position the start position in milliseconds at which the playback will start
         * @return the same Builder instance.
         *
         */
        @NonNull
        public Builder setStartPosition(long position) {
            if (position < 0) {
                position = 0;
            }
            mStartPositionMs = position;
            return this;
        }

        /**
         * Sets the end position in milliseconds at which the playback will end.
         * Any negative number is treated as maximum duration {@link #LONG_MAX_TIME_MS}
         * of the data source
         *
         * @param position the end position in milliseconds at which the playback will end
         * @return the same Builder instance.
         */
        @NonNull
        public Builder setEndPosition(long position) {
            if (position < 0) {
                position = LONG_MAX_TIME_MS;
            }
            mEndPositionMs = position;
            return this;
        }

        /**
         * Sets the data source as a content Uri.
         *
         * @param uri the Content URI of the data you want to play
         * @return the same Builder instance.
         * @throws NullPointerException if context or uri is null.
         */
        @NonNull
        public Builder setDataSource(@NonNull Uri uri) {
            setSourceType(SOURCE_TYPE_URI);
            Media2Utils.checkArgument(uri != null, "uri cannot be null");
            mUri = uri;
            return this;
        }

        /**
         * Sets the data source as a content Uri.
         *
         * To provide cookies for the subsequent HTTP requests, you can install your own default
         * cookie handler and use other variants of setDataSource APIs instead. Alternatively, you
         * can use this API to pass the cookies as a list of HttpCookie. If the app has not
         * installed a CookieHandler already, {@link MediaPlayer2} will create a CookieManager
         * and populates its CookieStore with the provided cookies when this data source is passed
         * to {@link MediaPlayer2}. If the app has installed its own handler already, the handler
         * is required to be of CookieManager type such that {@link MediaPlayer2} can update the
         * manager’s CookieStore.
         *
         *  <p><strong>Note</strong> that the cross domain redirection is allowed by default,
         * but that can be changed with key/value pairs through the headers parameter with
         * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
         * disallow or allow cross domain redirection.
         *
         * @param uri the Content URI of the data you want to play
         * @param headers the headers to be sent together with the request for the data
         *                The headers must not include cookies. Instead, use the cookies param.
         * @param cookies the cookies to be sent together with the request
         * @return the same Builder instance.
         * @throws NullPointerException if context or uri is null.
         * @throws IllegalArgumentException if the cookie handler is not of CookieManager type
         *                                  when cookies are provided.
         */
        @NonNull
        public Builder setDataSource(@NonNull Uri uri, @Nullable Map<String, String> headers,
                @Nullable List<HttpCookie> cookies) {
            setSourceType(SOURCE_TYPE_URI);
            Media2Utils.checkArgument(uri != null, "uri cannot be null");
            if (cookies != null) {
                CookieHandler cookieHandler = CookieHandler.getDefault();
                if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
                    throw new IllegalArgumentException(
                            "The cookie handler has to be of CookieManager type "
                                    + "when cookies are provided.");
                }
            }

            mUri = uri;
            if (headers != null) {
                mHeader = new HashMap<String, String>(headers);
            }
            if (cookies != null) {
                mCookies = new ArrayList<HttpCookie>(cookies);
            }
            return this;
        }

        /**
         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
         * seekable (N.B. a LocalSocket is not seekable). When the {@link DataSourceDesc}
         * created by this builder is passed to {@link MediaPlayer2} via
         * {@link MediaPlayer2#setDataSource},
         * {@link MediaPlayer2#setNextDataSource} or
         * {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
         * close the ParcelFileDescriptor.
         *
         * @param pfd the ParcelFileDescriptor for the file to play
         * @return the same Builder instance.
         * @throws NullPointerException if pfd is null.
         */
        @NonNull
        public Builder setDataSource(@NonNull ParcelFileDescriptor pfd) {
            setSourceType(SOURCE_TYPE_FILE);
            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
            mPFD = pfd;
            return this;
        }

        /**
         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
         * seekable (N.B. a LocalSocket is not seekable). When the {@link DataSourceDesc}
         * created by this builder is passed to {@link MediaPlayer2} via
         * {@link MediaPlayer2#setDataSource},
         * {@link MediaPlayer2#setNextDataSource} or
         * {@link MediaPlayer2#setNextDataSources}, 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 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 pfd is null.
         */
        @NonNull
        public Builder setDataSource(
                @NonNull ParcelFileDescriptor pfd, long offset, long length) {
            setSourceType(SOURCE_TYPE_FILE);
            if (pfd == null) {
                throw new NullPointerException("pfd cannot be null.");
            }
            if (offset < 0) {
                offset = 0;
            }
            if (length < 0) {
                length = FileDataSourceDesc.FD_LENGTH_UNKNOWN;
            }
            mPFD = pfd;
            mOffset = offset;
            mLength = length;
            return this;
        }

        private void setSourceType(int type) {
            if (mSourceType != SOURCE_TYPE_UNKNOWN) {
                throw new IllegalStateException("Source is already set. type=" + mSourceType);
            }
            mSourceType = type;
        }
    }
}
+0 −134
Original line number Original line Diff line number Diff line
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

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

import java.io.IOException;

/**
 * Structure of data source descriptor for sources using file descriptor.
 *
 * Used by {@link MediaPlayer2#setDataSource}, {@link MediaPlayer2#setNextDataSource} and
 * {@link MediaPlayer2#setNextDataSources} to set data source for playback.
 *
 * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}.
 * @hide
 */
public class FileDataSourceDesc extends DataSourceDesc {
    private static final String TAG = "FileDataSourceDesc";

    /**
     * Used when the length of file descriptor is unknown.
     *
     * @see #getLength()
     */
    public static final long FD_LENGTH_UNKNOWN = LONG_MAX;

    private ParcelFileDescriptor mPFD;
    private long mOffset = 0;
    private long mLength = FD_LENGTH_UNKNOWN;
    private int mCount = 0;
    private boolean mClosed = false;

    FileDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
            ParcelFileDescriptor pfd, long offset, long length) {
        super(mediaId, startPositionMs, endPositionMs);
        mPFD = pfd;
        mOffset = offset;
        mLength = length;
    }

    /**
     * Releases the resources held by this {@code FileDataSourceDesc} object.
     */
    @Override
    void close() {
        super.close();
        decCount();
    }

    /**
     * Decrements usage count by {@link MediaPlayer2}.
     * If this is the last usage, also releases the file descriptor held by this
     * {@code FileDataSourceDesc} object.
     */
    void decCount() {
        synchronized (this) {
            --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;
        }
    }

    /**
     * Return the ParcelFileDescriptor of this data source.
     * @return the ParcelFileDescriptor of this data source
     */
    public @NonNull ParcelFileDescriptor getParcelFileDescriptor() {
        return mPFD;
    }

    /**
     * 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 ParcelFileDescriptor of this data source
     */
    public long getOffset() {
        return mOffset;
    }

    /**
     * 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 ParcelFileDescriptor of this data source
     */
    public long getLength() {
        return mLength;
    }
}
+0 −385

File deleted.

Preview size limit exceeded, changes collapsed.

+0 −58
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import android.util.Log;

import java.net.HttpCookie;
import java.util.List;

/** @hide */
public class Media2HTTPService {
    private static final String TAG = "Media2HTTPService";
    private List<HttpCookie> mCookies;
    private Boolean mCookieStoreInitialized = new Boolean(false);

    public Media2HTTPService(List<HttpCookie> cookies) {
        mCookies = cookies;
        Log.v(TAG, "Media2HTTPService(" + this + "): Cookies: " + cookies);
    }

    public Media2HTTPConnection makeHTTPConnection() {

        synchronized (mCookieStoreInitialized) {
            Media2Utils.storeCookies(mCookies);
        }

        return new Media2HTTPConnection();
    }

    /* package private */ static Media2HTTPService createHTTPService(String path) {
        return createHTTPService(path, null);
    }

    // when cookies are provided
    static Media2HTTPService createHTTPService(String path, List<HttpCookie> cookies) {
        if (path.startsWith("http://") || path.startsWith("https://")) {
            return (new Media2HTTPService(cookies));
        } else if (path.startsWith("widevine://")) {
            Log.d(TAG, "Widevine classic is no longer supported");
        }

        return null;
    }
}
Loading