MediaPlayer2Impl.java revision 1789cc7f8221fd1f682fa08a1aeb1e37c2315887
10a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia/*
20a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * Copyright 2018 The Android Open Source Project
30a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
40a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * Licensed under the Apache License, Version 2.0 (the "License");
50a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * you may not use this file except in compliance with the License.
60a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * You may obtain a copy of the License at
70a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
80a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *      http://www.apache.org/licenses/LICENSE-2.0
90a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * Unless required by applicable law or agreed to in writing, software
110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * distributed under the License is distributed on an "AS IS" BASIS,
120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * See the License for the specific language governing permissions and
140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * limitations under the License.
150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia */
160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiapackage android.media;
180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.annotation.CallbackExecutor;
200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.annotation.NonNull;
210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.annotation.Nullable;
220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.app.ActivityThread;
230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.content.ContentProvider;
240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.content.ContentResolver;
250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.content.Context;
260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.content.res.AssetFileDescriptor;
271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jiaimport android.graphics.SurfaceTexture;
281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jiaimport android.media.SubtitleController.Anchor;
291789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jiaimport android.media.SubtitleTrack.RenderingWidget;
300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.net.Uri;
310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Handler;
320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.HandlerThread;
330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Looper;
340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Message;
350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Parcel;
360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Parcelable;
370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.PersistableBundle;
380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Process;
390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.PowerManager;
400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.SystemProperties;
410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.provider.Settings;
420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.system.ErrnoException;
430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.system.Os;
440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.system.OsConstants;
450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.Log;
460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.Pair;
470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.ArrayMap;
480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.view.Surface;
490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.view.SurfaceHolder;
500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.widget.VideoView;
510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport com.android.internal.annotations.GuardedBy;
530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport com.android.internal.util.Preconditions;
540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport dalvik.system.CloseGuard;
560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport libcore.io.IoBridge;
580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport libcore.io.Streams;
590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.ByteArrayOutputStream;
610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.File;
620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.FileDescriptor;
630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.FileInputStream;
640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.IOException;
650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.InputStream;
660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.lang.Runnable;
670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.lang.ref.WeakReference;
680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.CookieHandler;
690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.CookieManager;
700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.HttpCookie;
710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.HttpURLConnection;
720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.URL;
730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.nio.ByteOrder;
740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.ArrayList;
750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Arrays;
760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.BitSet;
770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Collections;
780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.concurrent.Executor;
790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.HashMap;
800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.List;
810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Map;
820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Scanner;
830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Set;
840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.UUID;
850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Vector;
860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia/**
890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * @hide
900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia */
910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiapublic final class MediaPlayer2Impl extends MediaPlayer2 {
920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    static {
930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        System.loadLibrary("media2_jni");
940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_init();
950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final static String TAG = "MediaPlayer2Impl";
980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private long mNativeContext; // accessed by native methods
1000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private long mNativeSurfaceTexture;  // accessed by native methods
1010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mListenerContext; // accessed by native methods
1020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private SurfaceHolder mSurfaceHolder;
1030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private EventHandler mEventHandler;
1040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private PowerManager.WakeLock mWakeLock = null;
1050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mScreenOnWhilePlaying;
1060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mStayAwake;
1070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
1080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mUsage = -1;
1090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mBypassInterruptionPolicy;
1100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final CloseGuard mGuard = CloseGuard.get();
1110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
112de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private final Object mPlLock = new Object();
1131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private DataSourceDesc mCurrentDSD;
1141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private long mCurrentSrcId = 0;
1150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private List<DataSourceDesc> mPlaylist;
1161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private long mNextSrcId = mCurrentSrcId + 1;
117de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private int mPlNextIndex = -1;
118de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private int mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
119de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private boolean mPlNextSourcePlayPending = false;
1200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM
1220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private UUID mDrmUUID;
1230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mDrmLock = new Object();
1240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private DrmInfoImpl mDrmInfoImpl;
1250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private MediaDrm mDrmObj;
1260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private byte[] mDrmSessionId;
1270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmInfoResolved;
1280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mActiveDrmScheme;
1290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmConfigAllowed;
1300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmProvisioningInProgress;
1310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mPrepareDrmInProgress;
1320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private ProvisioningThread mDrmProvisioningThread;
1330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
1350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Default constructor.
1360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>When done with the MediaPlayer2Impl, you should call  {@link #close()},
1370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to free the resources. If not released, too many MediaPlayer2Impl instances may
1380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * result in an exception.</p>
1390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
1400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaPlayer2Impl() {
1410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Looper looper;
1420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ((looper = Looper.myLooper()) != null) {
1430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(this, looper);
1440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if ((looper = Looper.getMainLooper()) != null) {
1450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(this, looper);
1460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
1470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = null;
1480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
1490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mTimeProvider = new TimeProvider(this);
1510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOpenSubtitleSources = new Vector<InputStream>();
1520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mGuard.open("close");
1530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* Native setup requires a weak reference to our object.
1550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * It's easier to create it here than in C++.
1560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
1570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_setup(new WeakReference<MediaPlayer2Impl>(this));
1580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
1590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
1611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Releases the resources held by this {@code MediaPlayer2} object.
1621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
1631789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * It is considered good practice to call this method when you're
1641789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * done using the MediaPlayer2. In particular, whenever an Activity
1651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * of an application is paused (its onPause() method is called),
1661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * or stopped (its onStop() method is called), this method should be
1671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * invoked to release the MediaPlayer2 object, unless the application
1681789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * has a special need to keep the object around. In addition to
1691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * unnecessary resources (such as memory and instances of codecs)
1701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * being held, failure to call this method immediately if a
1711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * MediaPlayer2 object is no longer needed may also lead to
1721789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * continuous battery consumption for mobile devices, and playback
1731789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * failure for other applications if no multiple instances of the
1741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * same codec are supported on a device. Even if multiple instances
1751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * of the same codec are supported, some performance degradation
1761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * may be expected when unnecessary multiple instances are used
1771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * at the same time.
1781789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
1791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@code close()} may be safely called after a prior {@code close()}.
1801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * This class implements the Java {@code AutoCloseable} interface and
1811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * may be used with try-with-resources.
1821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
1831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
1841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void close() {
1851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        synchronized (mGuard) {
1861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            release();
1871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        }
1881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
189de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
1901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
1911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Starts or resumes playback. If playback had previously been paused,
1921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * playback will continue from where it was paused. If playback had
1931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * been stopped, or never started before, playback will start at the
1941789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * beginning.
1951789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
1961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
1970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
1981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
1991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void play() {
2001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        stayAwake(true);
2011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        _start();
2021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
2030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _start() throws IllegalStateException;
2051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
2061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
2071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Prepares the player for playback, asynchronously.
2081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
2091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * After setting the datasource and the display surface, you need to either
2101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * call prepare(). For streams, you should call prepare(),
2111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * which returns immediately, rather than blocking until enough data has been
2121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * buffered.
2131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
2141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
2150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
2171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public native void prepare();
2180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2201789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Pauses playback. Call play() to resume.
2210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2221789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
2231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized.
2240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
2261789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void pause() {
2271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        stayAwake(false);
2281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        _pause();
2290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
2300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _pause() throws IllegalStateException;
2321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
2330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Tries to play next data source if applicable.
2350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2361789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
2370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
2391789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void skipToNext() {
2401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: switch to next data source and play
2410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
2420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2441789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current playback position.
2450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2461789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the current position in milliseconds
2471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
2481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
2491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public native long getCurrentPosition();
2501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
2511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
2521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the duration of the file.
2530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the duration in milliseconds, if no duration is available
2551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *         (for example, if streaming live content), -1 is returned.
2560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
2581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public native long getDuration();
2590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current buffered media source position received through progressive downloading.
2621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * The received buffering percentage indicates how much of the content has been buffered
2631789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * or played. For example a buffering update of 80 percent when half the content
2641789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * has already been played indicates that the next 30 percent of the
2651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * content to play has been buffered.
2660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the current buffered media source position in milliseconds
2681789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
2691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
2701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public long getBufferedPosition() {
2711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: either get buffered position from native code, or cache BUFFERING_UPDATE
2721789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // number and convert it to buffered position.
2731789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return 0;
2741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
2751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
2761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
2771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current player state.
2780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the current player state, one of the following:
2801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <ul>
2811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #PLAYER_STATE_IDLE}
2821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #PLAYER_STATE_PAUSED}
2831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #PLAYER_STATE_PLAYING}
2841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #PLAYER_STATE_ERROR}
2851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * </ul>
2860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
2870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
2880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
2901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @PlayerState int getPlayerState() {
2911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: use cached state or call native function.
2921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return PLAYER_STATE_IDLE;
2930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
2940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current buffering state of the player.
2971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
2981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * buffered.
2991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the buffering state, one of the following:
3000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <ul>
3011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #BUFFERING_STATE_UNKNOWN}
3021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #BUFFERING_STATE_BUFFERING_AND_PLAYABLE}
3031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #BUFFERING_STATE_BUFFERING_AND_STARVED}
3041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #BUFFERING_STATE_BUFFERING_COMPLETE}
3050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </ul>
3061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
3071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized or has been released.
3080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @BuffState int getBufferingState() {
3111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: use cached state or call native function.
3121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return BUFFERING_STATE_UNKNOWN;
3130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
3140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the audio attributes for this MediaPlayer2.
3171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * See {@link AudioAttributes} for how to build and configure an instance of this class.
3181789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * You must call this method before {@link #prepare()} in order
3191789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * for the audio attributes to become effective thereafter.
3201789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param attributes a non-null set of audio attributes
3211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalArgumentException if the attributes are null or invalid.
3220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setAudioAttributes(@NonNull AudioAttributes attributes) {
3251789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (attributes == null) {
3261789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            final String msg = "Cannot set AudioAttributes to null";
3271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException(msg);
3281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        }
3291789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        mUsage = attributes.getUsage();
3301789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        mBypassInterruptionPolicy = (attributes.getAllFlags()
3311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
3321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Parcel pattributes = Parcel.obtain();
3331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
3341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
3351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        pattributes.recycle();
3361789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
3371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
3381789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
3391789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @NonNull AudioAttributes getAudioAttributes() {
3401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Parcel pattributes = getParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES);
3411789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        AudioAttributes attributes = AudioAttributes.CREATOR.createFromParcel(pattributes);
3421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        pattributes.recycle();
3431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return attributes;
3440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
3450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the data source as described by a DataSourceDesc.
3480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
3490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param dsd the descriptor of data source you want to play
3500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
3510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException if dsd is null
3520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setDataSource(@NonNull DataSourceDesc dsd) {
3550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
356de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        synchronized (mPlLock) {
3571789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            mCurrentDSD = dsd;
3581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            try {
3591789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                handleDataSource(true /* isCurrent */, dsd);
3601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            } catch (IOException e) {
3611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            }
362de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
3630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
3640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets a single data source as described by a DataSourceDesc which will be played
3671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * after current data source is finished.
3680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
3691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param dsd the descriptor of data source you want to play after current one
3701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
3711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws NullPointerException if dsd is null
3720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setNextDataSource(@NonNull DataSourceDesc dsd) {
3751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
3761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
3771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: save dsd in a list
3780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
3790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets a list of data sources to be played sequentially after current data source is done.
3820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
3831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param dsds the list of data sources you want to play after current one
3840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
3851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalArgumentException if dsds is null or empty, or contains null DataSourceDesc
3860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
3891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: save the list.
3901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        /*
3911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (dsds == null || dsds.size() == 0) {
3921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException("data source list cannot be null or empty.");
3930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
3940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        HashSet ids = new HashSet(pl.size());
3950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (DataSourceDesc dsd : pl) {
3960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (dsd == null) {
3971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new IllegalArgumentException("DataSourceDesc in playlist cannot be null.");
3980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
3990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (ids.add(dsd.getId()) == false) {
4001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new IllegalArgumentException("DataSourceDesc Id in playlist should be unique.");
4010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
4020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
4030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (startIndex < 0) {
4050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            startIndex = 0;
4060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (startIndex >= pl.size()) {
4070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            startIndex = pl.size() - 1;
4080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
4090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
410de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        synchronized (mPlLock) {
411de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mPlaylist = Collections.synchronizedList(new ArrayList(pl));
4121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            handleDataSource(true, mPlaylist.get(startIndex));
4131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            // TODO: handle the preparation of next source in the playlist.
414de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            // It should be processed after current source is prepared.
415de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mPlNextIndex = getNextIndex_l();
416de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
4171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        */
4180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
4211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current data source as described by a DataSourceDesc.
4220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
4231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the current DataSourceDesc
4240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
4250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
4261789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @NonNull DataSourceDesc getCurrentDataSource() {
427de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        synchronized (mPlLock) {
4281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            return mCurrentDSD;
4290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
4300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
4331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Configures the player to loop on the current data source.
4341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param loop true if the current data source is meant to loop.
4350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
4360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
4371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void loopCurrent(boolean loop) {
4381789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: set the looping mode, send notification
4391789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        setLooping(loop);
4401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
4410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void setLooping(boolean looping);
4430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4441789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
4451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the playback speed.
4461789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A value of 1.0f is the default playback value.
4471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()}
4481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * before using negative values.<br>
4491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * After changing the playback speed, it is recommended to query the actual speed supported
4501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * by the player, see {@link #getPlaybackSpeed()}.
4511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param speed the desired playback speed
4521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
4531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
4541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setPlaybackSpeed(float speed) {
4551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: send notification
4561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        setPlaybackParams(getPlaybackParams().setSpeed(speed));
4570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
4601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Returns the actual playback speed to be used by the player when playing.
4611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}.
4621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the actual playback speed
4630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
4640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
4651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public float getPlaybackSpeed() {
4661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return getPlaybackParams().getSpeed();
4671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
4680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
4701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Indicates whether reverse playback is supported.
4711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Reverse playback is indicated by negative playback speeds, see
4721789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #setPlaybackSpeed(float)}.
4731789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return true if reverse playback is supported.
4741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
4751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
4761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public boolean isReversePlaybackSupported() {
4771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return false;
4781789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
4790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
4811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the volume of the audio of the media to play, expressed as a linear multiplier
4821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * on the audio samples.
4831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Note that this volume is specific to the player, and is separate from stream volume
4841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * used across the platform.<br>
4851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
4861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
4871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
4881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
4891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
4901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setPlayerVolume(float volume) {
4911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // send notification
4921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        _setVolume(volume, volume);
4930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4951789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _setVolume(float leftVolume, float rightVolume);
4961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
4970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
4981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Returns the current volume of this player to this player.
4991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Note that it does not take into account the associated stream volume.
5001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the player volume.
5010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
5031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public float getPlayerVolume() {
5041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: get real volume
5051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return 1.0f;
5060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
5091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
5100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
5121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public float getMaxPlayerVolume() {
5131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return 1.0f;
5141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
5150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
5171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Adds a callback to be notified of events for this player.
5181789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param e the {@link Executor} to be used for the events.
5191789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param cb the callback to receive the events.
5201789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5221789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void registerPlayerEventCallback(@NonNull Executor e,
5231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            @NonNull PlayerEventCallback cb) {
5241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
525de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
5261789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
5271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Removes a previously registered callback for player events
5281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param cb the callback to remove
5291789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5301789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb) {
5320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
5351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_ERROR = -1;
5361789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_INIT = 0;
5371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_PREPARING = 1;
5381789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_PREPARED = 2;
5391789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
5401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /*
5411789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Update the MediaPlayer2Impl SurfaceTexture.
5421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Call after setting a new display surface.
5431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5441789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _setVideoSurface(Surface surface);
5451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
5461789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /* Do not change these values (starting with INVOKE_ID) without updating
5471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * their counterparts in include/media/mediaplayer2.h!
5481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_GET_TRACK_INFO = 1;
5501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE = 2;
5511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3;
5521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_SELECT_TRACK = 4;
5531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_DESELECT_TRACK = 5;
5541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_SET_VIDEO_SCALE_MODE = 6;
5551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
5561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
5570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
5581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Create a request parcel which can be routed to the native media
5591789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * player using {@link #invoke(Parcel, Parcel)}. The Parcel
5601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * returned has the proper InterfaceToken set. The caller should
5611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * not overwrite that token, i.e it can only append data to the
5621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Parcel.
5630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
5641789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return A parcel suitable to hold a request for the native
5651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * player.
5661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@hide}
5670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
5691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public Parcel newRequest() {
5701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Parcel parcel = Parcel.obtain();
5711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return parcel;
5720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
5751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Invoke a generic method on the native player using opaque
5761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * parcels for the request and reply. Both payloads' format is a
5771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * convention between the java caller and the native player.
5781789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Must be called after setDataSource or setPlaylist to make sure a native player
5791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * exists. On failure, a RuntimeException is thrown.
5800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
5811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param request Parcel with the data for the extension. The
5821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * caller must use {@link #newRequest()} to get one.
5831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
5841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param reply Output parcel with the data returned by the
5851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * native player.
5861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@hide}
5870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
5891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void invoke(Parcel request, Parcel reply) {
5901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        int retcode = native_invoke(request, reply);
5911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        reply.setDataPosition(0);
5921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (retcode != 0) {
5931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new RuntimeException("failure code: " + retcode);
5940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
5950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void notifyWhenCommandLabelReached(Object label) {
5991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: create an entry in command queue
6001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
6011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
6020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the {@link SurfaceHolder} to use for displaying the video
6041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * portion of the media.
6050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Either a surface holder or surface must be set if a display or video sink
6071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * is needed.  Not calling this method or {@link #setSurface(Surface)}
6081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * when playing back a video will result in only the audio track being played.
6091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A null surface holder or surface will result in only the audio track being
6101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * played.
6110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param sh the SurfaceHolder to use for video display
6131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
6141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized or has been released.
6151789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @hide
6160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6181789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setDisplay(SurfaceHolder sh) {
6191789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        mSurfaceHolder = sh;
6201789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Surface surface;
6211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (sh != null) {
6221789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            surface = sh.getSurface();
6231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        } else {
6241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            surface = null;
625de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
6261789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        _setVideoSurface(surface);
6271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        updateSurfaceScreenOn();
6280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the {@link Surface} to be used as the sink for the video portion of
6321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but
6331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * does not support {@link #setScreenOnWhilePlaying(boolean)}.  Setting a
6341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Surface will un-set any Surface or SurfaceHolder that was previously set.
6351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A null surface will result in only the audio track being played.
6360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps
6381789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * returned from {@link SurfaceTexture#getTimestamp()} will have an
6391789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * unspecified zero point.  These timestamps cannot be directly compared
6401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * between different media sources, different instances of the same media
6411789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * source, or multiple runs of the same program.  The timestamp is normally
6421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * monotonically increasing and is unaffected by time-of-day adjustments,
6431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * but it is reset when the position is set.
6440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param surface The {@link Surface} to be used for the video portion of
6461789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * the media.
6471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
6481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized or has been released.
6490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setSurface(Surface surface) {
6521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (mScreenOnWhilePlaying && surface != null) {
6531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
6540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
6551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        mSurfaceHolder = null;
6561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        _setVideoSurface(surface);
6571789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        updateSurfaceScreenOn();
6580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets video scaling mode. To make the target video scaling mode
6621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * effective during playback, this method must be called after
6631789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * data source is set. If not called, the default video
6641789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}.
6650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <p> The supported video scaling modes are:
6671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <ul>
6681789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}
6691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}
6701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * </ul>
6710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6721789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param mode target video scaling mode. Must be one of the supported
6731789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * video scaling modes; otherwise, IllegalArgumentException will be thrown.
6740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT
6761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
6771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @hide
6780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setVideoScalingMode(int mode) {
6811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (!isVideoScalingModeSupported(mode)) {
6821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            final String msg = "Scaling mode " + mode + " is not supported";
6831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException(msg);
6841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        }
6851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Parcel request = Parcel.obtain();
6861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Parcel reply = Parcel.obtain();
6871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        try {
6881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE);
6891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            request.writeInt(mode);
6901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            invoke(request, reply);
6911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        } finally {
6921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            request.recycle();
6931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            reply.recycle();
6940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
695de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    }
6960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
6981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Discards all pending commands.
6991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
7001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
7011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void clearPendingCommands() {
7020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
704de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd)
705de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException {
7060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
7070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (dsd.getType()) {
7090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_CALLBACK:
710de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
7111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                 0,  // TODO: get mapped Id
712de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getMedia2DataSource());
7130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
7140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_FD:
716de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
7171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                 0,  // TODO: get mapped Id
718de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getFileDescriptor(),
719de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getFileDescriptorOffset(),
720de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getFileDescriptorLength());
7210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
7220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_URI:
724de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
7251789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                 0,  // TODO: get mapped Id
726de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUriContext(),
727de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUri(),
728de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUriHeaders(),
729de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUriCookies());
7300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
7310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
7330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
7340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
7350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * To provide cookies for the subsequent HTTP requests, you can install your own default cookie
7390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * handler and use other variants of setDataSource APIs instead. Alternatively, you can use
7400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this API to pass the cookies as a list of HttpCookie. If the app has not installed
7410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a CookieHandler already, this API creates a CookieManager and populates its CookieStore with
7420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the provided cookies. If the app has installed its own handler already, this API requires the
7430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * handler to be of CookieManager type such that the API can update the manager’s CookieStore.
7440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p><strong>Note</strong> that the cross domain redirection is allowed by default,
7460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * but that can be changed with key/value pairs through the headers parameter with
7470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
7480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * disallow or allow cross domain redirection.
7490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if cookies are provided and the installed handler is not
7510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                  a CookieManager
7520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException    if it is called in an invalid state
7530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException     if context or uri is null
7540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException              if uri has a file scheme and an I/O error occurs
7550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
756de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(
757de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
758de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            @NonNull Context context, @NonNull Uri uri,
7590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
7600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
7610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // The context and URI usually belong to the calling user. Get a resolver for that user
7620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // and strip out the userId from the URI if present.
7630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final ContentResolver resolver = context.getContentResolver();
7640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String scheme = uri.getScheme();
7650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
7660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
767de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, uri.getPath(), null, null);
7680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
769de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
770de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
771de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        if (ContentResolver.SCHEME_CONTENT.equals(scheme)
7720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                && Settings.AUTHORITY.equals(authority)) {
7730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Try cached ringtone first since the actual provider may not be
7740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // encryption aware, or it may be stored on CE media storage
7750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int type = RingtoneManager.getDefaultType(uri);
7760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
7770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
778de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            if (attemptDataSource(isCurrent, srcId, resolver, cacheUri)) {
7790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
780de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            }
781de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            if (attemptDataSource(isCurrent, srcId, resolver, actualUri)) {
7820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
7830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
784de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
7850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
7860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Try requested Uri locally first, or fallback to media server
787de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            if (attemptDataSource(isCurrent, srcId, resolver, uri)) {
7880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
7890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
790de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
7910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
7920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
794de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private boolean attemptDataSource(
795de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId, ContentResolver resolver, Uri uri) {
7960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
7970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (afd.getDeclaredLength() < 0) {
798de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
799de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 srcId,
800de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getFileDescriptor(),
801de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 0,
802de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 DataSourceDesc.LONG_MAX);
8030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
804de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
805de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 srcId,
806de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getFileDescriptor(),
807de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getStartOffset(),
808de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getDeclaredLength());
8090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
8100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return true;
8110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (NullPointerException | SecurityException | IOException ex) {
8120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "Couldn't open " + uri + ": " + ex);
8130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return false;
8140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
817de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(
818de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
819de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            String path, Map<String, String> headers, List<HttpCookie> cookies)
820de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException {
8210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String[] keys = null;
8220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String[] values = null;
8230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (headers != null) {
8250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            keys = new String[headers.size()];
8260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            values = new String[headers.size()];
8270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
8290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (Map.Entry<String, String> entry: headers.entrySet()) {
8300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                keys[i] = entry.getKey();
8310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                values[i] = entry.getValue();
8320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                ++i;
8330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
8340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
835de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        handleDataSource(isCurrent, srcId, path, keys, values, cookies);
8360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
838de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(boolean isCurrent, long srcId,
839de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            String path, String[] keys, String[] values, List<HttpCookie> cookies)
840de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException {
8410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final Uri uri = Uri.parse(path);
8420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String scheme = uri.getScheme();
8430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ("file".equals(scheme)) {
8440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            path = uri.getPath();
8450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (scheme != null) {
8460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // handle non-file sources
847de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            nativeHandleDataSourceUrl(
848de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                isCurrent,
84934c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                srcId,
8500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Media2HTTPService.createHTTPService(path, cookies),
8510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                path,
8520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                keys,
8530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                values);
8540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
8550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final File file = new File(path);
8580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (file.exists()) {
8590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileInputStream is = new FileInputStream(file);
8600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileDescriptor fd = is.getFD();
861de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX);
8620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            is.close();
8630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
864de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throw new IOException("handleDataSource failed.");
8650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
868de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativeHandleDataSourceUrl(
869de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
870de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            Media2HTTPService httpService, String path, String[] keys, String[] values)
871de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException;
8720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
8740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
8750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
8760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to close the file descriptor. It is safe to do so as soon as this call returns.
8770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
8780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
8790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if fd is not a valid FileDescriptor
8800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if fd can not be read
8810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
882de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(
883de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
884de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            FileDescriptor fd, long offset, long length) throws IOException {
885de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length);
8860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
888de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
889de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            FileDescriptor fd, long offset, long length) throws IOException;
8900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
8920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
8930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
8940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
895de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource) {
896de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        nativeHandleDataSourceCallback(isCurrent, srcId, dataSource);
8970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
899de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativeHandleDataSourceCallback(
900de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId, Media2DataSource dataSource);
9010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
902de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    // This function shall be called with |mPlLock| acquired.
903de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void prepareNextDataSource_l() {
904de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        if (mPlNextIndex < 0 || mPlNextSourceState != NEXT_SOURCE_STATE_INIT) {
905de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            // There is no next source or it's in preparing or prepared state.
906de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            return;
907de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
9080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
909de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        try {
910de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mPlNextSourceState = NEXT_SOURCE_STATE_PREPARING;
9111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            handleDataSource(false /* isCurrent */, mPlaylist.get(0));
912de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        } catch (Exception e) {
913de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            Message msg2 = mEventHandler.obtainMessage(
914de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
9151789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            final long nextSrcId = mNextSrcId;
916de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mEventHandler.post(new Runnable() {
917de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                @Override
918de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                public void run() {
919de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    mEventHandler.handleMessage(msg2, nextSrcId);
920de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                }
921de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            });
922de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
923de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    }
924de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
925de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    // This function shall be called with |mPlLock| acquired.
926de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void playNextDataSource_l() {
927de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        if (mPlNextIndex < 0) {
928de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            return;
929de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
930de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
931de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        if (mPlNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
932de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            // Switch to next source only when it's in prepared state.
9331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            mCurrentSrcId = mNextSrcId;
9341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            mNextSrcId = 0; // TODO; fix it
935de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
936de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mPlNextSourcePlayPending = false;
937de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
9381789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            long srcId = mCurrentSrcId;
939de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            try {
940de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                nativePlayNextDataSource(srcId);
941de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            } catch (Exception e) {
942de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                Message msg2 = mEventHandler.obtainMessage(
943de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
944de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                mEventHandler.post(new Runnable() {
945de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    @Override
946de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    public void run() {
947de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        mEventHandler.handleMessage(msg2, srcId);
948de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    }
949de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                });
950de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            }
951de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
952de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            // Wait for MEDIA2_INFO_STARTED_AS_NEXT to prepare next source.
953de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        } else {
954de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            if (mPlNextSourceState == NEXT_SOURCE_STATE_INIT) {
955de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                prepareNextDataSource_l();
956de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            }
957de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mPlNextSourcePlayPending = true;
9580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
961de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativePlayNextDataSource(long srcId);
9620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int getAudioStreamType() {
9650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
9660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mStreamType = _getAudioStreamType();
9670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mStreamType;
9690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native int _getAudioStreamType() throws IllegalStateException;
9720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Stops playback after playback has been started or paused.
9750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
9770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
9780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #hide
9790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
9800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
9810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void stop() {
9820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
9830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _stop();
9840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _stop() throws IllegalStateException;
9870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //--------------------------------------------------------------------------
9890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Explicit Routing
9900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //--------------------
9910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private AudioDeviceInfo mPreferredDevice = null;
9920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
9950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the output from this MediaPlayer2.
9960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
9970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  If deviceInfo is null, default routing is restored.
9980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
9990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * does not correspond to a valid audio device.
10000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
10020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
10030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (deviceInfo != null && !deviceInfo.isSink()) {
10040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return false;
10050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
10070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean status = native_setOutputDevice(preferredDeviceId);
10080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (status == true) {
10090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
10100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPreferredDevice = deviceInfo;
10110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
10120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return status;
10140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
10180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is not guaranteed to correspond to the actual device being used for playback.
10190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
10210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public AudioDeviceInfo getPreferredDevice() {
10220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (this) {
10230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mPreferredDevice;
10240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2
10290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note: The query is only valid if the MediaPlayer2 is currently playing.
10300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the player is not playing, the returned device can be null or correspond to previously
10310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * selected device when the player was last active.
10320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
10340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public AudioDeviceInfo getRoutedDevice() {
10350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int deviceId = native_getRoutedDeviceId();
10360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (deviceId == 0) {
10370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
10380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        AudioDeviceInfo[] devices =
10400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
10410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (int i = 0; i < devices.length; i++) {
10420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (devices[i].getId() == deviceId) {
10430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return devices[i];
10440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
10450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return null;
10470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
10500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
10510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
105257d03914a1d5680cfe0727c15a3a82e4dfeb0adeAndreas Gampe    @GuardedBy("mRoutingChangeListeners")
10530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void enableNativeRoutingCallbacksLocked(boolean enabled) {
10540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mRoutingChangeListeners.size() == 0) {
10550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            native_enableDeviceCallback(enabled);
10560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
10610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
10620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * by an app to receive (re)routing notifications.
10630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @GuardedBy("mRoutingChangeListeners")
10650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private ArrayMap<AudioRouting.OnRoutingChangedListener,
10660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
10670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
10700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * changes on this MediaPlayer2.
10710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
10720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notifications of rerouting events.
10730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
10740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the callback. If <code>null</code>, the handler on the main looper will be used.
10750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
10770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
10780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Handler handler) {
10790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mRoutingChangeListeners) {
10800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
10810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                enableNativeRoutingCallbacksLocked(true);
10820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRoutingChangeListeners.put(
10830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        listener, new NativeRoutingEventHandlerDelegate(this, listener,
10840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                handler != null ? handler : mEventHandler));
10850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
10860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
10910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to receive rerouting notifications.
10920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
10930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to remove.
10940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
10960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
10970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mRoutingChangeListeners) {
10980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mRoutingChangeListeners.containsKey(listener)) {
10990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRoutingChangeListeners.remove(listener);
11000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                enableNativeRoutingCallbacksLocked(false);
11010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final boolean native_setOutputDevice(int deviceId);
11060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_getRoutedDeviceId();
11070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_enableDeviceCallback(boolean enabled);
11080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set the low-level power management behavior for this MediaPlayer2.  This
11110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
11120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
11130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
11140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
11150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>This function has the MediaPlayer2 access the low-level power manager
11160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * service to control the device's power usage while playing is occurring.
11170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The parameter is a combination of {@link android.os.PowerManager} wake flags.
11180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
11190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * permission.
11200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * By default, no attempt is made to keep the device awake during playback.
11210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
11220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param context the Context to use
11230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode    the power/wake mode to set
11240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.os.PowerManager
11250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
11260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
11280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setWakeMode(Context context, int mode) {
11290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean washeld = false;
11300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* Disable persistant wakelocks in media player based on property */
11320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (SystemProperties.getBoolean("audio.offload.ignore_setawake", false) == true) {
11330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "IGNORING setWakeMode " + mode);
11340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
11350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mWakeLock != null) {
11380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mWakeLock.isHeld()) {
11390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                washeld = true;
11400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.release();
11410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mWakeLock = null;
11430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
11460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer2Impl.class.getName());
11470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mWakeLock.setReferenceCounted(false);
11480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (washeld) {
11490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mWakeLock.acquire();
11500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Control whether we should use the attached SurfaceHolder to keep the
11550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * screen on while video playback is occurring.  This is the preferred
11560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * method over {@link #setWakeMode} where possible, since it doesn't
11570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * require that the application have permission for low-level wake lock
11580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * access.
11590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
11600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param screenOn Supply true to keep the screen on, false to allow it
11610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to turn off.
11620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
11630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
11650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setScreenOnWhilePlaying(boolean screenOn) {
11660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mScreenOnWhilePlaying != screenOn) {
11670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (screenOn && mSurfaceHolder == null) {
11680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
11690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mScreenOnWhilePlaying = screenOn;
11710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            updateSurfaceScreenOn();
11720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void stayAwake(boolean awake) {
11760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mWakeLock != null) {
11770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (awake && !mWakeLock.isHeld()) {
11780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.acquire();
11790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else if (!awake && mWakeLock.isHeld()) {
11800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.release();
11810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mStayAwake = awake;
11840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
11850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void updateSurfaceScreenOn() {
11880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSurfaceHolder != null) {
11890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
11900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the width of the video.
11950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
11960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the width of the video, or 0 if there is no video,
11970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * no display surface was set, or the width has not been determined
11981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * yet. The {@code MediaPlayer2EventCallback} can be registered via
11991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
12001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the width
12011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * is available.
12020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getVideoWidth();
12050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the height of the video.
12080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the height of the video, or 0 if there is no video,
12100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * no display surface was set, or the height has not been determined
12111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * yet. The {@code MediaPlayer2EventCallback} can be registered via
12121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
12131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the height
12141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * is available.
12150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getVideoHeight();
12180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Return Metrics data about the current player.
12210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return a {@link PersistableBundle} containing the set of attributes and values
12230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * available for the media being handled by this instance of MediaPlayer2
12240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The attributes are descibed in {@link MetricsConstants}.
12250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  Additional vendor-specific fields may also be present in
12270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  the return value.
12280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public PersistableBundle getMetrics() {
12310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PersistableBundle bundle = native_getMetrics();
12320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return bundle;
12330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native PersistableBundle native_getMetrics();
12360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Checks whether the MediaPlayer2 is playing.
12390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if currently playing, false otherwise
12410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
12420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
12431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @hide
12440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native boolean isPlaying();
12470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current MediaPlayer2 state.
12501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
12511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the current MediaPlayer2 state, one of the following:
12521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <ul>
12531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #MEDIAPLAYER2_STATE_IDLE}
12541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #MEDIAPLAYER2_STATE_PREPARED}
12551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #MEDIAPLAYER2_STATE_PAUSED}
12561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #MEDIAPLAYER2_STATE_PLAYING}
12571789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li>{@link #MEDIAPLAYER2_STATE_ERROR}
12581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * </ul>
12591789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
12601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized or has been released.
12611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
12621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
12631789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @MediaPlayer2State int getMediaPlayer2State() {
12641789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: get state from native layer or cached value.
12651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return MEDIAPLAYER2_STATE_IDLE;
12661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
12671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
12681789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
12690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the current buffering management params used by the source component.
12700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Calling it only after {@code setDataSource} has been called.
12710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Each type of data source might have different set of default params.
12720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the current buffering management params used by the source component.
12740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
12750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized, or {@code setDataSource} has not been called.
12760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
12770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
12800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native BufferingParams getBufferingParams();
12810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets buffering management params.
12840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The object sets its internal BufferingParams to the input, except that the input is
12850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * invalid or not supported.
12860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Call it only after {@code setDataSource} has been called.
12870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The input is a hint to MediaPlayer2.
12880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the buffering management params.
12900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
12920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released, or {@code setDataSource} has not been called.
12930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params is invalid or not supported.
12940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
12950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setBufferingParams(@NonNull BufferingParams params);
12980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets playback rate and audio mode.
13010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param rate the ratio between desired playback rate and normal one.
13030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param audioMode audio playback mode. Must be one of the supported
13040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * audio modes.
13050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
13080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if audioMode is not supported.
13090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
13110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
13140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public PlaybackParams easyPlaybackParams(float rate, @PlaybackRateAudioMode int audioMode) {
13150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PlaybackParams params = new PlaybackParams();
13160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        params.allowDefaults();
13170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (audioMode) {
13180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_DEFAULT:
13190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(1.0f);
13200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
13210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_STRETCH:
13220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(1.0f)
13230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    .setAudioFallbackMode(params.AUDIO_FALLBACK_MODE_FAIL);
13240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
13250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE:
13260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(rate);
13270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
13280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        default:
13290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Audio playback mode " + audioMode + " is not supported";
13300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
13310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return params;
13330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets playback rate using {@link PlaybackParams}. The object sets its internal
13370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * PlaybackParams to the input, except that the object remembers previous speed
13380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when input speed is zero. This allows the object to resume at previous speed
13390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when play() is called. Calling it before the object is prepared does not change
13400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the object state. After the object is prepared, calling it with zero speed is
13410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * equivalent to calling pause(). After the object is prepared, calling it with
13420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * non-zero speed is equivalent to calling play().
13430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the playback params.
13450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
13480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params is not supported.
13490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setPlaybackParams(@NonNull PlaybackParams params);
13520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the playback params, containing the current playback rate.
13550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the playback params.
13570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
13590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
13620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native PlaybackParams getPlaybackParams();
13630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets A/V sync mode.
13660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the A/V sync params to apply
13680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
13710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params are not supported.
13720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setSyncParams(@NonNull SyncParams params);
13750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the A/V sync mode.
13780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the A/V sync params
13800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
13830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
13860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native SyncParams getSyncParams();
13870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Moves the media to specified time position by considering the given mode.
13900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
13910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When seekTo is finished, the user will be notified via OnSeekComplete supplied by the user.
13920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * There is at most one active seekTo processed at any time. If there is a to-be-completed
13930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * seekTo, new seekTo requests will be queued in such a way that only the last request
13940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is kept. When current seekTo is completed, the queued request will be processed if
13950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that request is different from just-finished seekTo operation, i.e., the requested
13960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * position or mode is different.
13970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param msec the offset in milliseconds from the start to seek to.
13990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When seeking to the given time position, there is no guarantee that the data source
14000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * has a frame located at the position. When this happens, a frame nearby will be rendered.
14010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If msec is negative, time position zero will be used.
14020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If msec is larger than duration, duration will be used.
14030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode the mode indicating where exactly to seek to.
14040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame
14050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp earlier than or the same as msec. Use
14060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame
14070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp later than or the same as msec. Use
14080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame
14090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp closest to or the same as msec. Use
14100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may
14110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * or may not be a sync frame but is closest to or the same as msec.
14120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST} often has larger performance overhead compared
14130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to the other options if there is no sync frame located at msec.
14140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
14150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized
14160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mode is invalid.
14170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void seekTo(long msec, @SeekMode int mode) {
14200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
14210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Illegal seek mode: " + mode;
14220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
14230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: pass long to native, instead of truncating here.
14250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (msec > Integer.MAX_VALUE) {
14260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "seekTo offset " + msec + " is too large, cap to " + Integer.MAX_VALUE);
14270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            msec = Integer.MAX_VALUE;
14280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (msec < Integer.MIN_VALUE) {
14290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "seekTo offset " + msec + " is too small, cap to " + Integer.MIN_VALUE);
14300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            msec = Integer.MIN_VALUE;
14310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _seekTo(msec, mode);
14330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
14340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native final void _seekTo(long msec, int mode);
14361789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
14370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Get current playback position as a {@link MediaTimestamp}.
14390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
14400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The MediaTimestamp represents how the media time correlates to the system time in
14410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a linear fashion using an anchor and a clock rate. During regular playback, the media
14420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * time moves fairly constantly (though the anchor frame may be rebased to a current
14430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * system time, the linear correlation stays steady). Therefore, this method does not
14440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * need to be called often.
14450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
14460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * To help users get current playback position, this method always anchors the timestamp
14470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to the current {@link System#nanoTime system time}, so
14480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
14490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
14510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *         is available, e.g. because the media player has not been initialized.
14520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see MediaTimestamp
14540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Nullable
14570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaTimestamp getTimestamp()
14580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
14590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
14600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // TODO: get the timestamp from native side
14610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new MediaTimestamp(
14620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    getCurrentPosition() * 1000L,
14630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    System.nanoTime(),
14640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    isPlaying() ? getPlaybackParams().getSpeed() : 0.f);
14650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (IllegalStateException e) {
14660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
14670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
14690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the media metadata.
14720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param update_only controls whether the full set of available
14740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * metadata is returned or just the set that changed since the
14750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
14760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #METADATA_ALL}.
14770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param apply_filter if true only metadata that matches the
14790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
14800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #BYPASS_METADATA_FILTER}.
14810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The metadata, possibly empty. null if an error occured.
14830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     // FIXME: unhide.
14840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
14850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public Metadata getMetadata(final boolean update_only,
14880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                final boolean apply_filter) {
14890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
14900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Metadata data = new Metadata();
14910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!native_getMetadata(update_only, apply_filter, reply)) {
14930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
14940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
14950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Metadata takes over the parcel, don't recycle it unless
14980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // there is an error.
14990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!data.parse(reply)) {
15000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
15010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
15020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return data;
15040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set a filter for the metadata update notification and update
15080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * retrieval. The caller provides 2 set of metadata keys, allowed
15090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and blocked. The blocked set always takes precedence over the
15100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * allowed one.
15110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
15120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * shorthands to allow/block all or no metadata.
15130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * By default, there is no filter set.
15150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param allow Is the set of metadata the client is interested
15170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *              in receiving new notifications for.
15180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param block Is the set of metadata the client is not interested
15190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *              in receiving new notifications for.
15200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The call status code.
15210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     // FIXME: unhide.
15230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
15240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
15270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Do our serialization manually instead of calling
15280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Parcel.writeArray since the sets are made of the same type
15290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // we avoid paying the price of calling writeValue (used by
15300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // writeArray) which burns an extra int per element to encode
15310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the type.
15320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request =  newRequest();
15330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // The parcel starts already with an interface token. There
15350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // are 2 filters. Each one starts with a 4bytes number to
15360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // store the len followed by a number of int (4 bytes as well)
15370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // representing the metadata type.
15380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
15390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (request.dataCapacity() < capacity) {
15410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.setDataCapacity(capacity);
15420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        request.writeInt(allow.size());
15450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for(Integer t: allow) {
15460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(t);
15470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        request.writeInt(block.size());
15490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for(Integer t: block) {
15500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(t);
15510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return native_setMetadataFilter(request);
15530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Resets the MediaPlayer2 to its uninitialized state. After calling
15570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method, you will have to initialize it again by setting the
15581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * data source and calling prepare().
15590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void reset() {
15620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSelectedSubtitleTrackIndex = -1;
15630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized(mOpenSubtitleSources) {
15640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (final InputStream is: mOpenSubtitleSources) {
15650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
15660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    is.close();
15670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (IOException e) {
15680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
15690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
15700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mOpenSubtitleSources.clear();
15710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null) {
15730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.reset();
15740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider != null) {
15760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider.close();
15770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = null;
15780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
158063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        synchronized (mEventCbLock) {
158163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.clear();
158263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        }
158363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        synchronized (mDrmEventCbLock) {
158463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.clear();
158563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        }
158663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
15870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
15880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _reset();
15890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // make sure none of the listeners get called anymore
15900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mEventHandler != null) {
15910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeCallbacksAndMessages(null);
15920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
15950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mIndexTrackPairs.clear();
15960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mInbandTrackIndices.clear();
15970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        };
15980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        resetDrmState();
16000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
16010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _reset();
16030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
16060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notified when the presentation time reaches (becomes greater than or equal to)
16070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the value specified.
16080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mediaTimeUs presentation time to get timed event callback at
16100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
16110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void notifyAt(long mediaTimeUs) {
16140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _notifyAt(mediaTimeUs);
16150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
16160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _notifyAt(long mediaTimeUs);
16180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Keep KEY_PARAMETER_* in sync with include/media/mediaplayer2.h
16200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
16210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the parameter indicated by key.
16230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param key key indicates the parameter to be set.
16240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param value value of the parameter to be set.
16250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if the parameter is set successfully, false otherwise
16260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native boolean setParameter(int key, Parcel value);
16280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1629128875996598b9cfa91bad137d3a73dfcb4a2aedWei Jia    private native Parcel getParameter(int key);
1630128875996598b9cfa91bad137d3a73dfcb4a2aedWei Jia
16310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Checks whether the MediaPlayer2 is looping or non-looping.
16340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if the MediaPlayer2 is currently looping, false otherwise
16360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
16370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native boolean isLooping();
16400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the audio session ID.
16430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param sessionId the audio session ID.
16450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The audio session ID is a system wide unique identifier for the audio stream played by
16460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this MediaPlayer2 instance.
16470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The primary use of the audio session ID  is to associate audio effects to a particular
16480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * instance of MediaPlayer2: if an audio session ID is provided when creating an audio effect,
16490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this effect will be applied only to the audio content of media players within the same
16500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * audio session and not to the output mix.
16510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When created, a MediaPlayer2 instance automatically generates its own audio session ID.
16520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * However, it is possible to force this player to be part of an already existing audio session
16530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * by calling this method.
16540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This method must be called before one of the overloaded <code> setDataSource </code> methods.
16550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
16560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the sessionId is invalid.
16570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setAudioSessionId(int sessionId);
16600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the audio session ID.
16630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the audio session ID. {@see #setAudioSessionId(int)}
16650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was contructed.
16660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getAudioSessionId();
16690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Attaches an auxiliary effect to the player. A typical auxiliary effect is a reverberation
16720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * effect which can be applied on any sound source that directs a certain amount of its
16730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * energy to this effect. This amount is defined by setAuxEffectSendLevel().
16740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * See {@link #setAuxEffectSendLevel(float)}.
16750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>After creating an auxiliary effect (e.g.
16760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with
16770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling this method
16780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to attach the player to the effect.
16790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>To detach the effect from the player, call this method with a null effect id.
16800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>This method must be called after one of the overloaded <code> setDataSource </code>
16810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * methods.
16820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param effectId system wide unique id of the effect to attach
16830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void attachAuxEffect(int effectId);
16860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the send level of the player to the attached auxiliary effect.
16890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
16900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>By default the send level is 0, so even if an effect is attached to the player
16910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method must be called for the effect to be applied.
16920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
16930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
16940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * so an appropriate conversion from linear UI input x to level is:
16950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * x == 0 -> level = 0
16960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
16970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param level send level scalar
16980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
17000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setAuxEffectSendLevel(float level) {
17010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _setAuxEffectSendLevel(level);
17020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
17030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _setAuxEffectSendLevel(float level);
17050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
17070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param request Parcel destinated to the media player.
17080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param reply[out] Parcel that will contain the reply.
17090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
17100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_invoke(Parcel request, Parcel reply);
17120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
17150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param update_only If true fetch only the set of metadata that have
17160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    changed since the last invocation of getMetadata.
17170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    The set is built using the unfiltered
17180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    notifications the native player sent to the
17190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    MediaPlayer2Manager during that period of
17200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    time. If false, all the metadatas are considered.
17210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param apply_filter  If true, once the metadata set has been built based on
17220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                     the value update_only, the current filter is applied.
17230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param reply[out] On return contains the serialized
17240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                   metadata. Valid only if the call was successful.
17250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
17260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final boolean native_getMetadata(boolean update_only,
17280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                    boolean apply_filter,
17290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                    Parcel reply);
17300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
17320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param request Parcel with the 2 serialized lists of allowed
17330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                metadata types followed by the one to be
17340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                dropped. Each list starts with an integer
17350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                indicating the number of metadata type elements.
17360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
17370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_setMetadataFilter(Parcel request);
17390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static native final void native_init();
17410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_setup(Object mediaplayer2_this);
17420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_finalize();
17430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17448e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onTearDown(
17458e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long nativeCallbackPtr, long userDataPtr);
17468e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onStreamPresentationEnd(
17478e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long nativeCallbackPtr, long userDataPtr);
17488e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onStreamDataRequest(
17498e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr);
17508e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
17510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Class for MediaPlayer2 to return each audio/video/subtitle track's metadata.
17530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
17550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class TrackInfoImpl extends TrackInfo {
17570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
17580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the track type.
17590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @return TrackType which indicates if the track is video, audio, timed text.
17600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
17610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
17620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public int getTrackType() {
17630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mTrackType;
17640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
17670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the language code of the track.
17680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @return a language code in either way of ISO-639-1 or ISO-639-2.
17690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * When the language is unknown or could not be determined,
17700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * ISO-639-2 language code, "und", is returned.
17710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
17720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
17730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public String getLanguage() {
17740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String language = mFormat.getString(MediaFormat.KEY_LANGUAGE);
17750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return language == null ? "und" : language;
17760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
17790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the {@link MediaFormat} of the track.  If the format is
17800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * unknown or could not be determined, null is returned.
17810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
17820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
17830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public MediaFormat getFormat() {
17840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
17850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
17860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return mFormat;
17870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
17880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
17890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final int mTrackType;
17920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat mFormat;
17930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl(Parcel in) {
17950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTrackType = in.readInt();
17960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat
17970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // even for audio/video tracks, meaning we only set the mime and language.
17980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String mime = in.readString();
17990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String language = in.readString();
18000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mFormat = MediaFormat.createSubtitleFormat(mime, language);
18010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
18030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
18040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
18050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
18060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
18070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
18100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl(int type, MediaFormat format) {
18110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTrackType = type;
18120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mFormat = format;
18130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
18160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Flatten this object in to a Parcel.
18170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         *
18180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @param dest The Parcel in which the object should be written.
18190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @param flags Additional flags about how the object should be written.
18200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * May be 0 or {@link android.os.Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
18210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
18220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* package private */ void writeToParcel(Parcel dest, int flags) {
18230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dest.writeInt(mTrackType);
18240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dest.writeString(getLanguage());
18250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
18270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
18280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
18290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
18300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
18310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
18320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
18350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public String toString() {
18360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            StringBuilder out = new StringBuilder(128);
18370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append(getClass().getName());
18380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append('{');
18390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            switch (mTrackType) {
18400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_VIDEO:
18410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("VIDEO");
18420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
18430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_AUDIO:
18440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("AUDIO");
18450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
18460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_TIMEDTEXT:
18470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("TIMEDTEXT");
18480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
18490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_SUBTITLE:
18500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("SUBTITLE");
18510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
18520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
18530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("UNKNOWN");
18540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
18550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
18560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append(", " + mFormat.toString());
18570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append("}");
18580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return out.toString();
18590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
18620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Used to read a TrackInfoImpl from a Parcel.
18630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
18640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* package private */ static final Parcelable.Creator<TrackInfoImpl> CREATOR
18650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                = new Parcelable.Creator<TrackInfoImpl>() {
18660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
18670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public TrackInfoImpl createFromParcel(Parcel in) {
18680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return new TrackInfoImpl(in);
18690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
18700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
18720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public TrackInfoImpl[] newArray(int size) {
18730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return new TrackInfoImpl[size];
18740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
18750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                };
18760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };
18780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // We would like domain specific classes with more informative names than the `first` and `second`
18800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
18810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // we document the meanings of `first` and `second` here:
18820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //
18830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Pair.first - inband track index; non-null iff representing an inband track.
18840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
18850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //               an inband subtitle track or any out-of-band track (subtitle or timedtext).
18860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
18870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private BitSet mInbandTrackIndices = new BitSet();
18880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns a List of track information.
18910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return List of track info. The total number of tracks is the array length.
18930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Must be called again if an external timed text source has been added after
18940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * addTimedTextSource method is called.
18950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state.
18960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
18980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public List<TrackInfo> getTrackInfo() {
18990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl trackInfo[] = getInbandTrackInfoImpl();
19000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // add out-of-band tracks
19010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
19020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            TrackInfoImpl allTrackInfo[] = new TrackInfoImpl[mIndexTrackPairs.size()];
19030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < allTrackInfo.length; i++) {
19040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
19050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (p.first != null) {
19060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // inband track
19070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    allTrackInfo[i] = trackInfo[p.first];
19080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
19090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleTrack track = p.second;
19100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    allTrackInfo[i] = new TrackInfoImpl(track.getTrackType(), track.getFormat());
19110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
19120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
19130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return Arrays.asList(allTrackInfo);
19140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException {
19180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
19190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
19200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
19210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(INVOKE_ID_GET_TRACK_INFO);
19220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
19230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            TrackInfoImpl trackInfo[] = reply.createTypedArray(TrackInfoImpl.CREATOR);
19240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return trackInfo;
19250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
19260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
19270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
19280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
19320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A helper function to check if the mime type is supported by media framework.
19330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
19340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static boolean availableMimeTypeForExternalSource(String mimeType) {
19350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (MEDIA_MIMETYPE_TEXT_SUBRIP.equals(mimeType)) {
19360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return true;
19370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return false;
19390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private SubtitleController mSubtitleController;
19420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
19440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
19450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setSubtitleAnchor(
19460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleController controller,
19470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleController.Anchor anchor) {
19480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: create SubtitleController in MediaPlayer2
19490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController = controller;
19500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController.setAnchor(anchor);
19510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
19540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The private version of setSubtitleAnchor is used internally to set mSubtitleController if
19550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * necessary when clients don't provide their own SubtitleControllers using the public version
19560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #setSubtitleAnchor(SubtitleController, Anchor)} (e.g. {@link VideoView} provides one).
19570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
19580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private synchronized void setSubtitleAnchor() {
19590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
19600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
19610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            thread.start();
19620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Handler handler = new Handler(thread.getLooper());
19630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            handler.post(new Runnable() {
19640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                @Override
19650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                public void run() {
19660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Context context = ActivityThread.currentApplication();
19670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer2Impl.this);
19680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSubtitleController.setAnchor(new Anchor() {
19690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        @Override
19700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        public void setSubtitleWidget(RenderingWidget subtitleWidget) {
19710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
19720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        @Override
19740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        public Looper getSubtitleLooper() {
19750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            return Looper.getMainLooper();
19760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
19770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    });
19780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    thread.getLooper().quitSafely();
19790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
19800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            });
19810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
19820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.join();
19830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (InterruptedException e) {
19840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Thread.currentThread().interrupt();
19850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "failed to join SetSubtitleAnchorThread");
19860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
19870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mSelectedSubtitleTrackIndex = -1;
19910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private Vector<InputStream> mOpenSubtitleSources;
19920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() {
19940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
19950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
19960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int index = data.getTrackIndex();
19970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
19980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
19990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p.first != null && p.first == index && p.second != null) {
20000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // inband subtitle track that owns data
20010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        SubtitleTrack track = p.second;
20020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        track.onData(data);
20030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
20040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
20050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };
20080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
20100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void onSubtitleTrackSelected(SubtitleTrack track) {
20120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSelectedSubtitleTrackIndex >= 0) {
20130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
20140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
20150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
20160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSelectedSubtitleTrackIndex = -1;
20180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setOnSubtitleDataListener(null);
20200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track == null) {
20210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
20220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
20250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
20260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (p.first != null && p.second == track) {
20270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // inband subtitle track that is selected
20280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSelectedSubtitleTrackIndex = p.first;
20290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
20300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
20310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSelectedSubtitleTrackIndex >= 0) {
20350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
20360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
20370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
20380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setOnSubtitleDataListener(mSubtitleDataListener);
20400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // no need to select out-of-band tracks
20420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
20430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
20450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addSubtitleSource(InputStream is, MediaFormat format)
20470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException
20480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
20490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final InputStream fIs = is;
20500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat fFormat = format;
20510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (is != null) {
20530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Ensure all input streams are closed.  It is also a handy
20540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // way to implement timeouts in the future.
20550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(mOpenSubtitleSources) {
20560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mOpenSubtitleSources.add(is);
20570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
20590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "addSubtitleSource called with null InputStream");
20600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        getMediaTimeProvider();
20630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // process each subtitle in its own thread
20650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final HandlerThread thread = new HandlerThread("SubtitleReadThread",
20660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia              Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
20670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        thread.start();
20680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Handler handler = new Handler(thread.getLooper());
20690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        handler.post(new Runnable() {
20700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            private int addTrack() {
20710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (fIs == null || mSubtitleController == null) {
20720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
20730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
20740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                SubtitleTrack track = mSubtitleController.addTrack(fFormat);
20760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (track == null) {
20770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
20780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
20790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // TODO: do the conversion in the subtitle track
20810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Scanner scanner = new Scanner(fIs, "UTF-8");
20820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                String contents = scanner.useDelimiter("\\A").next();
20830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized(mOpenSubtitleSources) {
20840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mOpenSubtitleSources.remove(fIs);
20850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
20860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scanner.close();
20870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mIndexTrackPairs) {
20880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
20890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
20900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Handler h = mTimeProvider.mEventHandler;
20910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int what = TimeProvider.NOTIFY;
20920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
20930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, contents.getBytes());
20940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Message m = h.obtainMessage(what, arg1, 0, trackData);
20950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                h.sendMessage(m);
20960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
20970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void run() {
21000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int res = addTrack();
21010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mEventHandler != null) {
21020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
21030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mEventHandler.sendMessage(m);
21040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
21050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.getLooper().quitSafely();
21060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
21070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        });
21080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
21090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void scanInternalSubtitleTracks() {
21110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setSubtitleAnchor();
21120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        populateInbandTracks();
21140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null) {
21160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.selectDefaultTrack();
21170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
21190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void populateInbandTracks() {
21210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl[] tracks = getInbandTrackInfoImpl();
21220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
21230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < tracks.length; i++) {
21240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mInbandTrackIndices.get(i)) {
21250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    continue;
21260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
21270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mInbandTrackIndices.set(i);
21280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
21290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // newly appeared inband track
21310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
21320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleTrack track = mSubtitleController.addTrack(
21330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            tracks[i].getFormat());
21340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.create(i, track));
21350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
21360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
21370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
21380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
21390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
21410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /* TODO: Limit the total number of external timed text source to a reasonable number.
21430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
21450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file.
21460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
21470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip with the file extension .srt, case insensitive.
21480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that a single external timed text source may contain multiple tracks in it.
21490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
21500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * additional tracks become available after this method call.
21510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
21520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param path The file path of external timed text source file.
21530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
21540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if the file cannot be accessed or is corrupted.
21550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
21560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
21570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
21580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
21600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(String path, String mimeType)
21610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
21620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!availableMimeTypeForExternalSource(mimeType)) {
21630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Illegal mimeType for timed text source: " + mimeType;
21640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
21650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        File file = new File(path);
21680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (file.exists()) {
21690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileInputStream is = new FileInputStream(file);
21700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileDescriptor fd = is.getFD();
21710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(fd, mimeType);
21720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            is.close();
21730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
21740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // We do not support the case where the path is not a file.
21750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IOException(path);
21760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
21780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
21810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file (Uri).
21820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
21830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip with the file extension .srt, case insensitive.
21840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that a single external timed text source may contain multiple tracks in it.
21850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
21860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * additional tracks become available after this method call.
21870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
21880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param context the Context to use when resolving the Uri
21890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param uri the Content URI of the data you want to play
21900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
21910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if the file cannot be accessed or is corrupted.
21920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
21930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
21940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
21950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
21970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(Context context, Uri uri, String mimeType)
21980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
21990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String scheme = uri.getScheme();
22000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if(scheme == null || scheme.equals("file")) {
22010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(uri.getPath(), mimeType);
22020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
22030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        AssetFileDescriptor fd = null;
22060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
22070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            ContentResolver resolver = context.getContentResolver();
22080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            fd = resolver.openAssetFileDescriptor(uri, "r");
22090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (fd == null) {
22100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
22110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(fd.getFileDescriptor(), mimeType);
22130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
22140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (SecurityException ex) {
22150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (IOException ex) {
22160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
22170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (fd != null) {
22180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                fd.close();
22190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
22220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
22240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file (FileDescriptor).
22250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
22260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is the caller's responsibility to close the file descriptor.
22270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is safe to do so as soon as this call returns.
22280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
22290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip. Note that a single external timed text source may
22300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain multiple tracks in it. One can find the total number of available tracks
22310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * using {@link #getTrackInfo()} to see what additional tracks become available
22320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * after this method call.
22330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
22340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param fd the FileDescriptor for the file you want to play
22350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
22360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
22370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
22380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
22390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
22400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
22410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(FileDescriptor fd, String mimeType) {
22420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // intentionally less than LONG_MAX
22430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        addTimedTextSource(fd, 0, 0x7ffffffffffffffL, mimeType);
22440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
22450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
22470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text file (FileDescriptor).
22480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
22490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is the caller's responsibility to close the file descriptor.
22500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is safe to do so as soon as this call returns.
22510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
22520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip. Note that a single external timed text source may
22530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain multiple tracks in it. One can find the total number of available tracks
22540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * using {@link #getTrackInfo()} to see what additional tracks become available
22550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * after this method call.
22560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
22570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param fd the FileDescriptor for the file you want to play
22580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param offset the offset into the file where the data to be played starts, in bytes
22590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param length the length in bytes of the data to be played
22600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mime The mime type of the file. Must be one of the mime types listed above.
22610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
22620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
22630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
22640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
22650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
22660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime) {
22670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!availableMimeTypeForExternalSource(mime)) {
22680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mime);
22690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final FileDescriptor dupedFd;
22720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
22730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dupedFd = Os.dup(fd);
22740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (ErrnoException ex) {
22750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, ex.getMessage(), ex);
22760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new RuntimeException(ex);
22770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat fFormat = new MediaFormat();
22800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        fFormat.setString(MediaFormat.KEY_MIME, mime);
22810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        fFormat.setInteger(MediaFormat.KEY_IS_TIMED_TEXT, 1);
22820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // A MediaPlayer2 created by a VideoView should already have its mSubtitleController set.
22840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController == null) {
22850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setSubtitleAnchor();
22860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!mSubtitleController.hasRendererFor(fFormat)) {
22890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // test and add not atomic
22900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Context context = ActivityThread.currentApplication();
22910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler));
22920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
22940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
22950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
22960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        getMediaTimeProvider();
22990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final long offset2 = offset;
23010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final long length2 = length;
23020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final HandlerThread thread = new HandlerThread(
23030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                "TimedTextReadThread",
23040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
23050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        thread.start();
23060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Handler handler = new Handler(thread.getLooper());
23070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        handler.post(new Runnable() {
23080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            private int addTrack() {
23090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final ByteArrayOutputStream bos = new ByteArrayOutputStream();
23100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
23110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
23120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    byte[] buffer = new byte[4096];
23130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (long total = 0; total < length2;) {
23140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        int bytesToRead = (int) Math.min(buffer.length, length2 - total);
23150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        int bytes = IoBridge.read(dupedFd, buffer, 0, bytesToRead);
23160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (bytes < 0) {
23170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            break;
23180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        } else {
23190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            bos.write(buffer, 0, bytes);
23200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            total += bytes;
23210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
23220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
23230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Handler h = mTimeProvider.mEventHandler;
23240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    int what = TimeProvider.NOTIFY;
23250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
23260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, bos.toByteArray());
23270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = h.obtainMessage(what, arg1, 0, trackData);
23280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    h.sendMessage(m);
23290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
23300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
23310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.e(TAG, e.getMessage(), e);
23320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_TIMED_TEXT_ERROR;
23330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } finally {
23340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    try {
23350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Os.close(dupedFd);
23360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    } catch (ErrnoException e) {
23370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, e.getMessage(), e);
23380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
23390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
23400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
23410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void run() {
23430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int res = addTrack();
23440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mEventHandler != null) {
23450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
23460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mEventHandler.sendMessage(m);
23470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
23480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.getLooper().quitSafely();
23490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
23500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        });
23510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
23520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
23540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the index of the audio, video, or subtitle track currently selected for playback,
23550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The return value is an index into the array returned by {@link #getTrackInfo()}, and can
23560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * be used in calls to {@link #selectTrack(int)} or {@link #deselectTrack(int)}.
23570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
23590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
23600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
23610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return index of the audio, video, or subtitle track currently selected for playback;
23620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a negative integer is returned when there is no selected track for {@code trackType} or
23630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when {@code trackType} is not one of audio, video, or subtitle.
23640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called after {@link #close()}
23650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #getTrackInfo()
23670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #selectTrack(int)
23680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #deselectTrack(int)
23690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
23710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int getSelectedTrack(int trackType) {
23720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null
23730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
23740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
23750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
23760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (subtitleTrack != null) {
23770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mIndexTrackPairs) {
23780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (int i = 0; i < mIndexTrackPairs.size(); i++) {
23790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
23800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
23810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            return i;
23820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
23830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
23840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
23850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
23860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
23890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
23900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
23910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(INVOKE_ID_GET_SELECTED_TRACK);
23920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(trackType);
23930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
23940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int inbandTrackIndex = reply.readInt();
23950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
23960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (int i = 0; i < mIndexTrackPairs.size(); i++) {
23970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
23980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p.first != null && p.first == inbandTrackIndex) {
23990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return i;
24000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
24010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
24020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return -1;
24040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
24050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
24060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
24070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
24090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
24110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Selects a track.
24120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
24130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is in invalid state, it throws an IllegalStateException exception.
24140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is in <em>Started</em> state, the selected track is presented immediately.
24150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is not in Started state, it just marks the track to be played.
24160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
24170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
24180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * In any valid state, if it is called multiple times on the same type of track (ie. Video,
24190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Audio, Timed Text), the most recent one will be chosen.
24200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
24210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
24220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The first audio and video tracks are selected by default if available, even though
24230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method is not called. However, no timed text track will be selected until
24240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this function is called.
24250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
24260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
24270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently, only timed text tracks or audio tracks can be selected via this method.
24280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * In addition, the support for selecting an audio track at runtime is pretty limited
24290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in that an audio track can only be selected in the <em>Prepared</em> state.
24300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
24310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of the track to be selected. The valid range of the index
24320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is 0..total number of track - 1. The total number of tracks as well as the type of
24330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * each individual track can be found by calling {@link #getTrackInfo()} method.
24340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
24350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
24360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
24370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
24380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
24390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void selectTrack(int index) {
24400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        selectOrDeselectTrack(index, true /* select */);
24410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
24420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
24440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Deselect a track.
24450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
24460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently, the track must be a timed text track and no audio or video tracks can be
24470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * deselected. If the timed text track identified by index has not been
24480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * selected before, it throws an exception.
24490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
24500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of the track to be deselected. The valid range of the index
24510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
24520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * each individual track can be found by calling {@link #getTrackInfo()} method.
24530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
24540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
24550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
24560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
24570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
24580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void deselectTrack(int index) {
24590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        selectOrDeselectTrack(index, false /* select */);
24600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
24610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void selectOrDeselectTrack(int index, boolean select)
24630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException {
24640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // handle subtitle track through subtitle controller
24650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        populateInbandTracks();
24660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Pair<Integer,SubtitleTrack> p = null;
24680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
24690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            p = mIndexTrackPairs.get(index);
24700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (ArrayIndexOutOfBoundsException e) {
24710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // ignore bad index
24720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
24730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        SubtitleTrack track = p.second;
24760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track == null) {
24770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // inband (de)select
24780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            selectOrDeselectInbandTrack(p.first, select);
24790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
24800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController == null) {
24830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
24840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!select) {
24870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // out-of-band deselect
24880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSubtitleController.getSelectedTrack() == track) {
24890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSubtitleController.selectTrack(null);
24900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
24910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "trying to deselect track that was not selected");
24920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
24940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // out-of-band select
24970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
24980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
24990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
25000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
25010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
25020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p2.first != null && p2.second == null) {
25030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // deselect inband counterpart
25040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        selectOrDeselectInbandTrack(p2.first, false);
25050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
25060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
25080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController.selectTrack(track);
25100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void selectOrDeselectInbandTrack(int index, boolean select)
25130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException {
25140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
25150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
25160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
25170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK);
25180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(index);
25190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
25200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
25210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
25220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
25230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Have to declare protected for finalize() since it is protected
25270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // in the base class Object.
25280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
25290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    protected void finalize() throws Throwable {
25300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mGuard != null) {
25310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mGuard.warnIfOpen();
25320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        close();
25350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_finalize();
25360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void release() {
25390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
25400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
25410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
254263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.clear();
25430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider != null) {
25450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider.close();
25460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = null;
25470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnSubtitleDataListener = null;
25490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Modular DRM clean up
25510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnDrmConfigHelper = null;
25520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
255363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.clear();
25540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        resetDrmState();
25560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _release();
25580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _release();
25610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /* Do not change these values without updating their counterparts
25630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in include/media/mediaplayer2.h!
25640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
25650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_NOP = 0; // interface test message
25660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PREPARED = 1;
25670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PLAYBACK_COMPLETE = 2;
25680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_BUFFERING_UPDATE = 3;
25690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SEEK_COMPLETE = 4;
25700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SET_VIDEO_SIZE = 5;
25710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_STARTED = 6;
25720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PAUSED = 7;
25730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_STOPPED = 8;
25740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SKIPPED = 9;
25750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_NOTIFY_TIME = 98;
25760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_TIMED_TEXT = 99;
25770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_ERROR = 100;
25780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_INFO = 200;
25790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SUBTITLE_DATA = 201;
25800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_META_DATA = 202;
25810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_DRM_INFO = 210;
25820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
25830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private TimeProvider mTimeProvider;
25850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
25870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
25880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaTimeProvider getMediaTimeProvider() {
25890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider == null) {
25900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = new TimeProvider(this);
25910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mTimeProvider;
25930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private class EventHandler extends Handler {
25960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mMediaPlayer;
25970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public EventHandler(MediaPlayer2Impl mp, Looper looper) {
25990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(looper);
26000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mMediaPlayer = mp;
26010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
26040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void handleMessage(Message msg) {
260534c5bb126b8cc85176645acea841c796a3cc0292Wei Jia            handleMessage(msg, 0);
260634c5bb126b8cc85176645acea841c796a3cc0292Wei Jia        }
260734c5bb126b8cc85176645acea841c796a3cc0292Wei Jia
260834c5bb126b8cc85176645acea841c796a3cc0292Wei Jia        public void handleMessage(Message msg, long srcId) {
26090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mMediaPlayer.mNativeContext == 0) {
26100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "mediaplayer2 went away with unhandled events");
26110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
26120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
261363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            final int what = msg.arg1;
261463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            final int extra = msg.arg2;
26150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            switch(msg.what) {
26160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PREPARED:
26170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
26180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scanInternalSubtitleTracks();
26190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (RuntimeException e) {
26200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // send error message instead of crashing;
26210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // send error message instead of inlining a call to onError
26220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // to avoid code duplication.
26230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message msg2 = obtainMessage(
26240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
26250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    sendMessage(msg2);
26260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
26270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                final DataSourceDesc dsd;
2629de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                synchronized (mPlLock) {
2630de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
26311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                            + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
26321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    if (srcId == mCurrentSrcId) {
2633de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        prepareNextDataSource_l();
26341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        dsd = mCurrentDSD;
26351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    } else if (mPlNextIndex >= 0 && srcId == mNextSrcId) {
2636de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        mPlNextSourceState = NEXT_SOURCE_STATE_PREPARED;
2637de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        if (mPlNextSourcePlayPending) {
2638de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                            playNextDataSource_l();
2639de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        }
26401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        dsd = mPlaylist.get(0);
26411789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    } else {
26421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        dsd = null;
2643de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    }
2644de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                }
2645de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
264663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
26471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
264863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
26491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0));
265063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
26510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
26520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
26530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_DRM_INFO:
26550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj == null) {
26560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
26570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (msg.obj instanceof Parcel) {
265863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    // The parcel was parsed already in postEventFromNative
265963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    final DrmInfoImpl drmInfo;
266063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
266163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    synchronized (mDrmLock) {
266263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (mDrmInfoImpl != null) {
266363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            drmInfo = mDrmInfoImpl.makeCopy();
266463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        } else {
266563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            drmInfo = null;
26660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
266763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
26680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
266963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    // notifying the client outside the lock
267063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    if (drmInfo != null) {
267163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        synchronized (mEventCbLock) {
267263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
267363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                cb.first.execute(() -> cb.second.onDrmInfo(
26741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                        mMediaPlayer, mCurrentDSD, drmInfo));
267563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            }
26760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
26770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
26780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
26790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
26800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
26810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
26820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PLAYBACK_COMPLETE:
2684de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                synchronized (mPlLock) {
26851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    if (srcId == mCurrentSrcId) {
2686de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
26871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
2688de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        playNextDataSource_l();
2689de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    }
2690de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                }
2691de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
269263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
26931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
269463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
26951789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
269663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
26970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
26980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                stayAwake(false);
26990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
27000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_STOPPED:
27020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                {
27030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
27040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
27050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onStopped();
27060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
27070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
27090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_STARTED:
27110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PAUSED:
27120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                {
27130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
27140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
27150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onPaused(msg.what == MEDIA_PAUSED);
27160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
27170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
27190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_BUFFERING_UPDATE:
272163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int percent = msg.arg1;
272263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
27231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
27241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        cb.first.execute(() -> cb.second.onInfo(
27251789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE, percent));
272663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
27270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
27290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SEEK_COMPLETE:
273163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
27321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
27331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        cb.first.execute(() -> cb.second.onCallComplete(
27341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, MEDIA_CALL_SEEK_TO, 0));
273563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
27360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // fall through
27380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SKIPPED:
27400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                {
27410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
27420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
27430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onSeekComplete(mMediaPlayer);
27440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
27450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
27470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SET_VIDEO_SIZE:
274963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int width = msg.arg1;
275063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int height = msg.arg2;
275163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
27521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
275363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onVideoSizeChanged(
27541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, width, height));
275563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
27560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
27580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_ERROR:
27600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
276163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
27621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
276363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onError(
27641789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, what, extra));
276563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
27661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
276763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
27680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                stayAwake(false);
27700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
27710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_INFO:
27730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                switch (msg.arg1) {
2774de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    case MEDIA_INFO_STARTED_AS_NEXT:
27751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        if (srcId == mCurrentSrcId) {
2776de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                            prepareNextDataSource_l();
2777de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        }
2778de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        break;
2779de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
278063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_VIDEO_TRACK_LAGGING:
278163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
278263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
278363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
278463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_METADATA_UPDATE:
278563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        try {
278663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            scanInternalSubtitleTracks();
278763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        } catch (RuntimeException e) {
278863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            Message msg2 = obtainMessage(
278963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED,
279063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                    null);
279163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            sendMessage(msg2);
279263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
279363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        // fall through
27940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
279563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
279663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
279763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        // update default track selection
279863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (mSubtitleController != null) {
279963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            mSubtitleController.selectDefaultTrack();
280063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
280163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
280263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
280363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_BUFFERING_START:
280463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_BUFFERING_END:
280563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        TimeProvider timeProvider = mTimeProvider;
280663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (timeProvider != null) {
280763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            timeProvider.onBuffering(msg.arg1 == MEDIA_INFO_BUFFERING_START);
280863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
280963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
28100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
281263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
28131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
281463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
28151789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, what, extra));
281663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
28170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // No real default action so far.
28190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
28200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_NOTIFY_TIME:
28220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
28230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
28240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onNotifyTime();
28250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
28260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
28270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TIMED_TEXT:
282963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final TimedText text;
283063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                if (msg.obj instanceof Parcel) {
283163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    Parcel parcel = (Parcel)msg.obj;
283263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    text = new TimedText(parcel);
283363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    parcel.recycle();
28340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
283563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    text = null;
283663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
283763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
283863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
28391789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
28401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, mCurrentDSD, text));
28410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
28420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
28440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SUBTITLE_DATA:
28460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener;
28470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (onSubtitleDataListener == null) {
28480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return;
28490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj instanceof Parcel) {
28510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Parcel parcel = (Parcel) msg.obj;
28520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleData data = new SubtitleData(parcel);
28530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    parcel.recycle();
28540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    onSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
28550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
28570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_META_DATA:
285963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final TimedMetaData data;
28600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj instanceof Parcel) {
28610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Parcel parcel = (Parcel) msg.obj;
286263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
28630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    parcel.recycle();
286463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                } else {
286563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    data = null;
286663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
286763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
286863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
28691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
287063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
28711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, data));
287263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
28730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
28750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_NOP: // interface test message - ignore
28770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
28780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_AUDIO_ROUTING_CHANGED:
28800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                AudioManager.resetAudioPortGeneration();
28810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mRoutingChangeListeners) {
28820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (NativeRoutingEventHandlerDelegate delegate
28830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            : mRoutingChangeListeners.values()) {
28840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        delegate.notifyClient();
28850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
28860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
28880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
28900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "Unknown message type " + msg.what);
28910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
28920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
28930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
28940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
28950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
28970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Called from native code when an interesting event happens.  This method
28980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * just uses the EventHandler system to post the event back to the main app thread.
28990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * We use a weak reference to the original MediaPlayer2 object so that the native
29000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * code is safe from the object disappearing from underneath it.  (This is
29010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the cookie passed to native_setup().)
29020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
290334c5bb126b8cc85176645acea841c796a3cc0292Wei Jia    private static void postEventFromNative(Object mediaplayer2_ref, long srcId,
29040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                            int what, int arg1, int arg2, Object obj)
29050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
29060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get();
29070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mp == null) {
29080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
29090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (what) {
29120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_INFO:
29130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
29140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                new Thread(new Runnable() {
29150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
29160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public void run() {
29170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // this acquires the wakelock if needed, and sets the client side state
29180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mp.play();
29190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
29200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }).start();
29210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Thread.yield();
29220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
29230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
29240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_DRM_INFO:
29260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // We need to derive mDrmInfoImpl before prepare() returns so processing it here
29270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // before the notification is sent to EventHandler below. EventHandler runs in the
29280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // notification looper so its handleMessage might process the event after prepare()
29290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // has returned.
29300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
29310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (obj instanceof Parcel) {
29320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Parcel parcel = (Parcel)obj;
29330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                DrmInfoImpl drmInfo = new DrmInfoImpl(parcel);
29340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mp.mDrmLock) {
29350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mp.mDrmInfoImpl = drmInfo;
29360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
29380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + obj);
29390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
29400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
29410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_PREPARED:
29430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // By this time, we've learned about DrmInfo's presence or absence. This is meant
29441789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            // mainly for prepare() use case. For prepare(), this still can run to a race
29450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // condition b/c MediaPlayerNative releases the prepare() lock before calling notify
29460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // so we also set mDrmInfoResolved in prepare().
29470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mp.mDrmLock) {
29480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mp.mDrmInfoResolved = true;
29490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
29500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
29510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mp.mEventHandler != null) {
29550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
295634c5bb126b8cc85176645acea841c796a3cc0292Wei Jia
295734c5bb126b8cc85176645acea841c796a3cc0292Wei Jia            mp.mEventHandler.post(new Runnable() {
295834c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                @Override
295934c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                public void run() {
296034c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                    mp.mEventHandler.handleMessage(m, srcId);
296134c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                }
296234c5bb126b8cc85176645acea841c796a3cc0292Wei Jia            });
29630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
29650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mEventCbLock = new Object();
29671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private ArrayList<Pair<Executor, MediaPlayer2EventCallback> > mEventCallbackRecords
29681789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        = new ArrayList<Pair<Executor, MediaPlayer2EventCallback> >();
29690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
29710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when the media source is ready
29720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * for playback.
29730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
29740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param eventCallback the callback that will be run
29750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param executor the executor through which the callback should be invoked
29760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
29770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
29781789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setMediaPlayer2EventCallback(@NonNull @CallbackExecutor Executor executor,
29791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            @NonNull MediaPlayer2EventCallback eventCallback) {
29800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (eventCallback == null) {
29811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
29820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (executor == null) {
29841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException(
29851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    "Illegal null Executor for the MediaPlayer2EventCallback");
29860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
298863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.add(new Pair(executor, eventCallback));
29890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
29910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
29931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Clears the {@link MediaPlayer2EventCallback}.
29940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
29950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
29961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void clearMediaPlayer2EventCallback() {
29970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
29981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
29991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                mEventCallbackRecords.remove(cb);
30000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
30010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
30050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when a track has data available.
30060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
30070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener the callback that will be run
30080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
30090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
30100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
30110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
30120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setOnSubtitleDataListener(OnSubtitleDataListener listener) {
30130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnSubtitleDataListener = listener;
30140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnSubtitleDataListener mOnSubtitleDataListener;
30170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM begin
30200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
30220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked for configuration of the DRM object before
30230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the session is created.
30240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The callback will be invoked synchronously during the execution
30250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * of {@link #prepareDrm(UUID uuid)}.
30260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
30270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener the callback that will be run
30280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
30290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
30300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setOnDrmConfigHelper(OnDrmConfigHelper listener)
30310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
30320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
30330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mOnDrmConfigHelper = listener;
30340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } // synchronized
30350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnDrmConfigHelper mOnDrmConfigHelper;
30380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mDrmEventCbLock = new Object();
304063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia    private ArrayList<Pair<Executor, DrmEventCallback> > mDrmEventCallbackRecords
304163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        = new ArrayList<Pair<Executor, DrmEventCallback> >();
30420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
30440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when the media source is ready
30450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * for playback.
30460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
30470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param eventCallback the callback that will be run
30480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param executor the executor through which the callback should be invoked
30490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
30500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
30511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
30520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @NonNull DrmEventCallback eventCallback) {
30530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (eventCallback == null) {
30541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
30550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (executor == null) {
30571789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException(
30581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    "Illegal null Executor for the MediaPlayer2EventCallback");
30590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
306163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
30620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
30661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Clears the {@link DrmEventCallback}.
30670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
30680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
30691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void clearDrmEventCallback() {
30700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
307163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
30721789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                mDrmEventCallbackRecords.remove(cb);
30730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
30740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
30790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Retrieves the DRM Info associated with the current source
30800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
30811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if called before prepare()
30820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
30830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
30840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public DrmInfo getDrmInfo() {
30850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        DrmInfoImpl drmInfo = null;
30860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // there is not much point if the app calls getDrmInfo within an OnDrmInfoListenet;
30880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // regardless below returns drmInfo anyway instead of raising an exception
30890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
30900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mDrmInfoResolved && mDrmInfoImpl == null) {
30910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "The Player has not been prepared yet";
30920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, msg);
30930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
30940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
30950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmInfoImpl != null) {
30970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                drmInfo = mDrmInfoImpl.makeCopy();
30980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
30990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
31000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return drmInfo;
31020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
31030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
31060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Prepares the DRM for the current source
31070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
31080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmConfigHelper} is registered, it will be called during
31090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * preparation to allow configuration of the DRM properties before opening the
31100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * DRM session. Note that the callback is called synchronously in the thread that called
31110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
31120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and {@code setDrmPropertyString} calls and refrain from any lengthy operation.
31130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
31140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the device has not been provisioned before, this call also provisions the device
31150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * which involves accessing the provisioning server and can take a variable time to
31160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * complete depending on the network connectivity.
31170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
31180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * mode by launching the provisioning in the background and returning. The listener
31190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * will be called when provisioning and preparation has finished. If a
31200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
31210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and preparation has finished, i.e., runs in blocking mode.
31220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
31230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
31240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * session being ready. The application should not make any assumption about its call
31250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * sequence (e.g., before or after prepareDrm returns), or the thread context that will
31260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * execute the listener (unless the listener is registered with a handler thread).
31270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
31280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
31290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
31300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
31310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
31321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException              if called before prepare(), or the DRM was
31330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            prepared already
31340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws UnsupportedSchemeException         if the crypto scheme is not supported
31350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ResourceBusyException              if required DRM resources are in use
31360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ProvisioningNetworkErrorException  if provisioning is required but failed due to a
31370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            network error
31380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ProvisioningServerErrorException   if provisioning is required but failed due to
31390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            the request denied by the provisioning server
31400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
31410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
31420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void prepareDrm(@NonNull UUID uuid)
31430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws UnsupportedSchemeException, ResourceBusyException,
31440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                   ProvisioningNetworkErrorException, ProvisioningServerErrorException
31450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
31460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper);
31470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean allDoneWithoutProvisioning = false;
31490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
31510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // only allowing if tied to a protected source; might relax for releasing offline keys
31530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmInfoImpl == null) {
31540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " +
31550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "DRM info be retrieved before this call.";
31560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
31570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
31580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mActiveDrmScheme) {
31610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: There is already " +
31620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "an active DRM scheme with " + mDrmUUID;
31630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
31640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
31650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mPrepareDrmInProgress) {
31680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: There is already " +
31690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "a pending prepareDrm call.";
31700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
31710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
31720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmProvisioningInProgress) {
31750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Unexpectd: Provisioning is already in progress.";
31760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
31770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
31780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // shouldn't need this; just for safeguard
31810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            cleanDrmObj();
31820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPrepareDrmInProgress = true;
31840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
31860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // only creating the DRM object to allow pre-openSession configuration
31871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                prepareDrm(uuid);
31880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
31890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "prepareDrm(): Exception ", e);
31900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPrepareDrmInProgress = false;
31910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
31920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmConfigAllowed = true;
31950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
31960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // call the callback outside the lock
31990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mOnDrmConfigHelper != null)  {
32001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            mOnDrmConfigHelper.onDrmConfig(this, mCurrentDSD);
32010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
32040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmConfigAllowed = false;
32050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean earlyExit = false;
32060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
32080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                prepareDrm_openSessionStep(uuid);
32090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmUUID = uuid;
32110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mActiveDrmScheme = true;
32120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                allDoneWithoutProvisioning = true;
32140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
32150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: The player must be " +
32160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "in the prepared state to call prepareDrm().";
32170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
32180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                earlyExit = true;
32190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
32200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
32210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "prepareDrm: NotProvisionedException");
32220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // handle provisioning internally; it'll reset mPrepareDrmInProgress
32240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int result = HandleProvisioninig(uuid);
32250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if blocking mode, we're already done;
32270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if non-blocking mode, we attempted to launch background provisioning
32280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (result != PREPARE_DRM_STATUS_SUCCESS) {
32290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    earlyExit = true;
32300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    String msg;
32310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    switch (result) {
32330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
32340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Provisioning was required but failed " +
32350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                "due to a network error.";
32360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
32370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new ProvisioningNetworkErrorExceptionImpl(msg);
32380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
32400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Provisioning was required but the request " +
32410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                "was denied by the server.";
32420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
32430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new ProvisioningServerErrorExceptionImpl(msg);
32440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PREPARATION_ERROR:
32460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    default: // default for safeguard
32470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Post-provisioning preparation failed.";
32480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
32490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new IllegalStateException(msg);
32500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
32510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // nothing else to do;
32530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup
32540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
32550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "prepareDrm: Exception " + e);
32560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                earlyExit = true;
32570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
32580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } finally {
32590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!mDrmProvisioningInProgress) {// if early exit other than provisioning exception
32600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPrepareDrmInProgress = false;
32610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (earlyExit) {    // cleaning up object if didn't succeed
32630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    cleanDrmObj();
32640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } // finally
32660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
32670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // if finished successfully without provisioning, call the callback outside the lock
32700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (allDoneWithoutProvisioning) {
32710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mDrmEventCbLock) {
327263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
327363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    cb.first.execute(() -> cb.second.onDrmPrepared(
32741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                            this, mCurrentDSD, PREPARE_DRM_STATUS_SUCCESS));
327563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
32760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
32770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
32800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _releaseDrm();
32830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
32850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Releases the DRM session
32860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
32870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The player has to have an active DRM session and be in stopped, or prepared
32880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * state before this call is made.
32890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A {@code reset()} call will release the DRM session implicitly.
32900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
32910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session to release
32920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
32930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
32940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void releaseDrm()
32950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
32960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
32970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "releaseDrm:");
32980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
33000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
33010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "releaseDrm(): No active DRM scheme to release.");
33020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("releaseDrm: No active DRM scheme to release.");
33030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
33060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we don't have the player's state in this layer. The below call raises
33070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // exception if we're in a non-stopped/prepared state.
33080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // for cleaning native/mediaserver crypto object
33100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                _releaseDrm();
33110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // for cleaning client-side MediaDrm object; only called if above has succeeded
33130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                cleanDrmObj();
33140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mActiveDrmScheme = false;
33160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
33170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "releaseDrm: Exception ", e);
33180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException("releaseDrm: The player is not in a valid state.");
33190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
33200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "releaseDrm: Exception ", e);
33210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
33230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
33240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
33270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A key request/response exchange occurs between the app and a license server
33280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to obtain or release keys used to decrypt encrypted content.
33290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
33301789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * getDrmKeyRequest() is used to obtain an opaque key request byte array that is
33310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * delivered to the license server.  The opaque key request byte array is returned
33320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in KeyRequest.data.  The recommended URL to deliver the key request to is
33330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * returned in KeyRequest.defaultUrl.
33340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
33350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * After the app has received the key request response from the server,
33360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * it should deliver to the response to the DRM engine plugin using the method
33371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #provideDrmKeyResponse}.
33380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId is the key-set identifier of the offline keys being released when keyType is
33400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
33410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}.
33420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param initData is the container-specific initialization data when the keyType is
33440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is
33450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * interpreted based on the mime type provided in the mimeType parameter.  It could
33460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain, for example, the content ID, key ID or other data obtained from the content
33470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * metadata that is required in generating the key request.
33480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null.
33490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType identifies the mime type of the content
33510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keyType specifies the type of the request. The request may be to acquire
33530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content
33540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired
33550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId.
33560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param optionalParameters are included in the key request message to
33580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * allow a client application to provide additional message parameters to the server.
33590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This may be {@code null} if no additional parameters are to be sent.
33600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session
33620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
33630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
33640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
33651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public MediaDrm.KeyRequest getDrmKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData,
33660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable String mimeType, @MediaDrm.KeyType int keyType,
33670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable Map<String, String> optionalParameters)
33680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
33690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
33701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Log.v(TAG, "getDrmKeyRequest: " +
33710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
33720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " keyType: " + keyType + " optionalParameters: " + optionalParameters);
33730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
33750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
33761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
33771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new NoDrmSchemeExceptionImpl("getDrmKeyRequest: Has to set a DRM scheme first.");
33780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
33810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
33820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
33830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        keySetId;       // keySetId for KEY_TYPE_RELEASE
33840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                HashMap<String, String> hmapOptionalParameters =
33860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                (optionalParameters != null) ?
33870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                new HashMap<String, String>(optionalParameters) :
33880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                null;
33890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scope, initData, mimeType,
33910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                              keyType, hmapOptionalParameters);
33921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.v(TAG, "getDrmKeyRequest:   --> request: " + request);
33930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return request;
33950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
33971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "getDrmKeyRequest NotProvisionedException: " +
33980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected. Shouldn't have reached here.");
33991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new IllegalStateException("getDrmKeyRequest: Unexpected provisioning error.");
34000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
34011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "getDrmKeyRequest Exception " + e);
34020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
34030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
34060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A key response is received from the license server by the app, then it is
34111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * provided to the DRM engine plugin using provideDrmKeyResponse. When the
34120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * response is for an offline key request, a key-set identifier is returned that
34130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * can be used to later restore the keys to a new session with the method
34141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@ link # restoreDrmKeys}.
34150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When the response is for a streaming or release request, null is returned.
34160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId When the response is for a release request, keySetId identifies
34180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the saved key associated with the release request (i.e., the same keySetId
34191789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * passed to the earlier {@ link #getDrmKeyRequest} call. It MUST be null when the
34200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * response is for either streaming or offline key requests.
34210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param response the byte array response from the server
34230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session
34250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws DeniedByServerException if the response indicates that the
34260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * server rejected the request
34270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
34280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
34291789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public byte[] provideDrmKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
34300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException, DeniedByServerException
34310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
34321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response);
34330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
34350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
34371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
34381789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new NoDrmSchemeExceptionImpl("getDrmKeyRequest: Has to set a DRM scheme first.");
34390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
34420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] scope = (keySetId == null) ?
34430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mDrmSessionId :     // sessionId for KEY_TYPE_STREAMING/OFFLINE
34440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                keySetId;           // keySetId for KEY_TYPE_RELEASE
34450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
34470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response +
34490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        " --> " + keySetResult);
34500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return keySetResult;
34530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
34551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "provideDrmKeyResponse NotProvisionedException: " +
34560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected. Shouldn't have reached here.");
34571789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new IllegalStateException("provideDrmKeyResponse: " +
34580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected provisioning error.");
34590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
34601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "provideDrmKeyResponse Exception " + e);
34610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
34620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
34640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Restore persisted offline keys into a new session.  keySetId identifies the
34691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * keys to load, obtained from a prior call to {@link #provideDrmKeyResponse}.
34700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId identifies the saved key set to restore
34720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
34730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
34741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void restoreDrmKeys(@NonNull byte[] keySetId)
34750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
34760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
34771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
34780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
34800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
34821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
34831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new NoDrmSchemeExceptionImpl("restoreDrmKeys: Has to set a DRM scheme first.");
34840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
34870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmObj.restoreKeys(mDrmSessionId, keySetId);
34880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
34890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "restoreKeys Exception " + e);
34900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
34910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
34940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Read a DRM engine plugin String property value, given the property name string.
34990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param propertyName the property name
35010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Standard fields names are:
35030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
35040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
35050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
35060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
35070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
35080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName)
35090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
35100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
35110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName);
35120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String value;
35140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
35150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme && !mDrmConfigAllowed) {
35170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getDrmPropertyString NoDrmSchemeException");
35180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("getDrmPropertyString: Has to prepareDrm() first.");
35190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
35220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                value = mDrmObj.getPropertyString(propertyName);
35230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
35240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getDrmPropertyString Exception " + e);
35250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
35260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
35280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName + " --> value: " + value);
35300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return value;
35320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
35330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
35360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set a DRM engine plugin String property value.
35370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param propertyName the property name
35390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param value the property value
35400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Standard fields names are:
35420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
35430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
35440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
35450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
35460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName,
35470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                     @NonNull String value)
35480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
35490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
35500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "setDrmPropertyString: propertyName: " + propertyName + " value: " + value);
35510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
35530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if ( !mActiveDrmScheme && !mDrmConfigAllowed ) {
35550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setDrmPropertyString NoDrmSchemeException");
35560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("setDrmPropertyString: Has to prepareDrm() first.");
35570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
35600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmObj.setPropertyString(propertyName, value);
35610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch ( Exception e ) {
35620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setDrmPropertyString Exception " + e);
35630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
35640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
35660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
35670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
35690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Encapsulates the DRM properties of the source.
35700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
35710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class DrmInfoImpl extends DrmInfo {
35720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Map<UUID, byte[]> mapPssh;
35730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID[] supportedSchemes;
35740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
35760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Returns the PSSH info of the data source for each supported DRM scheme.
35770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
35780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
35790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public Map<UUID, byte[]> getPssh() {
35800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mapPssh;
35810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
35820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
35840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Returns the intersection of the data source and the device DRM schemes.
35850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * It effectively identifies the subset of the source's DRM schemes which
35860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * are supported by the device too.
35870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
35880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
35890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public List<UUID> getSupportedSchemes() {
35900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return Arrays.asList(supportedSchemes);
35910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
35920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes) {
35940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mapPssh = Pssh;
35950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            supportedSchemes = SupportedSchemes;
35960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
35970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl(Parcel parcel) {
35990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl(" + parcel + ") size " + parcel.dataSize());
36000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int psshsize = parcel.readInt();
36020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] pssh = new byte[psshsize];
36030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            parcel.readByteArray(pssh);
36040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() PSSH: " + arrToHex(pssh));
36060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mapPssh = parsePSSH(pssh, psshsize);
36070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() PSSH: " + mapPssh);
36080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int supportedDRMsCount = parcel.readInt();
36100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            supportedSchemes = new UUID[supportedDRMsCount];
36110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < supportedDRMsCount; i++) {
36120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] uuid = new byte[16];
36130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                parcel.readByteArray(uuid);
36140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                supportedSchemes[i] = bytesToUUID(uuid);
36160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, "DrmInfoImpl() supportedScheme[" + i + "]: " +
36180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                      supportedSchemes[i]);
36190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + psshsize +
36220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                  " supportedDRMsCount: " + supportedDRMsCount);
36230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
36240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl makeCopy() {
36260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new DrmInfoImpl(this.mapPssh, this.supportedSchemes);
36270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
36280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private String arrToHex(byte[] bytes) {
36300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String out = "0x";
36310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < bytes.length; i++) {
36320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out += String.format("%02x", bytes[i]);
36330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return out;
36360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
36370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID bytesToUUID(byte[] uuid) {
36390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long msb = 0, lsb = 0;
36400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < 8; i++) {
36410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                msb |= ( ((long)uuid[i]   & 0xff) << (8 * (7 - i)) );
36420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                lsb |= ( ((long)uuid[i+8] & 0xff) << (8 * (7 - i)) );
36430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new UUID(msb, lsb);
36460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
36470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
36490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Map<UUID, byte[]> result = new HashMap<UUID, byte[]>();
36500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int UUID_SIZE = 16;
36520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int DATALEN_SIZE = 4;
36530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int len = psshsize;
36550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int numentries = 0;
36560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
36570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            while (len > 0) {
36590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < UUID_SIZE) {
36600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
36610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "UUID: (%d < 16) pssh: %d", len, psshsize));
36620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
36630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
36640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] subset = Arrays.copyOfRange(pssh, i, i + UUID_SIZE);
36660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                UUID uuid = bytesToUUID(subset);
36670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += UUID_SIZE;
36680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= UUID_SIZE;
36690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // get data length
36710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < 4) {
36720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
36730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "datalen: (%d < 4) pssh: %d", len, psshsize));
36740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
36750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
36760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                subset = Arrays.copyOfRange(pssh, i, i+DATALEN_SIZE);
36780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) ?
36790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16) |
36800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[1] & 0xff) <<  8) |  (subset[0] & 0xff)          :
36810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16) |
36820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[2] & 0xff) <<  8) |  (subset[3] & 0xff) ;
36830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += DATALEN_SIZE;
36840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= DATALEN_SIZE;
36850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < datalen) {
36870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
36880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "data: (%d < %d) pssh: %d", len, datalen, psshsize));
36890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
36900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
36910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] data = Arrays.copyOfRange(pssh, i, i+datalen);
36930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // skip the data
36950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += datalen;
36960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= datalen;
36970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, String.format("parsePSSH[%d]: <%s, %s> pssh: %d",
36990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                         numentries, uuid, arrToHex(data), psshsize));
37000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                numentries++;
37010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                result.put(uuid, data);
37020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
37030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return result;
37050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
37060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };  // DrmInfoImpl
37080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when a DRM method is called before preparing a DRM scheme through prepareDrm().
37110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
37120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class NoDrmSchemeExceptionImpl extends NoDrmSchemeException {
37140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public NoDrmSchemeExceptionImpl(String detailMessage) {
37150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
37160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
37170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when the device requires DRM provisioning but the provisioning attempt has
37210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * failed due to a network error (Internet reachability, timeout, etc.).
37220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
37230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class ProvisioningNetworkErrorExceptionImpl
37250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            extends ProvisioningNetworkErrorException {
37260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningNetworkErrorExceptionImpl(String detailMessage) {
37270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
37280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
37290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when the device requires DRM provisioning but the provisioning attempt has
37330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * failed due to the provisioning server denying the request.
37340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
37350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class ProvisioningServerErrorExceptionImpl
37370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            extends ProvisioningServerErrorException {
37380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningServerErrorExceptionImpl(String detailMessage) {
37390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
37400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
37410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId);
37450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Modular DRM helpers
37470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void prepareDrm_createDrmStep(@NonNull UUID uuid)
37490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws UnsupportedSchemeException {
37500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid);
37510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
37530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj = new MediaDrm(uuid);
37540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj);
37550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) { // UnsupportedSchemeException
37560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e);
37570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw e;
37580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
37590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void prepareDrm_openSessionStep(@NonNull UUID uuid)
37620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NotProvisionedException, ResourceBusyException {
37630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm_openSessionStep: uuid: " + uuid);
37640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: don't need an open session for a future specialKeyReleaseDrm mode but we should do
37660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // it anyway so it raises provisioning error if needed. We'd rather handle provisioning
37671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // at prepareDrm/openSession rather than getDrmKeyRequest/provideDrmKeyResponse
37680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
37690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmSessionId = mDrmObj.openSession();
37700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId);
37710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Sending it down to native/mediaserver to create the crypto object
37730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // This call could simply fail due to bad player state, e.g., after play().
37740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            _prepareDrm(getByteArrayFromUUID(uuid), mDrmSessionId);
37750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_openSessionStep: _prepareDrm/Crypto succeeded");
37760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) { //ResourceBusyException, NotProvisionedException
37780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "prepareDrm_openSessionStep: open/crypto failed with " + e);
37790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw e;
37800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
37810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37848e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    // Called from the native side
37858e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    @SuppressWarnings("unused")
37868e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static boolean setAudioOutputDeviceById(AudioTrack track, int deviceId) {
37878e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        if (track == null) {
37888e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            return false;
37898e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
37908e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
37918e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        if (deviceId == 0) {
37928e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            // Use default routing.
37938e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            track.setPreferredDevice(null);
37948e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            return true;
37958e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
37968e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
37978e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        // TODO: Unhide AudioManager.getDevicesStatic.
37988e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        AudioDeviceInfo[] outputDevices =
37998e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
38008e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
38018e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        boolean success = false;
38028e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        for (AudioDeviceInfo device : outputDevices) {
38038e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            if (device.getId() == deviceId) {
38048e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                track.setPreferredDevice(device);
38058e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                success = true;
38068e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                break;
38078e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            }
38088e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
38098e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        return success;
38108e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    }
38118e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
38128e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    // Instantiated from the native side
38138e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    @SuppressWarnings("unused")
38148e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static class StreamEventCallback extends AudioTrack.StreamEventCallback {
38158e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mJAudioTrackPtr;
38168e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mNativeCallbackPtr;
38178e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mUserDataPtr;
38188e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
38198e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public StreamEventCallback(long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr) {
38208e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            super();
38218e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mJAudioTrackPtr = jAudioTrackPtr;
38228e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mNativeCallbackPtr = nativeCallbackPtr;
38238e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mUserDataPtr = userDataPtr;
38248e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
38258e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
38268e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
38278e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onTearDown(AudioTrack track) {
38288e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onTearDown(mNativeCallbackPtr, mUserDataPtr);
38298e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
38308e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
38318e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
38328e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onStreamPresentationEnd(AudioTrack track) {
38338e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onStreamPresentationEnd(mNativeCallbackPtr, mUserDataPtr);
38348e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
38358e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
38368e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
38378e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onStreamDataRequest(AudioTrack track) {
38388e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onStreamDataRequest(
38398e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                    mJAudioTrackPtr, mNativeCallbackPtr, mUserDataPtr);
38408e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
38418e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    }
38428e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
38430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private class ProvisioningThread extends Thread {
38440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public static final int TIMEOUT_MS = 60000;
38450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID uuid;
38470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private String urlStr;
38480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Object drmLock;
38490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mediaPlayer;
38500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private int status;
38510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean finished;
38520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public  int status() {
38530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return status;
38540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningThread initialize(MediaDrm.ProvisionRequest request,
38570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                          UUID uuid, MediaPlayer2Impl mediaPlayer) {
38580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // lock is held by the caller
38590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            drmLock = mediaPlayer.mDrmLock;
38600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            this.mediaPlayer = mediaPlayer;
38610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
38630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            this.uuid = uuid;
38640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
38660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "HandleProvisioninig: Thread is initialised url: " + urlStr);
38680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return this;
38690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void run() {
38720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] response = null;
38740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean provisioningSucceeded = false;
38750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
38760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                URL url = new URL(urlStr);
38770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
38780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
38790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setRequestMethod("POST");
38800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setDoOutput(false);
38810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setDoInput(true);
38820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setConnectTimeout(TIMEOUT_MS);
38830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setReadTimeout(TIMEOUT_MS);
38840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.connect();
38860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    response = Streams.readFully(connection.getInputStream());
38870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.v(TAG, "HandleProvisioninig: Thread run: response " +
38890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            response.length + " " + response);
38900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
38910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
38920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url);
38930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } finally {
38940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.disconnect();
38950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
38960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e)   {
38970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
38980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "HandleProvisioninig: Thread run: openConnection " + e);
38990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (response != null) {
39020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
39030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mDrmObj.provideProvisionResponse(response);
39040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.v(TAG, "HandleProvisioninig: Thread run: " +
39050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            "provideProvisionResponse SUCCEEDED!");
39060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    provisioningSucceeded = true;
39080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
39090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR;
39100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "HandleProvisioninig: Thread run: " +
39110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            "provideProvisionResponse " + e);
39120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
39130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean succeeded = false;
39160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
391763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            boolean hasCallback = false;
39180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mDrmEventCbLock) {
391963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                hasCallback = !mDrmEventCallbackRecords.isEmpty();
39200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // non-blocking mode needs the lock
392263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            if (hasCallback) {
39230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (drmLock) {
39250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // continuing with prepareDrm
39260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (provisioningSucceeded) {
39270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        succeeded = mediaPlayer.resumePrepareDrm(uuid);
39280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        status = (succeeded) ?
39290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                PREPARE_DRM_STATUS_SUCCESS :
39300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                PREPARE_DRM_STATUS_PREPARATION_ERROR;
39310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
39320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mediaPlayer.mDrmProvisioningInProgress = false;
39330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mediaPlayer.mPrepareDrmInProgress = false;
39340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (!succeeded) {
39350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        cleanDrmObj();  // cleaning up if it hasn't gone through while in the lock
39360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
39370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } // synchronized
39380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // calling the callback outside the lock
394063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mDrmEventCbLock) {
394163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
39421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        cb.first.execute(() -> cb.second.onDrmPrepared(
39431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mediaPlayer, mCurrentDSD, status));
394463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
394563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
39460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {   // blocking mode already has the lock
39470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // continuing with prepareDrm
39490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (provisioningSucceeded) {
39500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    succeeded = mediaPlayer.resumePrepareDrm(uuid);
39510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = (succeeded) ?
39520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            PREPARE_DRM_STATUS_SUCCESS :
39530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            PREPARE_DRM_STATUS_PREPARATION_ERROR;
39540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
39550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mediaPlayer.mDrmProvisioningInProgress = false;
39560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mediaPlayer.mPrepareDrmInProgress = false;
39570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!succeeded) {
39580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    cleanDrmObj();  // cleaning up if it hasn't gone through
39590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
39600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            finished = true;
39630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // run()
39640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }   // ProvisioningThread
39660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int HandleProvisioninig(UUID uuid) {
39680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the lock is already held by the caller
39690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmProvisioningInProgress) {
39710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress");
39720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
39730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
39740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
39760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (provReq == null) {
39770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null.");
39780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
39790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
39800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "HandleProvisioninig provReq " +
39820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
39830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // networking in a background thread
39850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningInProgress = true;
39860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this);
39880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningThread.start();
39890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int result;
39910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // non-blocking: this is not the final result
399363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        boolean hasCallback = false;
39940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
399563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            hasCallback = !mDrmEventCallbackRecords.isEmpty();
39960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
399763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        if (hasCallback) {
39980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            result = PREPARE_DRM_STATUS_SUCCESS;
39990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
40000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // if blocking mode, wait till provisioning is done
40010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
40020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmProvisioningThread.join();
40030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
40040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e);
40050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
40060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            result = mDrmProvisioningThread.status();
40070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // no longer need the thread
40080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmProvisioningThread = null;
40090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return result;
40120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
40130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean resumePrepareDrm(UUID uuid) {
40150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "resumePrepareDrm: uuid: " + uuid);
40160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // mDrmLock is guaranteed to be held
40180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean success = false;
40190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
40200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // resuming
40210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            prepareDrm_openSessionStep(uuid);
40220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmUUID = uuid;
40240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mActiveDrmScheme = true;
40250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            success = true;
40270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) {
40280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "HandleProvisioninig: Thread run _prepareDrm resume failed with " + e);
40290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // mDrmObj clean up is done by the caller
40300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return success;
40330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
40340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void resetDrmState() {
40360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
40370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "resetDrmState: " +
40380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mDrmInfoImpl=" + mDrmInfoImpl +
40390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mDrmProvisioningThread=" + mDrmProvisioningThread +
40400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mPrepareDrmInProgress=" + mPrepareDrmInProgress +
40410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mActiveDrmScheme=" + mActiveDrmScheme);
40420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmInfoResolved = false;
40440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmInfoImpl = null;
40450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmProvisioningThread != null) {
40470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // timeout; relying on HttpUrlConnection
40480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
40490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mDrmProvisioningThread.join();
40500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
40510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                catch (InterruptedException e) {
40520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "resetDrmState: ProvThread.join Exception " + e);
40530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
40540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmProvisioningThread = null;
40550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
40560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPrepareDrmInProgress = false;
40580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mActiveDrmScheme = false;
40590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            cleanDrmObj();
40610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
40620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
40630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void cleanDrmObj() {
40650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the caller holds mDrmLock
40660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj + " mDrmSessionId=" + mDrmSessionId);
40670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmSessionId != null)    {
40690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj.closeSession(mDrmSessionId);
40700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmSessionId = null;
40710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmObj != null) {
40730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj.release();
40740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj = null;
40750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
40770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
40790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long msb = uuid.getMostSignificantBits();
40800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long lsb = uuid.getLeastSignificantBits();
40810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        byte[] uuidBytes = new byte[16];
40830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (int i = 0; i < 8; ++i) {
40840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
40850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
40860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return uuidBytes;
40890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
40900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM end
40920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
40940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Test whether a given video scaling mode is supported.
40950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
40960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean isVideoScalingModeSupported(int mode) {
40970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return (mode == VIDEO_SCALING_MODE_SCALE_TO_FIT ||
40980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
40990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
41000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
41020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    static class TimeProvider implements MediaTimeProvider {
41030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final String TAG = "MTP";
41040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long MAX_NS_WITHOUT_POSITION_CHECK = 5000000000L;
41050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long MAX_EARLY_CALLBACK_US = 1000;
41060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long TIME_ADJUSTMENT_RATE = 2;  /* meaning 1/2 */
41070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mLastTimeUs = 0;
41080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mPlayer;
41090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mPaused = true;
41100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mStopped = true;
41110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mBuffering;
41120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mLastReportedTime;
41130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // since we are expecting only a handful listeners per stream, there is
41140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // no need for log(N) search performance
41150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaTimeProvider.OnMediaTimeListener mListeners[];
41160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mTimes[];
411734c5bb126b8cc85176645acea841c796a3cc0292Wei Jia        private EventHandler mEventHandler;
41180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mRefresh = false;
41190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mPausing = false;
41200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mSeeking = false;
41210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY = 1;
41220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_TIME = 0;
41230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_STOP = 2;
41240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_SEEK = 3;
41250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_TRACK_DATA = 4;
41260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private HandlerThread mHandlerThread;
41270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
41290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public boolean DEBUG = false;
41300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public TimeProvider(MediaPlayer2Impl mp) {
41320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPlayer = mp;
41330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
41340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                getCurrentTimeUs(true, false);
41350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
41360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we assume starting position
41370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRefresh = true;
41380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Looper looper;
41410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if ((looper = Looper.myLooper()) == null &&
41420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                (looper = Looper.getMainLooper()) == null) {
41430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // Create our own looper here in case MP was created without one
41440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread = new HandlerThread("MediaPlayer2MTPEventThread",
41450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                      Process.THREAD_PRIORITY_FOREGROUND);
41460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.start();
41470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                looper = mHandlerThread.getLooper();
41480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(looper);
41500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
41520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimes = new long[0];
41530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mLastTimeUs = 0;
41540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private void scheduleNotification(int type, long delayUs) {
41570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // ignore time notifications until seek is handled
41580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSeeking && type == NOTIFY_TIME) {
41590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
41600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (DEBUG) Log.v(TAG, "scheduleNotification " + type + " in " + delayUs);
41630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeMessages(NOTIFY);
41640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Message msg = mEventHandler.obtainMessage(NOTIFY, type, 0);
41650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.sendMessageDelayed(msg, (int) (delayUs / 1000));
41660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
41690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void close() {
41700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeMessages(NOTIFY);
41710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mHandlerThread != null) {
41720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.quitSafely();
41730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread = null;
41740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
41780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        protected void finalize() {
41790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mHandlerThread != null) {
41800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.quitSafely();
41810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
41850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onNotifyTime() {
41860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
41870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onNotifyTime: ");
41880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
41890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
41930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onPaused(boolean paused) {
41940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
41950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onPaused: " + paused);
41960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mStopped) { // handle as seek if we were stopped
41970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mStopped = false;
41980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = true;
41990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
42000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
42010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPausing = paused;  // special handling if player disappeared
42020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = false;
42030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
42040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
42090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onBuffering(boolean buffering) {
42100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
42110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onBuffering: " + buffering);
42120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mBuffering = buffering;
42130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
42140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
42180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onStopped() {
42190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
42200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onStopped");
42210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPaused = true;
42220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mStopped = true;
42230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSeeking = false;
42240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mBuffering = false;
42250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_STOP, 0 /* delay */);
42260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
42300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onSeekComplete(MediaPlayer2Impl mp) {
42310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
42320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mStopped = false;
42330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSeeking = true;
42340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
42350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
42390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onNewPlayer() {
42400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mRefresh) {
42410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized(this) {
42420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mStopped = false;
42430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = true;
42440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mBuffering = false;
42450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
42460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifySeek() {
42510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSeeking = false;
42520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
42530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long timeUs = getCurrentTimeUs(true, false);
42540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onSeekComplete at " + timeUs);
42550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
42570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (listener == null) {
42580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
42590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
42600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    listener.onSeek(timeUs);
42610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
42630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we should not be there, but at least signal pause
42640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onSeekComplete but no player");
42650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPausing = true;  // special handling if player disappeared
42660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                notifyTimedEvent(false /* refreshTime */);
42670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyTrackData(Pair<SubtitleTrack, byte[]> trackData) {
42710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleTrack track = trackData.first;
42720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] data = trackData.second;
42730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            track.onData(data, true /* eos */, ~0 /* runID: keep forever */);
42740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyStop() {
42770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
42780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (listener == null) {
42790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
42800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                listener.onStop();
42820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private int registerListener(MediaTimeProvider.OnMediaTimeListener listener) {
42860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
42870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (; i < mListeners.length; i++) {
42880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mListeners[i] == listener || mListeners[i] == null) {
42890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
42900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // new listener
42940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (i >= mListeners.length) {
42950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaTimeProvider.OnMediaTimeListener[] newListeners =
42960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    new MediaTimeProvider.OnMediaTimeListener[i + 1];
42970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long[] newTimes = new long[i + 1];
42980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                System.arraycopy(mListeners, 0, newListeners, 0, mListeners.length);
42990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                System.arraycopy(mTimes, 0, newTimes, 0, mTimes.length);
43000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mListeners = newListeners;
43010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes = newTimes;
43020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mListeners[i] == null) {
43050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mListeners[i] = listener;
43060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes[i] = MediaTimeProvider.NO_TIME;
43070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return i;
43090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
43100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void notifyAt(
43120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long timeUs, MediaTimeProvider.OnMediaTimeListener listener) {
43130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
43140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "notifyAt " + timeUs);
43150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes[registerListener(listener)] = timeUs;
43160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
43170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
43190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void scheduleUpdate(MediaTimeProvider.OnMediaTimeListener listener) {
43210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
43220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "scheduleUpdate");
43230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int i = registerListener(listener);
43240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!mStopped) {
43260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mTimes[i] = 0;
43270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
43280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
43310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void cancelNotifications(
43330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaTimeProvider.OnMediaTimeListener listener) {
43340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
43350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int i = 0;
43360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (; i < mListeners.length; i++) {
43370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mListeners[i] == listener) {
43380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        System.arraycopy(mListeners, i + 1,
43390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mListeners, i, mListeners.length - i - 1);
43400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        System.arraycopy(mTimes, i + 1,
43410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mTimes, i, mTimes.length - i - 1);
43420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mListeners[mListeners.length - 1] = null;
43430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mTimes[mTimes.length - 1] = NO_TIME;
43440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
43450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    } else if (mListeners[i] == null) {
43460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
43470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
43480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
43510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
43530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyTimedEvent(boolean refreshTime) {
43550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // figure out next callback
43560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long nowUs;
43570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
43580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                nowUs = getCurrentTimeUs(refreshTime, true);
43590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
43600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // assume we paused until new player arrives
43610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRefresh = true;
43620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPausing = true; // this ensures that call succeeds
43630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                nowUs = getCurrentTimeUs(refreshTime, true);
43640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long nextTimeUs = nowUs;
43660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSeeking) {
43680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // skip timed-event notifications until seek is complete
43690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
43700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (DEBUG) {
43730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                StringBuilder sb = new StringBuilder();
43740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                sb.append("notifyTimedEvent(").append(mLastTimeUs).append(" -> ")
43750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        .append(nowUs).append(") from {");
43760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                boolean first = true;
43770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (long time: mTimes) {
43780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (time == NO_TIME) {
43790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        continue;
43800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
43810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (!first) sb.append(", ");
43820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    sb.append(time);
43830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    first = false;
43840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                sb.append("}");
43860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.d(TAG, sb.toString());
43870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Vector<MediaTimeProvider.OnMediaTimeListener> activatedListeners =
43900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                new Vector<MediaTimeProvider.OnMediaTimeListener>();
43910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int ix = 0; ix < mTimes.length; ix++) {
43920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mListeners[ix] == null) {
43930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
43940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mTimes[ix] <= NO_TIME) {
43960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // ignore, unless we were stopped
43970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (mTimes[ix] <= nowUs + MAX_EARLY_CALLBACK_US) {
43980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    activatedListeners.add(mListeners[ix]);
43990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (DEBUG) Log.d(TAG, "removed");
44000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mTimes[ix] = NO_TIME;
44010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (nextTimeUs == nowUs || mTimes[ix] < nextTimeUs) {
44020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    nextTimeUs = mTimes[ix];
44030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (nextTimeUs > nowUs && !mPaused) {
44070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // schedule callback at nextTimeUs
44080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "scheduling for " + nextTimeUs + " and " + nowUs);
44090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPlayer.notifyAt(nextTimeUs);
44100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
44110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mEventHandler.removeMessages(NOTIFY);
44120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // no more callbacks
44130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (MediaTimeProvider.OnMediaTimeListener listener: activatedListeners) {
44160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                listener.onTimedEvent(nowUs);
44170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public long getCurrentTimeUs(boolean refreshTime, boolean monotonic)
44210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throws IllegalStateException {
44220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
44230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we always refresh the time when the paused-state changes, because
44240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we expect to have received the pause-change event delayed.
44250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mPaused && !refreshTime) {
44260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return mLastReportedTime;
44270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
44300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mLastTimeUs = mPlayer.getCurrentPosition() * 1000L;
44310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPaused = !mPlayer.isPlaying() || mBuffering;
44320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (DEBUG) Log.v(TAG, (mPaused ? "paused" : "playing") + " at " + mLastTimeUs);
44330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (IllegalStateException e) {
44340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mPausing) {
44350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // if we were pausing, get last estimated timestamp
44360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mPausing = false;
44370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (!monotonic || mLastReportedTime < mLastTimeUs) {
44380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            mLastReportedTime = mLastTimeUs;
44390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
44400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mPaused = true;
44410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (DEBUG) Log.d(TAG, "illegal state, but pausing: estimating at " + mLastReportedTime);
44420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return mLastReportedTime;
44430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
44440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // TODO get time when prepared
44450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    throw e;
44460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (monotonic && mLastTimeUs < mLastReportedTime) {
44480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    /* have to adjust time */
44490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mLastReportedTime - mLastTimeUs > 1000000) {
44500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // schedule seeked event if time jumped significantly
44510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // TODO: do this properly by introducing an exception
44520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mStopped = false;
44530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mSeeking = true;
44540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
44550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
44560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
44570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mLastReportedTime = mLastTimeUs;
44580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return mLastReportedTime;
44610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private class EventHandler extends Handler {
44650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public EventHandler(Looper looper) {
44660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                super(looper);
44670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Override
44700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void handleMessage(Message msg) {
44710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.what == NOTIFY) {
44720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    switch (msg.arg1) {
44730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_TIME:
44740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyTimedEvent(true /* refreshTime */);
44750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
44760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_STOP:
44770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyStop();
44780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
44790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_SEEK:
44800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifySeek();
44810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
44820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_TRACK_DATA:
44830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyTrackData((Pair<SubtitleTrack, byte[]>)msg.obj);
44840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
44850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
44860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
44900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
4491