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.PowerManager;
3947cab8322a01edee503f10e9d5cbec2a5b5cffc3Dongwon Kangimport android.os.Process;
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;
4547cab8322a01edee503f10e9d5cbec2a5b5cffc3Dongwon Kangimport android.util.ArrayMap;
460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.Log;
470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.Pair;
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.ref.WeakReference;
670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.HttpCookie;
680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.HttpURLConnection;
690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.URL;
700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.nio.ByteOrder;
710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.ArrayList;
720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Arrays;
730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.BitSet;
740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.HashMap;
75adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kangimport java.util.LinkedList;
760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.List;
770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Map;
780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Scanner;
790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Set;
800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.UUID;
810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Vector;
8247cab8322a01edee503f10e9d5cbec2a5b5cffc3Dongwon Kangimport java.util.concurrent.Executor;
83c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jiaimport java.util.concurrent.atomic.AtomicInteger;
840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia/**
860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * @hide
870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia */
880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiapublic final class MediaPlayer2Impl extends MediaPlayer2 {
890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    static {
900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        System.loadLibrary("media2_jni");
910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_init();
920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final static String TAG = "MediaPlayer2Impl";
950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private long mNativeContext; // accessed by native methods
970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private long mNativeSurfaceTexture;  // accessed by native methods
980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mListenerContext; // accessed by native methods
990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private SurfaceHolder mSurfaceHolder;
1000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private EventHandler mEventHandler;
1010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private PowerManager.WakeLock mWakeLock = null;
1020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mScreenOnWhilePlaying;
1030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mStayAwake;
1040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
1050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final CloseGuard mGuard = CloseGuard.get();
1060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
107cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private final Object mSrcLock = new Object();
108cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    //--- guarded by |mSrcLock| start
109cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private long mSrcIdGenerator = 0;
1101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private DataSourceDesc mCurrentDSD;
111cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private long mCurrentSrcId = mSrcIdGenerator++;
112cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private List<DataSourceDesc> mNextDSDs;
113cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private long mNextSrcId = mSrcIdGenerator++;
114cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private int mNextSourceState = NEXT_SOURCE_STATE_INIT;
115cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private boolean mNextSourcePlayPending = false;
116cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    //--- guarded by |mSrcLock| end
1170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
118371144fcc23f3d0a668d0d51bd3c3f90c964cd7bWei Jia    private AtomicInteger mBufferedPercentageCurrent = new AtomicInteger(0);
119371144fcc23f3d0a668d0d51bd3c3f90c964cd7bWei Jia    private AtomicInteger mBufferedPercentageNext = new AtomicInteger(0);
120096d97ac3e01d3a148f6148180c375f9337b64e5Wei Jia    private volatile float mVolume = 1.0f;
121c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia
1220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM
1230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mDrmLock = new Object();
124cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    //--- guarded by |mDrmLock| start
125cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private UUID mDrmUUID;
1260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private DrmInfoImpl mDrmInfoImpl;
1270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private MediaDrm mDrmObj;
1280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private byte[] mDrmSessionId;
1290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmInfoResolved;
1300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mActiveDrmScheme;
1310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmConfigAllowed;
1320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmProvisioningInProgress;
1330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mPrepareDrmInProgress;
1340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private ProvisioningThread mDrmProvisioningThread;
135cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    //--- guarded by |mDrmLock| end
1360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
137adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    private HandlerThread mHandlerThread;
138adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    private final Handler mTaskHandler;
139adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    private final Object mTaskLock = new Object();
140adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    @GuardedBy("mTaskLock")
141adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    private final List<Task> mPendingTasks = new LinkedList<>();
142adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    @GuardedBy("mTaskLock")
143adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    private Task mCurrentTask;
144adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
1450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
1460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Default constructor.
1470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>When done with the MediaPlayer2Impl, you should call  {@link #close()},
1480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to free the resources. If not released, too many MediaPlayer2Impl instances may
1490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * result in an exception.</p>
1500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
1510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaPlayer2Impl() {
1520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Looper looper;
1530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ((looper = Looper.myLooper()) != null) {
1540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(this, looper);
1550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if ((looper = Looper.getMainLooper()) != null) {
1560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(this, looper);
1570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
1580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = null;
1590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
1600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
161adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        mHandlerThread = new HandlerThread("MediaPlayer2TaskThread");
162adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        mHandlerThread.start();
163adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        looper = mHandlerThread.getLooper();
164adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        mTaskHandler = new Handler(looper);
165adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
1660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mTimeProvider = new TimeProvider(this);
1670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOpenSubtitleSources = new Vector<InputStream>();
1680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mGuard.open("close");
1690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* Native setup requires a weak reference to our object.
1710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * It's easier to create it here than in C++.
1720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
1730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_setup(new WeakReference<MediaPlayer2Impl>(this));
1740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
1750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
1771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Releases the resources held by this {@code MediaPlayer2} object.
1781789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
1791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * It is considered good practice to call this method when you're
1801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * done using the MediaPlayer2. In particular, whenever an Activity
1811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * of an application is paused (its onPause() method is called),
1821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * or stopped (its onStop() method is called), this method should be
1831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * invoked to release the MediaPlayer2 object, unless the application
1841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * has a special need to keep the object around. In addition to
1851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * unnecessary resources (such as memory and instances of codecs)
1861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * being held, failure to call this method immediately if a
1871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * MediaPlayer2 object is no longer needed may also lead to
1881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * continuous battery consumption for mobile devices, and playback
1891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * failure for other applications if no multiple instances of the
1901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * same codec are supported on a device. Even if multiple instances
1911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * of the same codec are supported, some performance degradation
1921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * may be expected when unnecessary multiple instances are used
1931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * at the same time.
1941789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
1951789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@code close()} may be safely called after a prior {@code close()}.
1961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * This class implements the Java {@code AutoCloseable} interface and
1971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * may be used with try-with-resources.
1981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
1991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
2001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void close() {
2011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        synchronized (mGuard) {
2021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            release();
2031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        }
2041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
205de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
2061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
2071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Starts or resumes playback. If playback had previously been paused,
2081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * playback will continue from where it was paused. If playback had
2091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * been stopped, or never started before, playback will start at the
2101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * beginning.
2111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
2121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
2130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
2151789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void play() {
21669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_PLAY, false) {
21769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
21869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
21969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                stayAwake(true);
22069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _start();
22169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
22269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
2231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
2240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2251789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _start() throws IllegalStateException;
2261789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
2271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
2281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Prepares the player for playback, asynchronously.
2291789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
2301789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * After setting the datasource and the display surface, you need to either
2311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * call prepare(). For streams, you should call prepare(),
2321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * which returns immediately, rather than blocking until enough data has been
2331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * buffered.
2341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
2351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
2360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
238adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    public void prepare() {
23969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_PREPARE, true) {
24069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
24169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
24269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _prepare();
24369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
24469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
245adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    }
246adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
247adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    public native void _prepare();
2480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Pauses playback. Call play() to resume.
2510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
2531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized.
2540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
2561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void pause() {
25769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_PAUSE, false) {
25869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
25969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
26069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                stayAwake(false);
26169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _pause();
26269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
26369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
2640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
2650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _pause() throws IllegalStateException;
2671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
2680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2691789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Tries to play next data source if applicable.
2700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
2720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
2741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void skipToNext() {
27569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
27669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
27769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
27869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                // TODO: switch to next data source and play
27969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
28069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
2810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
2820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
2830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
2841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current playback position.
2850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the current position in milliseconds
2871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
2881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
2891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public native long getCurrentPosition();
2901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
2911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
2921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the duration of the file.
2930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
2941789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the duration in milliseconds, if no duration is available
2951789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *         (for example, if streaming live content), -1 is returned.
2960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
2970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
2981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public native long getDuration();
2990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current buffered media source position received through progressive downloading.
3021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * The received buffering percentage indicates how much of the content has been buffered
3031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * or played. For example a buffering update of 80 percent when half the content
3041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * has already been played indicates that the next 30 percent of the
3051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * content to play has been buffered.
3060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
3071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the current buffered media source position in milliseconds
3081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
3091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
3101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public long getBufferedPosition() {
311c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia        // Use cached buffered percent for now.
312c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia        return getDuration() * mBufferedPercentageCurrent.get() / 100;
3131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
3141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
3150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @PlayerState int getPlayerState() {
317be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia        int mediaplayer2State = getMediaPlayer2State();
318be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia        int playerState;
319be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia        switch (mediaplayer2State) {
320be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia            case MEDIAPLAYER2_STATE_IDLE:
321be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                playerState = PLAYER_STATE_IDLE;
322be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                break;
323be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia            case MEDIAPLAYER2_STATE_PREPARED:
324be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia            case MEDIAPLAYER2_STATE_PAUSED:
325be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                playerState = PLAYER_STATE_PAUSED;
326be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                break;
327be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia            case MEDIAPLAYER2_STATE_PLAYING:
328be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                playerState = PLAYER_STATE_PLAYING;
329be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                break;
330be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia            case MEDIAPLAYER2_STATE_ERROR:
331be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia            default:
332be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                playerState = PLAYER_STATE_ERROR;
333be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia                break;
334be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia        }
335be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia
336be6e3024bdab7479e352933194eec36abf2b0bf3Wei Jia        return playerState;
3370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
3380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Gets the current buffering state of the player.
3411789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
3421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * buffered.
3430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @BuffState int getBufferingState() {
3461789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // TODO: use cached state or call native function.
3471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return BUFFERING_STATE_UNKNOWN;
3480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
3490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the audio attributes for this MediaPlayer2.
3521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * See {@link AudioAttributes} for how to build and configure an instance of this class.
3531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * You must call this method before {@link #prepare()} in order
3541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * for the audio attributes to become effective thereafter.
3551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param attributes a non-null set of audio attributes
3561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalArgumentException if the attributes are null or invalid.
3570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3591789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setAudioAttributes(@NonNull AudioAttributes attributes) {
36069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) {
36169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
36269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
36369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (attributes == null) {
36469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    final String msg = "Cannot set AudioAttributes to null";
36569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    throw new IllegalArgumentException(msg);
36669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
36769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Parcel pattributes = Parcel.obtain();
36869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
36969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
37069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                pattributes.recycle();
37169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
37269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
3731789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
3741789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
3751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
3761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @NonNull AudioAttributes getAudioAttributes() {
3771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Parcel pattributes = getParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES);
3781789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        AudioAttributes attributes = AudioAttributes.CREATOR.createFromParcel(pattributes);
3791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        pattributes.recycle();
3801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return attributes;
3810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
3820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
3830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
3840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the data source as described by a DataSourceDesc.
3850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
3860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param dsd the descriptor of data source you want to play
3870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
3880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException if dsd is null
3890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
3900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
3911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setDataSource(@NonNull DataSourceDesc dsd) {
39269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
39369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
39469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
39569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
39669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                // TODO: setDataSource could update exist data source
39769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                synchronized (mSrcLock) {
39869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mCurrentDSD = dsd;
39969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mCurrentSrcId = mSrcIdGenerator++;
40069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    try {
40169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        handleDataSource(true /* isCurrent */, dsd, mCurrentSrcId);
40269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    } catch (IOException e) {
40369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
40469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
4051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            }
40669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
4070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
4101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets a single data source as described by a DataSourceDesc which will be played
4111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * after current data source is finished.
4120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
4131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param dsd the descriptor of data source you want to play after current one
4141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if it is called in an invalid state
4151789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws NullPointerException if dsd is null
4160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
4170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
4181789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setNextDataSource(@NonNull DataSourceDesc dsd) {
41969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
42069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
42169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
42269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
42369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                synchronized (mSrcLock) {
42469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextDSDs = new ArrayList<DataSourceDesc>(1);
42569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextDSDs.add(dsd);
42669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextSrcId = mSrcIdGenerator++;
42769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextSourceState = NEXT_SOURCE_STATE_INIT;
42869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextSourcePlayPending = false;
42969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
43069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                int state = getMediaPlayer2State();
43169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (state != MEDIAPLAYER2_STATE_IDLE) {
43269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    synchronized (mSrcLock) {
43369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        prepareNextDataSource_l();
43469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
43569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
436cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
43769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
4380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
4411789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets a list of data sources to be played sequentially after current data source is done.
4420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
4431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param dsds the list of data sources you want to play after current one
4440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
4451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalArgumentException if dsds is null or empty, or contains null DataSourceDesc
4460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
4470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
4481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
44969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) {
45069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
45169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
45269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (dsds == null || dsds.size() == 0) {
45369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    throw new IllegalArgumentException("data source list cannot be null or empty.");
45469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
45569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                for (DataSourceDesc dsd : dsds) {
45669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    if (dsd == null) {
45769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        throw new IllegalArgumentException(
45869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                                "DataSourceDesc in the source list cannot be null.");
45969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
46069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
4610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                synchronized (mSrcLock) {
46369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextDSDs = new ArrayList(dsds);
46469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextSrcId = mSrcIdGenerator++;
46569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextSourceState = NEXT_SOURCE_STATE_INIT;
46669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    mNextSourcePlayPending = false;
46769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
46869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                int state = getMediaPlayer2State();
46969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (state != MEDIAPLAYER2_STATE_IDLE) {
47069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    synchronized (mSrcLock) {
47169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        prepareNextDataSource_l();
47269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
47369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
474cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
47569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
4760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
4791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @NonNull DataSourceDesc getCurrentDataSource() {
480cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia        synchronized (mSrcLock) {
4811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            return mCurrentDSD;
4820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
4830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
4850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
4861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Configures the player to loop on the current data source.
4871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param loop true if the current data source is meant to loop.
4880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
4890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
4901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void loopCurrent(boolean loop) {
49169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) {
49269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
49369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
49469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                // TODO: set the looping mode, send notification
49569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                setLooping(loop);
49669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
49769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
4981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
4990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void setLooping(boolean looping);
5010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
5031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the playback speed.
5041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A value of 1.0f is the default playback value.
5051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()}
5061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * before using negative values.<br>
5071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * After changing the playback speed, it is recommended to query the actual speed supported
5081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * by the player, see {@link #getPlaybackSpeed()}.
5091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param speed the desired playback speed
5101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setPlaybackSpeed(float speed) {
51369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_SPEED, false) {
51469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
51569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
51669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setPlaybackParams(getPlaybackParams().setSpeed(speed));
51769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
51869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
5190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
5221789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Returns the actual playback speed to be used by the player when playing.
5231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}.
5241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the actual playback speed
5250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
5271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public float getPlaybackSpeed() {
5281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return getPlaybackParams().getSpeed();
5291789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
5300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
5321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Indicates whether reverse playback is supported.
5331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Reverse playback is indicated by negative playback speeds, see
5341789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #setPlaybackSpeed(float)}.
5351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return true if reverse playback is supported.
5361789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5381789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public boolean isReversePlaybackSupported() {
5391789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return false;
5401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
5410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
5431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the volume of the audio of the media to play, expressed as a linear multiplier
5441789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * on the audio samples.
5451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Note that this volume is specific to the player, and is separate from stream volume
5461789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * used across the platform.<br>
5471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
5481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
5491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
5501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setPlayerVolume(float volume) {
55369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
55469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
55569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
556096d97ac3e01d3a148f6148180c375f9337b64e5Wei Jia                mVolume = volume;
55769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setVolume(volume, volume);
55869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
55969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
5600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _setVolume(float leftVolume, float rightVolume);
5631789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
5640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
5651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Returns the current volume of this player to this player.
5661789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Note that it does not take into account the associated stream volume.
5671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the player volume.
5680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
5701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public float getPlayerVolume() {
571096d97ac3e01d3a148f6148180c375f9337b64e5Wei Jia        return mVolume;
5720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
5751789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
5760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
5781789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public float getMaxPlayerVolume() {
5791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return 1.0f;
5801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
5810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
5831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Adds a callback to be notified of events for this player.
5841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param e the {@link Executor} to be used for the events.
5851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param cb the callback to receive the events.
5861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void registerPlayerEventCallback(@NonNull Executor e,
5891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            @NonNull PlayerEventCallback cb) {
5901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
591de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
5921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
5931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Removes a previously registered callback for player events
5941789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param cb the callback to remove
5951789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
5961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
5971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb) {
5980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
6011789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_ERROR = -1;
6021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_INIT = 0;
6031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_PREPARING = 1;
6041789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int NEXT_SOURCE_STATE_PREPARED = 2;
6051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
6061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /*
6071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Update the MediaPlayer2Impl SurfaceTexture.
6081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Call after setting a new display surface.
6091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
6101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native void _setVideoSurface(Surface surface);
6111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
6121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /* Do not change these values (starting with INVOKE_ID) without updating
6131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * their counterparts in include/media/mediaplayer2.h!
6141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
6151789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_GET_TRACK_INFO = 1;
6161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE = 2;
6171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3;
6181789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_SELECT_TRACK = 4;
6191789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_DESELECT_TRACK = 5;
6201789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_SET_VIDEO_SCALE_MODE = 6;
6211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
6221789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
6230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Create a request parcel which can be routed to the native media
6251789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * player using {@link #invoke(Parcel, Parcel)}. The Parcel
6261789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * returned has the proper InterfaceToken set. The caller should
6271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * not overwrite that token, i.e it can only append data to the
6281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Parcel.
6290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6301789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @return A parcel suitable to hold a request for the native
6311789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * player.
6321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@hide}
6330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public Parcel newRequest() {
6361789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Parcel parcel = Parcel.obtain();
6371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        return parcel;
6380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6411789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Invoke a generic method on the native player using opaque
6421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * parcels for the request and reply. Both payloads' format is a
6431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * convention between the java caller and the native player.
6441789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Must be called after setDataSource or setPlaylist to make sure a native player
6451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * exists. On failure, a RuntimeException is thrown.
6460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param request Parcel with the data for the extension. The
6481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * caller must use {@link #newRequest()} to get one.
6491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     *
6501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param reply Output parcel with the data returned by the
6511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * native player.
6521789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@hide}
6530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void invoke(Parcel request, Parcel reply) {
6561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        int retcode = native_invoke(request, reply);
6571789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        reply.setDataPosition(0);
6581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (retcode != 0) {
6591789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new RuntimeException("failure code: " + retcode);
6600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
6610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6631789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
6641789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void notifyWhenCommandLabelReached(Object label) {
66569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) {
66669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
66769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
66869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                synchronized (mEventCbLock) {
66969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
67069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        cb.first.execute(() -> cb.second.onCommandLabelReached(
67169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                                MediaPlayer2Impl.this, label));
67269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
67369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
67469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
67569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
6761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
6771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
6780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the {@link SurfaceHolder} to use for displaying the video
6801789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * portion of the media.
6810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6821789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Either a surface holder or surface must be set if a display or video sink
6831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * is needed.  Not calling this method or {@link #setSurface(Surface)}
6841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * when playing back a video will result in only the audio track being played.
6851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A null surface holder or surface will result in only the audio track being
6861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * played.
6870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param sh the SurfaceHolder to use for video display
6891789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
6901789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized or has been released.
6911789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @hide
6920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6941789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setDisplay(SurfaceHolder sh) {
6951789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        mSurfaceHolder = sh;
6961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Surface surface;
6971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        if (sh != null) {
6981789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            surface = sh.getSurface();
6991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        } else {
7001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            surface = null;
701de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
7021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        _setVideoSurface(surface);
7031789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        updateSurfaceScreenOn();
7040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets the {@link Surface} to be used as the sink for the video portion of
7081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but
7091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * does not support {@link #setScreenOnWhilePlaying(boolean)}.  Setting a
7101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Surface will un-set any Surface or SurfaceHolder that was previously set.
7111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * A null surface will result in only the audio track being played.
7120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps
7141789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * returned from {@link SurfaceTexture#getTimestamp()} will have an
7151789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * unspecified zero point.  These timestamps cannot be directly compared
7161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * between different media sources, different instances of the same media
7171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * source, or multiple runs of the same program.  The timestamp is normally
7181789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * monotonically increasing and is unaffected by time-of-day adjustments,
7191789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * but it is reset when the position is set.
7200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param surface The {@link Surface} to be used for the video portion of
7221789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * the media.
7231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if the internal player engine has not been
7241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * initialized or has been released.
7250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
7260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
7271789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setSurface(Surface surface) {
72869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_SURFACE, false) {
72969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
73069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
73169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (mScreenOnWhilePlaying && surface != null) {
73269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
73369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
73469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                mSurfaceHolder = null;
73569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setVideoSurface(surface);
73669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                updateSurfaceScreenOn();
73769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
73869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
7390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7421789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Sets video scaling mode. To make the target video scaling mode
7431789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * effective during playback, this method must be called after
7441789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * data source is set. If not called, the default video
7451789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}.
7460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <p> The supported video scaling modes are:
7481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <ul>
7491789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}
7501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}
7511789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * </ul>
7520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @param mode target video scaling mode. Must be one of the supported
7541789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * video scaling modes; otherwise, IllegalArgumentException will be thrown.
7550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7561789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT
7571789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
7581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @hide
7590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
7600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
7611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setVideoScalingMode(int mode) {
76269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_VIDEO_SCALING_MODE, false) {
76369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
76469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
76569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (!isVideoScalingModeSupported(mode)) {
76669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    final String msg = "Scaling mode " + mode + " is not supported";
76769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    throw new IllegalArgumentException(msg);
76869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
76969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Parcel request = Parcel.obtain();
77069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Parcel reply = Parcel.obtain();
77169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                try {
77269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE);
77369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    request.writeInt(mode);
77469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    invoke(request, reply);
77569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                } finally {
77669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    request.recycle();
77769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    reply.recycle();
77869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
77969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
78069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
781de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    }
7820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7831789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
7841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Discards all pending commands.
7851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     */
7861789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
7871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void clearPendingCommands() {
7880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
79069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    private void addTask(Task task) {
79169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        synchronized (mTaskLock) {
79269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            mPendingTasks.add(task);
79369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            processPendingTask_l();
79469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        }
79569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    }
79669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
797adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    @GuardedBy("mTaskLock")
798adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    private void processPendingTask_l() {
799adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        if (mCurrentTask != null) {
800adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            return;
801adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        }
802adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        if (!mPendingTasks.isEmpty()) {
803adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            Task task = mPendingTasks.remove(0);
804adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            mCurrentTask = task;
805adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            mTaskHandler.post(task);
806adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        }
807adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    }
808adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
809cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId)
810de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException {
8110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
8120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (dsd.getType()) {
8140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_CALLBACK:
815de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
816cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                                 srcId,
817de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getMedia2DataSource());
8180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
8190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_FD:
821de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
822cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                                 srcId,
823de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getFileDescriptor(),
824de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getFileDescriptorOffset(),
825de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getFileDescriptorLength());
8260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
8270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_URI:
829de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
830cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                                 srcId,
831de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUriContext(),
832de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUri(),
833de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUriHeaders(),
834de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 dsd.getUriCookies());
8350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
8360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
8380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
8390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
8430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * To provide cookies for the subsequent HTTP requests, you can install your own default cookie
8440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * handler and use other variants of setDataSource APIs instead. Alternatively, you can use
8450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this API to pass the cookies as a list of HttpCookie. If the app has not installed
8460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a CookieHandler already, this API creates a CookieManager and populates its CookieStore with
8470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the provided cookies. If the app has installed its own handler already, this API requires the
8480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * handler to be of CookieManager type such that the API can update the manager’s CookieStore.
8490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
8500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p><strong>Note</strong> that the cross domain redirection is allowed by default,
8510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * but that can be changed with key/value pairs through the headers parameter with
8520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
8530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * disallow or allow cross domain redirection.
8540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
8550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if cookies are provided and the installed handler is not
8560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                  a CookieManager
8570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException    if it is called in an invalid state
8580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException     if context or uri is null
8590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException              if uri has a file scheme and an I/O error occurs
8600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
861de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(
862de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
863de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            @NonNull Context context, @NonNull Uri uri,
8640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
8650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
8660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // The context and URI usually belong to the calling user. Get a resolver for that user
8670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // and strip out the userId from the URI if present.
8680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final ContentResolver resolver = context.getContentResolver();
8690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String scheme = uri.getScheme();
8700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
8710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
872de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, uri.getPath(), null, null);
8730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
874de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
875de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
876de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        if (ContentResolver.SCHEME_CONTENT.equals(scheme)
8770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                && Settings.AUTHORITY.equals(authority)) {
8780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Try cached ringtone first since the actual provider may not be
8790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // encryption aware, or it may be stored on CE media storage
8800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int type = RingtoneManager.getDefaultType(uri);
8810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
8820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
883de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            if (attemptDataSource(isCurrent, srcId, resolver, cacheUri)) {
8840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
885de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            }
886de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            if (attemptDataSource(isCurrent, srcId, resolver, actualUri)) {
8870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
8880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
889de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
8900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
8910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Try requested Uri locally first, or fallback to media server
892de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            if (attemptDataSource(isCurrent, srcId, resolver, uri)) {
8930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
8940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
895de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
8960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
899de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private boolean attemptDataSource(
900de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId, ContentResolver resolver, Uri uri) {
9010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
9020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (afd.getDeclaredLength() < 0) {
903de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
904de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 srcId,
905de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getFileDescriptor(),
906de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 0,
907de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 DataSourceDesc.LONG_MAX);
9080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
909de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                handleDataSource(isCurrent,
910de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 srcId,
911de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getFileDescriptor(),
912de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getStartOffset(),
913de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                                 afd.getDeclaredLength());
9140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
9150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return true;
9160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (NullPointerException | SecurityException | IOException ex) {
9170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "Couldn't open " + uri + ": " + ex);
9180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return false;
9190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
922de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(
923de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
924de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            String path, Map<String, String> headers, List<HttpCookie> cookies)
925de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException {
9260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String[] keys = null;
9270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String[] values = null;
9280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (headers != null) {
9300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            keys = new String[headers.size()];
9310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            values = new String[headers.size()];
9320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
9340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (Map.Entry<String, String> entry: headers.entrySet()) {
9350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                keys[i] = entry.getKey();
9360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                values[i] = entry.getValue();
9370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                ++i;
9380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
9390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
940de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        handleDataSource(isCurrent, srcId, path, keys, values, cookies);
9410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
943de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(boolean isCurrent, long srcId,
944de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            String path, String[] keys, String[] values, List<HttpCookie> cookies)
945de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException {
9460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final Uri uri = Uri.parse(path);
9470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String scheme = uri.getScheme();
9480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ("file".equals(scheme)) {
9490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            path = uri.getPath();
9500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (scheme != null) {
9510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // handle non-file sources
952de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            nativeHandleDataSourceUrl(
953de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                isCurrent,
95434c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                srcId,
9550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Media2HTTPService.createHTTPService(path, cookies),
9560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                path,
9570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                keys,
9580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                values);
9590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
9600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final File file = new File(path);
9630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (file.exists()) {
9640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileInputStream is = new FileInputStream(file);
9650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileDescriptor fd = is.getFD();
966de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX);
9670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            is.close();
9680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
969de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throw new IOException("handleDataSource failed.");
9700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
973de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativeHandleDataSourceUrl(
974de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
975de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            Media2HTTPService httpService, String path, String[] keys, String[] values)
976de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            throws IOException;
9770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
9800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
9810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to close the file descriptor. It is safe to do so as soon as this call returns.
9820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
9840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if fd is not a valid FileDescriptor
9850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if fd can not be read
9860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
987de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(
988de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId,
989de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            FileDescriptor fd, long offset, long length) throws IOException {
990de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length);
9910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
993de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
994de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            FileDescriptor fd, long offset, long length) throws IOException;
9950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
9980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
9990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
1000de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource) {
1001de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        nativeHandleDataSourceCallback(isCurrent, srcId, dataSource);
10020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1004de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativeHandleDataSourceCallback(
1005de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            boolean isCurrent, long srcId, Media2DataSource dataSource);
10060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1007cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    // This function shall be called with |mSrcLock| acquired.
1008de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void prepareNextDataSource_l() {
1009cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia        if (mNextDSDs == null || mNextDSDs.isEmpty()
1010cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                || mNextSourceState != NEXT_SOURCE_STATE_INIT) {
1011de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            // There is no next source or it's in preparing or prepared state.
1012de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            return;
1013de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
10140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1015de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        try {
1016cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            mNextSourceState = NEXT_SOURCE_STATE_PREPARING;
1017cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            handleDataSource(false /* isCurrent */, mNextDSDs.get(0), mNextSrcId);
1018de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        } catch (Exception e) {
1019de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            Message msg2 = mEventHandler.obtainMessage(
1020de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
10211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            final long nextSrcId = mNextSrcId;
1022de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            mEventHandler.post(new Runnable() {
1023de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                @Override
1024de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                public void run() {
1025de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    mEventHandler.handleMessage(msg2, nextSrcId);
1026de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                }
1027de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            });
1028de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
1029de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    }
1030de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
1031cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    // This function shall be called with |mSrcLock| acquired.
1032de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private void playNextDataSource_l() {
1033cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia        if (mNextDSDs == null || mNextDSDs.isEmpty()) {
1034de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            return;
1035de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        }
1036de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
1037cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia        if (mNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
1038de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            // Switch to next source only when it's in prepared state.
1039cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            mCurrentDSD = mNextDSDs.get(0);
10401789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            mCurrentSrcId = mNextSrcId;
1041c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia            mBufferedPercentageCurrent.set(mBufferedPercentageNext.get());
1042cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            mNextDSDs.remove(0);
1043cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            mNextSrcId = mSrcIdGenerator++;  // make it different from mCurrentSrcId
1044c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia            mBufferedPercentageNext.set(0);
1045cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            mNextSourceState = NEXT_SOURCE_STATE_INIT;
1046cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            mNextSourcePlayPending = false;
1047de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
10481789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            long srcId = mCurrentSrcId;
1049de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            try {
1050de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                nativePlayNextDataSource(srcId);
1051de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            } catch (Exception e) {
1052de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                Message msg2 = mEventHandler.obtainMessage(
1053de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
1054de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                mEventHandler.post(new Runnable() {
1055de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    @Override
1056de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    public void run() {
1057de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        mEventHandler.handleMessage(msg2, srcId);
1058de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    }
1059de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                });
1060de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            }
1061de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
1062de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            // Wait for MEDIA2_INFO_STARTED_AS_NEXT to prepare next source.
1063de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia        } else {
1064cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            if (mNextSourceState == NEXT_SOURCE_STATE_INIT) {
1065de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                prepareNextDataSource_l();
1066de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia            }
1067cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            mNextSourcePlayPending = true;
10680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1071de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia    private native void nativePlayNextDataSource(long srcId);
10720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int getAudioStreamType() {
10750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
10760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mStreamType = _getAudioStreamType();
10770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mStreamType;
10790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native int _getAudioStreamType() throws IllegalStateException;
10820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Stops playback after playback has been started or paused.
10850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
10860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
10870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
10880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #hide
10890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
10910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void stop() {
10920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
10930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _stop();
10940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _stop() throws IllegalStateException;
10970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //--------------------------------------------------------------------------
10990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Explicit Routing
11000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //--------------------
11010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private AudioDeviceInfo mPreferredDevice = null;
11020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
11050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the output from this MediaPlayer2.
11060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
11070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  If deviceInfo is null, default routing is restored.
11080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
11090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * does not correspond to a valid audio device.
11100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
11120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
11130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (deviceInfo != null && !deviceInfo.isSink()) {
11140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return false;
11150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
11170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean status = native_setOutputDevice(preferredDeviceId);
11180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (status == true) {
11190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
11200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPreferredDevice = deviceInfo;
11210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return status;
11240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
11280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is not guaranteed to correspond to the actual device being used for playback.
11290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
11310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public AudioDeviceInfo getPreferredDevice() {
11320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (this) {
11330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mPreferredDevice;
11340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2
11390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note: The query is only valid if the MediaPlayer2 is currently playing.
11400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the player is not playing, the returned device can be null or correspond to previously
11410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * selected device when the player was last active.
11420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
11440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public AudioDeviceInfo getRoutedDevice() {
11450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int deviceId = native_getRoutedDeviceId();
11460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (deviceId == 0) {
11470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
11480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        AudioDeviceInfo[] devices =
11500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
11510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (int i = 0; i < devices.length; i++) {
11520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (devices[i].getId() == deviceId) {
11530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return devices[i];
11540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return null;
11570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
11600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
11610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
116257d03914a1d5680cfe0727c15a3a82e4dfeb0adeAndreas Gampe    @GuardedBy("mRoutingChangeListeners")
11630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void enableNativeRoutingCallbacksLocked(boolean enabled) {
11640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mRoutingChangeListeners.size() == 0) {
11650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            native_enableDeviceCallback(enabled);
11660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
11710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
11720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * by an app to receive (re)routing notifications.
11730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @GuardedBy("mRoutingChangeListeners")
11750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private ArrayMap<AudioRouting.OnRoutingChangedListener,
11760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
11770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
11790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
11800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * changes on this MediaPlayer2.
11810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
11820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notifications of rerouting events.
11830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
11840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the callback. If <code>null</code>, the handler on the main looper will be used.
11850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
11870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
11880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Handler handler) {
11890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mRoutingChangeListeners) {
11900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
11910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                enableNativeRoutingCallbacksLocked(true);
11920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRoutingChangeListeners.put(
11930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        listener, new NativeRoutingEventHandlerDelegate(this, listener,
11940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                handler != null ? handler : mEventHandler));
11950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
12010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to receive rerouting notifications.
12020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
12030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to remove.
12040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
12070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mRoutingChangeListeners) {
12080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mRoutingChangeListeners.containsKey(listener)) {
12090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRoutingChangeListeners.remove(listener);
12100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                enableNativeRoutingCallbacksLocked(false);
12110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
12120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final boolean native_setOutputDevice(int deviceId);
12160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_getRoutedDeviceId();
12170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_enableDeviceCallback(boolean enabled);
12180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set the low-level power management behavior for this MediaPlayer2.  This
12210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
12220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
12230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
12240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>This function has the MediaPlayer2 access the low-level power manager
12260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * service to control the device's power usage while playing is occurring.
12270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The parameter is a combination of {@link android.os.PowerManager} wake flags.
12280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
12290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * permission.
12300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * By default, no attempt is made to keep the device awake during playback.
12310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param context the Context to use
12330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode    the power/wake mode to set
12340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.os.PowerManager
12350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
12360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setWakeMode(Context context, int mode) {
12390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean washeld = false;
12400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* Disable persistant wakelocks in media player based on property */
12420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (SystemProperties.getBoolean("audio.offload.ignore_setawake", false) == true) {
12430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "IGNORING setWakeMode " + mode);
12440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
12450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mWakeLock != null) {
12480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mWakeLock.isHeld()) {
12490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                washeld = true;
12500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.release();
12510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
12520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mWakeLock = null;
12530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
12560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer2Impl.class.getName());
12570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mWakeLock.setReferenceCounted(false);
12580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (washeld) {
12590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mWakeLock.acquire();
12600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Control whether we should use the attached SurfaceHolder to keep the
12650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * screen on while video playback is occurring.  This is the preferred
12660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * method over {@link #setWakeMode} where possible, since it doesn't
12670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * require that the application have permission for low-level wake lock
12680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * access.
12690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param screenOn Supply true to keep the screen on, false to allow it
12710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to turn off.
12720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
12730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setScreenOnWhilePlaying(boolean screenOn) {
12760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mScreenOnWhilePlaying != screenOn) {
12770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (screenOn && mSurfaceHolder == null) {
12780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
12790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
12800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mScreenOnWhilePlaying = screenOn;
12810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            updateSurfaceScreenOn();
12820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void stayAwake(boolean awake) {
12860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mWakeLock != null) {
12870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (awake && !mWakeLock.isHeld()) {
12880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.acquire();
12890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else if (!awake && mWakeLock.isHeld()) {
12900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.release();
12910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
12920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mStayAwake = awake;
12940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
12950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void updateSurfaceScreenOn() {
12980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSurfaceHolder != null) {
12990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
13000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the width of the video.
13050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the width of the video, or 0 if there is no video,
13070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * no display surface was set, or the width has not been determined
13081789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * yet. The {@code MediaPlayer2EventCallback} can be registered via
13091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
13101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the width
13111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * is available.
13120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getVideoWidth();
13150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the height of the video.
13180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the height of the video, or 0 if there is no video,
13200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * no display surface was set, or the height has not been determined
13211789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * yet. The {@code MediaPlayer2EventCallback} can be registered via
13221789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #setMediaPlayer2EventCallback(Executor, MediaPlayer2EventCallback)} to provide a
13231789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * notification {@code MediaPlayer2EventCallback.onVideoSizeChanged} when the height
13241789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * is available.
13250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getVideoHeight();
13280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Return Metrics data about the current player.
13310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return a {@link PersistableBundle} containing the set of attributes and values
13330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * available for the media being handled by this instance of MediaPlayer2
13340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The attributes are descibed in {@link MetricsConstants}.
13350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  Additional vendor-specific fields may also be present in
13370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  the return value.
13380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public PersistableBundle getMetrics() {
13410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PersistableBundle bundle = native_getMetrics();
13420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return bundle;
13430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native PersistableBundle native_getMetrics();
13460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Checks whether the MediaPlayer2 is playing.
13490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if currently playing, false otherwise
13510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
13531789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @hide
13540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native boolean isPlaying();
13570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13581789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    @Override
13591789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public @MediaPlayer2State int getMediaPlayer2State() {
1360cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia        return native_getMediaPlayer2State();
13611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    }
13621789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
1363cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia    private native int native_getMediaPlayer2State();
1364cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia
13651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    /**
13660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the current buffering management params used by the source component.
13670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Calling it only after {@code setDataSource} has been called.
13680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Each type of data source might have different set of default params.
13690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the current buffering management params used by the source component.
13710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized, or {@code setDataSource} has not been called.
13730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
13740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
13770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native BufferingParams getBufferingParams();
13780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets buffering management params.
13810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The object sets its internal BufferingParams to the input, except that the input is
13820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * invalid or not supported.
13830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Call it only after {@code setDataSource} has been called.
13840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The input is a hint to MediaPlayer2.
13850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the buffering management params.
13870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released, or {@code setDataSource} has not been called.
13900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params is invalid or not supported.
13910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
13920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
139469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    public void setBufferingParams(@NonNull BufferingParams params) {
139569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_BUFFERING_PARAMS, false) {
139669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
139769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
139869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Preconditions.checkNotNull(params, "the BufferingParams cannot be null");
139969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setBufferingParams(params);
140069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
140169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
140269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    }
140369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
140469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    private native void _setBufferingParams(@NonNull BufferingParams params);
14050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets playback rate and audio mode.
14080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param rate the ratio between desired playback rate and normal one.
14100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param audioMode audio playback mode. Must be one of the supported
14110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * audio modes.
14120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
14140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
14150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if audioMode is not supported.
14160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
14180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
14210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public PlaybackParams easyPlaybackParams(float rate, @PlaybackRateAudioMode int audioMode) {
14220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PlaybackParams params = new PlaybackParams();
14230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        params.allowDefaults();
14240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (audioMode) {
14250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_DEFAULT:
14260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(1.0f);
14270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
14280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_STRETCH:
14290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(1.0f)
14300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    .setAudioFallbackMode(params.AUDIO_FALLBACK_MODE_FAIL);
14310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
14320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE:
14330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(rate);
14340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
14350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        default:
14360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Audio playback mode " + audioMode + " is not supported";
14370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
14380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return params;
14400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
14410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets playback rate using {@link PlaybackParams}. The object sets its internal
14440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * PlaybackParams to the input, except that the object remembers previous speed
14450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when input speed is zero. This allows the object to resume at previous speed
14460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when play() is called. Calling it before the object is prepared does not change
14470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the object state. After the object is prepared, calling it with zero speed is
14480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * equivalent to calling pause(). After the object is prepared, calling it with
14490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * non-zero speed is equivalent to calling play().
14500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the playback params.
14520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
14540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
14550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params is not supported.
14560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
145869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    public void setPlaybackParams(@NonNull PlaybackParams params) {
145969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) {
146069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
146169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
146269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Preconditions.checkNotNull(params, "the PlaybackParams cannot be null");
146369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setPlaybackParams(params);
146469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
146569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
146669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    }
146769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
146869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    private native void _setPlaybackParams(@NonNull PlaybackParams params);
14690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the playback params, containing the current playback rate.
14720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the playback params.
14740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
14750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
14760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
14790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native PlaybackParams getPlaybackParams();
14800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets A/V sync mode.
14830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the A/V sync params to apply
14850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
14870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
14880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params are not supported.
14890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
149169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    public void setSyncParams(@NonNull SyncParams params) {
149269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_SYNC_PARAMS, false) {
149369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
149469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
149569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Preconditions.checkNotNull(params, "the SyncParams cannot be null");
149669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setSyncParams(params);
149769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
149869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
149969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    }
150069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
150169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    private native void _setSyncParams(@NonNull SyncParams params);
15020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the A/V sync mode.
15050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the A/V sync params
15070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
15090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
15100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
15130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native SyncParams getSyncParams();
15140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Moves the media to specified time position by considering the given mode.
15170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
15180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When seekTo is finished, the user will be notified via OnSeekComplete supplied by the user.
15190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * There is at most one active seekTo processed at any time. If there is a to-be-completed
15200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * seekTo, new seekTo requests will be queued in such a way that only the last request
15210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is kept. When current seekTo is completed, the queued request will be processed if
15220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that request is different from just-finished seekTo operation, i.e., the requested
15230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * position or mode is different.
15240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param msec the offset in milliseconds from the start to seek to.
15260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When seeking to the given time position, there is no guarantee that the data source
15270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * has a frame located at the position. When this happens, a frame nearby will be rendered.
15280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If msec is negative, time position zero will be used.
15290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If msec is larger than duration, duration will be used.
15300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode the mode indicating where exactly to seek to.
15310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame
15320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp earlier than or the same as msec. Use
15330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame
15340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp later than or the same as msec. Use
15350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame
15360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp closest to or the same as msec. Use
15370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may
15380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * or may not be a sync frame but is closest to or the same as msec.
15390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST} often has larger performance overhead compared
15400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to the other options if there is no sync frame located at msec.
15410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
15420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized
15430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mode is invalid.
15440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
154669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    public void seekTo(final long msec, @SeekMode int mode) {
154769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SEEK_TO, true) {
154869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
154969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
155069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
155169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    final String msg = "Illegal seek mode: " + mode;
155269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    throw new IllegalArgumentException(msg);
155369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
155469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                // TODO: pass long to native, instead of truncating here.
155569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                long posMs = msec;
155669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                if (posMs > Integer.MAX_VALUE) {
155769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    Log.w(TAG, "seekTo offset " + posMs + " is too large, cap to "
155869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                            + Integer.MAX_VALUE);
155969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    posMs = Integer.MAX_VALUE;
156069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                } else if (posMs < Integer.MIN_VALUE) {
156169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    Log.w(TAG, "seekTo offset " + posMs + " is too small, cap to "
156269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                            + Integer.MIN_VALUE);
156369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    posMs = Integer.MIN_VALUE;
156469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
156569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _seekTo(posMs, mode);
156669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
156769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
15680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15701789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private native final void _seekTo(long msec, int mode);
15711789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia
15720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Get current playback position as a {@link MediaTimestamp}.
15740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
15750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The MediaTimestamp represents how the media time correlates to the system time in
15760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a linear fashion using an anchor and a clock rate. During regular playback, the media
15770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * time moves fairly constantly (though the anchor frame may be rebased to a current
15780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * system time, the linear correlation stays steady). Therefore, this method does not
15790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * need to be called often.
15800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
15810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * To help users get current playback position, this method always anchors the timestamp
15820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to the current {@link System#nanoTime system time}, so
15830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
15840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
15860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *         is available, e.g. because the media player has not been initialized.
15870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see MediaTimestamp
15890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Nullable
15920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaTimestamp getTimestamp()
15930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
15940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
15950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // TODO: get the timestamp from native side
15960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new MediaTimestamp(
15970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    getCurrentPosition() * 1000L,
15980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    System.nanoTime(),
15990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    isPlaying() ? getPlaybackParams().getSpeed() : 0.f);
16000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (IllegalStateException e) {
16010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
16020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
16030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
16040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the media metadata.
16070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param update_only controls whether the full set of available
16090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * metadata is returned or just the set that changed since the
16100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
16110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #METADATA_ALL}.
16120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param apply_filter if true only metadata that matches the
16140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
16150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #BYPASS_METADATA_FILTER}.
16160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The metadata, possibly empty. null if an error occured.
16180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     // FIXME: unhide.
16190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
16200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public Metadata getMetadata(final boolean update_only,
16230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                final boolean apply_filter) {
16240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
16250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Metadata data = new Metadata();
16260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!native_getMetadata(update_only, apply_filter, reply)) {
16280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
16290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
16300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
16310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Metadata takes over the parcel, don't recycle it unless
16330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // there is an error.
16340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!data.parse(reply)) {
16350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
16360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
16370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
16380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return data;
16390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
16400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set a filter for the metadata update notification and update
16430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * retrieval. The caller provides 2 set of metadata keys, allowed
16440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and blocked. The blocked set always takes precedence over the
16450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * allowed one.
16460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
16470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * shorthands to allow/block all or no metadata.
16480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * By default, there is no filter set.
16500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param allow Is the set of metadata the client is interested
16520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *              in receiving new notifications for.
16530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param block Is the set of metadata the client is not interested
16540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *              in receiving new notifications for.
16550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The call status code.
16560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     // FIXME: unhide.
16580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
16590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
16620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Do our serialization manually instead of calling
16630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Parcel.writeArray since the sets are made of the same type
16640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // we avoid paying the price of calling writeValue (used by
16650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // writeArray) which burns an extra int per element to encode
16660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the type.
16670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request =  newRequest();
16680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // The parcel starts already with an interface token. There
16700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // are 2 filters. Each one starts with a 4bytes number to
16710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // store the len followed by a number of int (4 bytes as well)
16720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // representing the metadata type.
16730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
16740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (request.dataCapacity() < capacity) {
16760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.setDataCapacity(capacity);
16770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
16780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        request.writeInt(allow.size());
16800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for(Integer t: allow) {
16810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(t);
16820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
16830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        request.writeInt(block.size());
16840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for(Integer t: block) {
16850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(t);
16860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
16870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return native_setMetadataFilter(request);
16880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
16890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Resets the MediaPlayer2 to its uninitialized state. After calling
16920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method, you will have to initialize it again by setting the
16931789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * data source and calling prepare().
16940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void reset() {
16970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSelectedSubtitleTrackIndex = -1;
16980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized(mOpenSubtitleSources) {
16990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (final InputStream is: mOpenSubtitleSources) {
17000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
17010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    is.close();
17020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (IOException e) {
17030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
17040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
17050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mOpenSubtitleSources.clear();
17060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null) {
17080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.reset();
17090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider != null) {
17110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider.close();
17120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = null;
17130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
171563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        synchronized (mEventCbLock) {
171663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.clear();
171763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        }
171863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        synchronized (mDrmEventCbLock) {
171963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.clear();
172063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        }
172163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
17220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
17230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _reset();
17240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // make sure none of the listeners get called anymore
17250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mEventHandler != null) {
17260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeCallbacksAndMessages(null);
17270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
17300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mIndexTrackPairs.clear();
17310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mInbandTrackIndices.clear();
17320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        };
17330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        resetDrmState();
17350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
17360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _reset();
17380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
17410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notified when the presentation time reaches (becomes greater than or equal to)
17420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the value specified.
17430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mediaTimeUs presentation time to get timed event callback at
17450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
17460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
17480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void notifyAt(long mediaTimeUs) {
17490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _notifyAt(mediaTimeUs);
17500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
17510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _notifyAt(long mediaTimeUs);
17530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Keep KEY_PARAMETER_* in sync with include/media/mediaplayer2.h
17550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
17560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the parameter indicated by key.
17580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param key key indicates the parameter to be set.
17590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param value value of the parameter to be set.
17600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if the parameter is set successfully, false otherwise
17610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native boolean setParameter(int key, Parcel value);
17630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1764128875996598b9cfa91bad137d3a73dfcb4a2aedWei Jia    private native Parcel getParameter(int key);
1765128875996598b9cfa91bad137d3a73dfcb4a2aedWei Jia
17660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Checks whether the MediaPlayer2 is looping or non-looping.
17690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if the MediaPlayer2 is currently looping, false otherwise
17710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
17720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
17740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native boolean isLooping();
17750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the audio session ID.
17780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param sessionId the audio session ID.
17800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The audio session ID is a system wide unique identifier for the audio stream played by
17810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this MediaPlayer2 instance.
17820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The primary use of the audio session ID  is to associate audio effects to a particular
17830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * instance of MediaPlayer2: if an audio session ID is provided when creating an audio effect,
17840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this effect will be applied only to the audio content of media players within the same
17850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * audio session and not to the output mix.
17860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When created, a MediaPlayer2 instance automatically generates its own audio session ID.
17870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * However, it is possible to force this player to be part of an already existing audio session
17880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * by calling this method.
17890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This method must be called before one of the overloaded <code> setDataSource </code> methods.
17900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
17910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the sessionId is invalid.
17920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
179469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    public void setAudioSessionId(int sessionId) {
179569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_AUDIO_SESSION_ID, false) {
179669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
179769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
179869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setAudioSessionId(sessionId);
179969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
180069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
180169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    }
180269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
180369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    private native void _setAudioSessionId(int sessionId);
18040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the audio session ID.
18070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the audio session ID. {@see #setAudioSessionId(int)}
18090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was contructed.
18100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
18120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getAudioSessionId();
18130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Attaches an auxiliary effect to the player. A typical auxiliary effect is a reverberation
18160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * effect which can be applied on any sound source that directs a certain amount of its
18170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * energy to this effect. This amount is defined by setAuxEffectSendLevel().
18180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * See {@link #setAuxEffectSendLevel(float)}.
18190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>After creating an auxiliary effect (e.g.
18200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with
18210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling this method
18220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to attach the player to the effect.
18230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>To detach the effect from the player, call this method with a null effect id.
18240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>This method must be called after one of the overloaded <code> setDataSource </code>
18250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * methods.
18260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param effectId system wide unique id of the effect to attach
18270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
182969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    public void attachAuxEffect(int effectId) {
183069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_ATTACH_AUX_EFFECT, false) {
183169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
183269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
183369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _attachAuxEffect(effectId);
183469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
183569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
183669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    }
183769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
183869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang    private native void _attachAuxEffect(int effectId);
18390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the send level of the player to the attached auxiliary effect.
18420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
18430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>By default the send level is 0, so even if an effect is attached to the player
18440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method must be called for the effect to be applied.
18450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
18460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
18470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * so an appropriate conversion from linear UI input x to level is:
18480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * x == 0 -> level = 0
18490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
18500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param level send level scalar
18510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
18530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setAuxEffectSendLevel(float level) {
185469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL, false) {
185569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
185669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
185769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                _setAuxEffectSendLevel(level);
185869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
185969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
18600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
18610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _setAuxEffectSendLevel(float level);
18630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
18650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param request Parcel destinated to the media player.
18660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param reply[out] Parcel that will contain the reply.
18670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
18680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_invoke(Parcel request, Parcel reply);
18700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
18730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param update_only If true fetch only the set of metadata that have
18740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    changed since the last invocation of getMetadata.
18750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    The set is built using the unfiltered
18760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    notifications the native player sent to the
18770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    MediaPlayer2Manager during that period of
18780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    time. If false, all the metadatas are considered.
18790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param apply_filter  If true, once the metadata set has been built based on
18800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                     the value update_only, the current filter is applied.
18810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param reply[out] On return contains the serialized
18820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                   metadata. Valid only if the call was successful.
18830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
18840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final boolean native_getMetadata(boolean update_only,
18860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                    boolean apply_filter,
18870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                    Parcel reply);
18880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
18900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param request Parcel with the 2 serialized lists of allowed
18910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                metadata types followed by the one to be
18920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                dropped. Each list starts with an integer
18930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                indicating the number of metadata type elements.
18940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
18950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_setMetadataFilter(Parcel request);
18970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static native final void native_init();
18990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_setup(Object mediaplayer2_this);
19000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_finalize();
19010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19028e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onTearDown(
19038e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long nativeCallbackPtr, long userDataPtr);
19048e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onStreamPresentationEnd(
19058e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long nativeCallbackPtr, long userDataPtr);
19068e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onStreamDataRequest(
19078e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr);
19088e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
19090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
19100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Class for MediaPlayer2 to return each audio/video/subtitle track's metadata.
19110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
19120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
19130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
19140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class TrackInfoImpl extends TrackInfo {
19150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
19160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the track type.
19170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @return TrackType which indicates if the track is video, audio, timed text.
19180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
19190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
19200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public int getTrackType() {
19210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mTrackType;
19220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
19250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the language code of the track.
19260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @return a language code in either way of ISO-639-1 or ISO-639-2.
19270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * When the language is unknown or could not be determined,
19280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * ISO-639-2 language code, "und", is returned.
19290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
19300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
19310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public String getLanguage() {
19320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String language = mFormat.getString(MediaFormat.KEY_LANGUAGE);
19330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return language == null ? "und" : language;
19340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
19370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the {@link MediaFormat} of the track.  If the format is
19380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * unknown or could not be determined, null is returned.
19390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
19400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
19410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public MediaFormat getFormat() {
19420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
19430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
19440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return mFormat;
19450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
19460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
19470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final int mTrackType;
19500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat mFormat;
19510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl(Parcel in) {
19530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTrackType = in.readInt();
19540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat
19550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // even for audio/video tracks, meaning we only set the mime and language.
19560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String mime = in.readString();
19570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String language = in.readString();
19580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mFormat = MediaFormat.createSubtitleFormat(mime, language);
19590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
19610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
19620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
19630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
19640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
19650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
19680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl(int type, MediaFormat format) {
19690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTrackType = type;
19700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mFormat = format;
19710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
19740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Flatten this object in to a Parcel.
19750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         *
19760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @param dest The Parcel in which the object should be written.
19770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @param flags Additional flags about how the object should be written.
19780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * May be 0 or {@link android.os.Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
19790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
19800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* package private */ void writeToParcel(Parcel dest, int flags) {
19810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dest.writeInt(mTrackType);
19820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dest.writeString(getLanguage());
19830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
19850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
19860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
19870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
19880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
19890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
19900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
19930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public String toString() {
19940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            StringBuilder out = new StringBuilder(128);
19950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append(getClass().getName());
19960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append('{');
19970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            switch (mTrackType) {
19980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_VIDEO:
19990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("VIDEO");
20000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
20010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_AUDIO:
20020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("AUDIO");
20030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
20040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_TIMEDTEXT:
20050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("TIMEDTEXT");
20060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
20070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_SUBTITLE:
20080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("SUBTITLE");
20090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
20100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
20110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("UNKNOWN");
20120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
20130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append(", " + mFormat.toString());
20150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append("}");
20160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return out.toString();
20170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
20200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Used to read a TrackInfoImpl from a Parcel.
20210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
20220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* package private */ static final Parcelable.Creator<TrackInfoImpl> CREATOR
20230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                = new Parcelable.Creator<TrackInfoImpl>() {
20240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
20250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public TrackInfoImpl createFromParcel(Parcel in) {
20260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return new TrackInfoImpl(in);
20270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
20280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
20300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public TrackInfoImpl[] newArray(int size) {
20310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return new TrackInfoImpl[size];
20320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
20330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                };
20340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };
20360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // We would like domain specific classes with more informative names than the `first` and `second`
20380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
20390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // we document the meanings of `first` and `second` here:
20400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //
20410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Pair.first - inband track index; non-null iff representing an inband track.
20420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
20430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //               an inband subtitle track or any out-of-band track (subtitle or timedtext).
20440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
20450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private BitSet mInbandTrackIndices = new BitSet();
20460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns a List of track information.
20490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
20500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return List of track info. The total number of tracks is the array length.
20510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Must be called again if an external timed text source has been added after
20520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * addTimedTextSource method is called.
20530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state.
20540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public List<TrackInfo> getTrackInfo() {
20570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl trackInfo[] = getInbandTrackInfoImpl();
20580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // add out-of-band tracks
20590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
20600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            TrackInfoImpl allTrackInfo[] = new TrackInfoImpl[mIndexTrackPairs.size()];
20610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < allTrackInfo.length; i++) {
20620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
20630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (p.first != null) {
20640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // inband track
20650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    allTrackInfo[i] = trackInfo[p.first];
20660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
20670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleTrack track = p.second;
20680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    allTrackInfo[i] = new TrackInfoImpl(track.getTrackType(), track.getFormat());
20690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
20700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
20710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return Arrays.asList(allTrackInfo);
20720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
20740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException {
20760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
20770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
20780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
20790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(INVOKE_ID_GET_TRACK_INFO);
20800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
20810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            TrackInfoImpl trackInfo[] = reply.createTypedArray(TrackInfoImpl.CREATOR);
20820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return trackInfo;
20830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
20840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
20850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
20860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
20880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
20900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A helper function to check if the mime type is supported by media framework.
20910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static boolean availableMimeTypeForExternalSource(String mimeType) {
20930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (MEDIA_MIMETYPE_TEXT_SUBRIP.equals(mimeType)) {
20940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return true;
20950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return false;
20970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
20980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private SubtitleController mSubtitleController;
21000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
21020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
21030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setSubtitleAnchor(
21040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleController controller,
21050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleController.Anchor anchor) {
21060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: create SubtitleController in MediaPlayer2
21070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController = controller;
21080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController.setAnchor(anchor);
21090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
21100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
21120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The private version of setSubtitleAnchor is used internally to set mSubtitleController if
21130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * necessary when clients don't provide their own SubtitleControllers using the public version
21140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #setSubtitleAnchor(SubtitleController, Anchor)} (e.g. {@link VideoView} provides one).
21150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private synchronized void setSubtitleAnchor() {
21170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
21180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
21190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            thread.start();
21200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Handler handler = new Handler(thread.getLooper());
21210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            handler.post(new Runnable() {
21220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                @Override
21230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                public void run() {
21240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Context context = ActivityThread.currentApplication();
21250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer2Impl.this);
21260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSubtitleController.setAnchor(new Anchor() {
21270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        @Override
21280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        public void setSubtitleWidget(RenderingWidget subtitleWidget) {
21290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
21300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        @Override
21320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        public Looper getSubtitleLooper() {
21330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            return Looper.getMainLooper();
21340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
21350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    });
21360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    thread.getLooper().quitSafely();
21370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
21380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            });
21390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
21400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.join();
21410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (InterruptedException e) {
21420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Thread.currentThread().interrupt();
21430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "failed to join SetSubtitleAnchorThread");
21440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
21450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
21470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mSelectedSubtitleTrackIndex = -1;
21490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private Vector<InputStream> mOpenSubtitleSources;
21500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() {
21520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
21530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
21540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int index = data.getTrackIndex();
21550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
21560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
21570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p.first != null && p.first == index && p.second != null) {
21580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // inband subtitle track that owns data
21590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        SubtitleTrack track = p.second;
21600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        track.onData(data);
21610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
21620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
21630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
21640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };
21660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
21680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
21690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void onSubtitleTrackSelected(SubtitleTrack track) {
21700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSelectedSubtitleTrackIndex >= 0) {
21710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
21720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
21730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
21740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
21750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSelectedSubtitleTrackIndex = -1;
21760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setOnSubtitleDataListener(null);
21780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track == null) {
21790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
21800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
21830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
21840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (p.first != null && p.second == track) {
21850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // inband subtitle track that is selected
21860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSelectedSubtitleTrackIndex = p.first;
21870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
21880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
21890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
21900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSelectedSubtitleTrackIndex >= 0) {
21930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
21940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
21950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
21960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
21970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setOnSubtitleDataListener(mSubtitleDataListener);
21980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // no need to select out-of-band tracks
22000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
22010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
22030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
22040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addSubtitleSource(InputStream is, MediaFormat format)
22050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException
22060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
22070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final InputStream fIs = is;
22080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat fFormat = format;
22090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (is != null) {
22110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Ensure all input streams are closed.  It is also a handy
22120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // way to implement timeouts in the future.
22130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(mOpenSubtitleSources) {
22140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mOpenSubtitleSources.add(is);
22150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
22170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "addSubtitleSource called with null InputStream");
22180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        getMediaTimeProvider();
22210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // process each subtitle in its own thread
22230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final HandlerThread thread = new HandlerThread("SubtitleReadThread",
22240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia              Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
22250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        thread.start();
22260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Handler handler = new Handler(thread.getLooper());
22270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        handler.post(new Runnable() {
22280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            private int addTrack() {
22290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (fIs == null || mSubtitleController == null) {
22300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
22310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
22320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                SubtitleTrack track = mSubtitleController.addTrack(fFormat);
22340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (track == null) {
22350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
22360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
22370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // TODO: do the conversion in the subtitle track
22390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Scanner scanner = new Scanner(fIs, "UTF-8");
22400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                String contents = scanner.useDelimiter("\\A").next();
22410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized(mOpenSubtitleSources) {
22420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mOpenSubtitleSources.remove(fIs);
22430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
22440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scanner.close();
22450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mIndexTrackPairs) {
22460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
22470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
22480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Handler h = mTimeProvider.mEventHandler;
22490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int what = TimeProvider.NOTIFY;
22500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
22510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, contents.getBytes());
22520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Message m = h.obtainMessage(what, arg1, 0, trackData);
22530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                h.sendMessage(m);
22540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
22550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void run() {
22580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int res = addTrack();
22590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mEventHandler != null) {
22600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
22610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mEventHandler.sendMessage(m);
22620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
22630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.getLooper().quitSafely();
22640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        });
22660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
22670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void scanInternalSubtitleTracks() {
22690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setSubtitleAnchor();
22700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        populateInbandTracks();
22720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null) {
22740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.selectDefaultTrack();
22750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
22770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void populateInbandTracks() {
22790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl[] tracks = getInbandTrackInfoImpl();
22800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
22810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < tracks.length; i++) {
22820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mInbandTrackIndices.get(i)) {
22830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    continue;
22840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
22850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mInbandTrackIndices.set(i);
22860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
22870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // newly appeared inband track
22890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
22900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleTrack track = mSubtitleController.addTrack(
22910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            tracks[i].getFormat());
22920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.create(i, track));
22930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
22940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
22950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
22960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
22990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /* TODO: Limit the total number of external timed text source to a reasonable number.
23010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
23030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file.
23040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip with the file extension .srt, case insensitive.
23060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that a single external timed text source may contain multiple tracks in it.
23070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
23080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * additional tracks become available after this method call.
23090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param path The file path of external timed text source file.
23110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
23120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if the file cannot be accessed or is corrupted.
23130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
23140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
23150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
23160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
23180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(String path, String mimeType)
23190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
23200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!availableMimeTypeForExternalSource(mimeType)) {
23210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Illegal mimeType for timed text source: " + mimeType;
23220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
23230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        File file = new File(path);
23260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (file.exists()) {
23270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileInputStream is = new FileInputStream(file);
23280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileDescriptor fd = is.getFD();
23290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(fd, mimeType);
23300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            is.close();
23310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
23320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // We do not support the case where the path is not a file.
23330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IOException(path);
23340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
23360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
23390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file (Uri).
23400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip with the file extension .srt, case insensitive.
23420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that a single external timed text source may contain multiple tracks in it.
23430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
23440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * additional tracks become available after this method call.
23450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param context the Context to use when resolving the Uri
23470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param uri the Content URI of the data you want to play
23480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
23490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if the file cannot be accessed or is corrupted.
23500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
23510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
23520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
23530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
23550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(Context context, Uri uri, String mimeType)
23560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
23570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String scheme = uri.getScheme();
23580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if(scheme == null || scheme.equals("file")) {
23590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(uri.getPath(), mimeType);
23600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
23610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        AssetFileDescriptor fd = null;
23640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
23650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            ContentResolver resolver = context.getContentResolver();
23660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            fd = resolver.openAssetFileDescriptor(uri, "r");
23670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (fd == null) {
23680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
23690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
23700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(fd.getFileDescriptor(), mimeType);
23710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
23720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (SecurityException ex) {
23730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (IOException ex) {
23740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
23750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (fd != null) {
23760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                fd.close();
23770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
23780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
23800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
23820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file (FileDescriptor).
23830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is the caller's responsibility to close the file descriptor.
23850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is safe to do so as soon as this call returns.
23860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip. Note that a single external timed text source may
23880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain multiple tracks in it. One can find the total number of available tracks
23890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * using {@link #getTrackInfo()} to see what additional tracks become available
23900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * after this method call.
23910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param fd the FileDescriptor for the file you want to play
23930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
23940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
23950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
23960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
23970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
23990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(FileDescriptor fd, String mimeType) {
24000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // intentionally less than LONG_MAX
24010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        addTimedTextSource(fd, 0, 0x7ffffffffffffffL, mimeType);
24020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
24030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
24050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text file (FileDescriptor).
24060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
24070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is the caller's responsibility to close the file descriptor.
24080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is safe to do so as soon as this call returns.
24090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
24100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip. Note that a single external timed text source may
24110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain multiple tracks in it. One can find the total number of available tracks
24120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * using {@link #getTrackInfo()} to see what additional tracks become available
24130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * after this method call.
24140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
24150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param fd the FileDescriptor for the file you want to play
24160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param offset the offset into the file where the data to be played starts, in bytes
24170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param length the length in bytes of the data to be played
24180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mime The mime type of the file. Must be one of the mime types listed above.
24190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
24200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
24210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
24220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
24230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
24240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime) {
24250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!availableMimeTypeForExternalSource(mime)) {
24260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mime);
24270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final FileDescriptor dupedFd;
24300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
24310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dupedFd = Os.dup(fd);
24320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (ErrnoException ex) {
24330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, ex.getMessage(), ex);
24340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new RuntimeException(ex);
24350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat fFormat = new MediaFormat();
24380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        fFormat.setString(MediaFormat.KEY_MIME, mime);
24390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        fFormat.setInteger(MediaFormat.KEY_IS_TIMED_TEXT, 1);
24400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // A MediaPlayer2 created by a VideoView should already have its mSubtitleController set.
24420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController == null) {
24430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setSubtitleAnchor();
24440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!mSubtitleController.hasRendererFor(fFormat)) {
24470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // test and add not atomic
24480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Context context = ActivityThread.currentApplication();
24490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler));
24500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
24520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
24530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
24540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        getMediaTimeProvider();
24570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final long offset2 = offset;
24590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final long length2 = length;
24600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final HandlerThread thread = new HandlerThread(
24610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                "TimedTextReadThread",
24620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
24630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        thread.start();
24640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Handler handler = new Handler(thread.getLooper());
24650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        handler.post(new Runnable() {
24660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            private int addTrack() {
24670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final ByteArrayOutputStream bos = new ByteArrayOutputStream();
24680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
24690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
24700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    byte[] buffer = new byte[4096];
24710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (long total = 0; total < length2;) {
24720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        int bytesToRead = (int) Math.min(buffer.length, length2 - total);
24730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        int bytes = IoBridge.read(dupedFd, buffer, 0, bytesToRead);
24740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (bytes < 0) {
24750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            break;
24760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        } else {
24770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            bos.write(buffer, 0, bytes);
24780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            total += bytes;
24790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
24800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
24810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Handler h = mTimeProvider.mEventHandler;
24820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    int what = TimeProvider.NOTIFY;
24830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
24840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, bos.toByteArray());
24850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = h.obtainMessage(what, arg1, 0, trackData);
24860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    h.sendMessage(m);
24870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
24880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
24890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.e(TAG, e.getMessage(), e);
24900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_TIMED_TEXT_ERROR;
24910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } finally {
24920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    try {
24930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Os.close(dupedFd);
24940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    } catch (ErrnoException e) {
24950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, e.getMessage(), e);
24960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
24970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
24980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void run() {
25010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int res = addTrack();
25020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mEventHandler != null) {
25030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
25040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mEventHandler.sendMessage(m);
25050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.getLooper().quitSafely();
25070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
25080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        });
25090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
25120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the index of the audio, video, or subtitle track currently selected for playback,
25130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The return value is an index into the array returned by {@link #getTrackInfo()}, and can
25140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * be used in calls to {@link #selectTrack(int)} or {@link #deselectTrack(int)}.
25150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
25160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
25170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
25180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
25190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return index of the audio, video, or subtitle track currently selected for playback;
25200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a negative integer is returned when there is no selected track for {@code trackType} or
25210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when {@code trackType} is not one of audio, video, or subtitle.
25220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called after {@link #close()}
25230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
25240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #getTrackInfo()
25250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #selectTrack(int)
25260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #deselectTrack(int)
25270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
25280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
25290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int getSelectedTrack(int trackType) {
25300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null
25310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
25320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
25330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
25340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (subtitleTrack != null) {
25350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mIndexTrackPairs) {
25360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (int i = 0; i < mIndexTrackPairs.size(); i++) {
25370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
25380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
25390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            return i;
25400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
25410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
25420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
25440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
25470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
25480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
25490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(INVOKE_ID_GET_SELECTED_TRACK);
25500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(trackType);
25510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
25520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int inbandTrackIndex = reply.readInt();
25530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
25540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (int i = 0; i < mIndexTrackPairs.size(); i++) {
25550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
25560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p.first != null && p.first == inbandTrackIndex) {
25570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return i;
25580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
25590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
25610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return -1;
25620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
25630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
25640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
25650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
25690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Selects a track.
25700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
25710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is in invalid state, it throws an IllegalStateException exception.
25720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is in <em>Started</em> state, the selected track is presented immediately.
25730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is not in Started state, it just marks the track to be played.
25740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
25750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
25760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * In any valid state, if it is called multiple times on the same type of track (ie. Video,
25770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Audio, Timed Text), the most recent one will be chosen.
25780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
25790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
25800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The first audio and video tracks are selected by default if available, even though
25810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method is not called. However, no timed text track will be selected until
25820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this function is called.
25830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
25840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
25850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently, only timed text tracks or audio tracks can be selected via this method.
25860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * In addition, the support for selecting an audio track at runtime is pretty limited
25870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in that an audio track can only be selected in the <em>Prepared</em> state.
25880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
25890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of the track to be selected. The valid range of the index
25900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is 0..total number of track - 1. The total number of tracks as well as the type of
25910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * each individual track can be found by calling {@link #getTrackInfo()} method.
25920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
25930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
25940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
25950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
25960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
25970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void selectTrack(int index) {
259869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_SELECT_TRACK, false) {
259969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
260069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
260169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                selectOrDeselectTrack(index, true /* select */);
260269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
260369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
26040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
26050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
26070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Deselect a track.
26080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
26090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently, the track must be a timed text track and no audio or video tracks can be
26100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * deselected. If the timed text track identified by index has not been
26110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * selected before, it throws an exception.
26120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
26130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of the track to be deselected. The valid range of the index
26140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
26150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * each individual track can be found by calling {@link #getTrackInfo()} method.
26160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
26170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
26190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
26200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
26210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void deselectTrack(int index) {
262269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_DESELECT_TRACK, false) {
262369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
262469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() {
262569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                selectOrDeselectTrack(index, false /* select */);
262669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
262769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
26280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
26290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void selectOrDeselectTrack(int index, boolean select)
26310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException {
26320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // handle subtitle track through subtitle controller
26330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        populateInbandTracks();
26340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Pair<Integer,SubtitleTrack> p = null;
26360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
26370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            p = mIndexTrackPairs.get(index);
26380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (ArrayIndexOutOfBoundsException e) {
26390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // ignore bad index
26400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
26410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        SubtitleTrack track = p.second;
26440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track == null) {
26450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // inband (de)select
26460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            selectOrDeselectInbandTrack(p.first, select);
26470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
26480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController == null) {
26510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
26520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!select) {
26550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // out-of-band deselect
26560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSubtitleController.getSelectedTrack() == track) {
26570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSubtitleController.selectTrack(null);
26580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
26590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "trying to deselect track that was not selected");
26600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
26610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
26620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // out-of-band select
26650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
26660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
26670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
26680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
26690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
26700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p2.first != null && p2.second == null) {
26710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // deselect inband counterpart
26720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        selectOrDeselectInbandTrack(p2.first, false);
26730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
26740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
26750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
26760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController.selectTrack(track);
26780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
26790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void selectOrDeselectInbandTrack(int index, boolean select)
26810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException {
26820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
26830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
26840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
26850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK);
26860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(index);
26870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
26880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
26890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
26900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
26910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
26930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Have to declare protected for finalize() since it is protected
26950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // in the base class Object.
26960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
26970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    protected void finalize() throws Throwable {
26980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mGuard != null) {
26990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mGuard.warnIfOpen();
27000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        close();
27030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_finalize();
27040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
27050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void release() {
27070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
27080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
27090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
271063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.clear();
27110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
2712adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        if (mHandlerThread != null) {
2713adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            mHandlerThread.quitSafely();
2714adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            mHandlerThread = null;
2715adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        }
27160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider != null) {
27170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider.close();
27180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = null;
27190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnSubtitleDataListener = null;
27210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Modular DRM clean up
27230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnDrmConfigHelper = null;
27240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
272563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.clear();
27260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        resetDrmState();
27280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _release();
27300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
27310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _release();
27330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /* Do not change these values without updating their counterparts
27350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in include/media/mediaplayer2.h!
27360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
27370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_NOP = 0; // interface test message
27380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PREPARED = 1;
27390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PLAYBACK_COMPLETE = 2;
27400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_BUFFERING_UPDATE = 3;
27410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SEEK_COMPLETE = 4;
27420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SET_VIDEO_SIZE = 5;
27430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_STARTED = 6;
27440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PAUSED = 7;
27450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_STOPPED = 8;
27460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SKIPPED = 9;
27470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_NOTIFY_TIME = 98;
27480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_TIMED_TEXT = 99;
27490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_ERROR = 100;
27500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_INFO = 200;
27510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SUBTITLE_DATA = 201;
27520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_META_DATA = 202;
27530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_DRM_INFO = 210;
27540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
27550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private TimeProvider mTimeProvider;
27570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
27590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
27600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaTimeProvider getMediaTimeProvider() {
27610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider == null) {
27620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = new TimeProvider(this);
27630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mTimeProvider;
27650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
27660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private class EventHandler extends Handler {
27680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mMediaPlayer;
27690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public EventHandler(MediaPlayer2Impl mp, Looper looper) {
27710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(looper);
27720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mMediaPlayer = mp;
27730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
27760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void handleMessage(Message msg) {
277734c5bb126b8cc85176645acea841c796a3cc0292Wei Jia            handleMessage(msg, 0);
277834c5bb126b8cc85176645acea841c796a3cc0292Wei Jia        }
277934c5bb126b8cc85176645acea841c796a3cc0292Wei Jia
278034c5bb126b8cc85176645acea841c796a3cc0292Wei Jia        public void handleMessage(Message msg, long srcId) {
27810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mMediaPlayer.mNativeContext == 0) {
27820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "mediaplayer2 went away with unhandled events");
27830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
27840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
278563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            final int what = msg.arg1;
278663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            final int extra = msg.arg2;
2787cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia
27880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            switch(msg.what) {
27890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PREPARED:
2790cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
27910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
27920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scanInternalSubtitleTracks();
27930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (RuntimeException e) {
27940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // send error message instead of crashing;
27950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // send error message instead of inlining a call to onError
27960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // to avoid code duplication.
27970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message msg2 = obtainMessage(
27980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
27990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    sendMessage(msg2);
28000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                final DataSourceDesc dsd;
2803cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                synchronized (mSrcLock) {
2804de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
28051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                            + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
28061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    if (srcId == mCurrentSrcId) {
28071789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        dsd = mCurrentDSD;
2808cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                        prepareNextDataSource_l();
2809cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                    } else if (mNextDSDs != null && !mNextDSDs.isEmpty()
2810cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                            && srcId == mNextSrcId) {
2811cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                        dsd = mNextDSDs.get(0);
2812cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                        mNextSourceState = NEXT_SOURCE_STATE_PREPARED;
2813cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                        if (mNextSourcePlayPending) {
2814de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                            playNextDataSource_l();
2815de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        }
28161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    } else {
28171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        dsd = null;
2818de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    }
2819de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                }
2820de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
2821cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                if (dsd != null) {
2822cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                    synchronized (mEventCbLock) {
2823cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                        for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
2824cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                            cb.first.execute(() -> cb.second.onInfo(
2825cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                                    mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0));
2826cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                        }
282763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
28280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
2829adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                synchronized (mTaskLock) {
283069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    if (mCurrentTask != null
283169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                            && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
283269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                            && mCurrentTask.mDSD == dsd
2833adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                            && mCurrentTask.mNeedToWaitForEventToComplete) {
283469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
2835adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                        mCurrentTask = null;
2836adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                        processPendingTask_l();
2837adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                    }
2838adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                }
28390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
2840cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
28410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_DRM_INFO:
2843cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
28440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj == null) {
28450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
28460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (msg.obj instanceof Parcel) {
284763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    // The parcel was parsed already in postEventFromNative
284863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    final DrmInfoImpl drmInfo;
284963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
285063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    synchronized (mDrmLock) {
285163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (mDrmInfoImpl != null) {
285263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            drmInfo = mDrmInfoImpl.makeCopy();
285363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        } else {
285463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            drmInfo = null;
28550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
285663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
28570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
285863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    // notifying the client outside the lock
285963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    if (drmInfo != null) {
286063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        synchronized (mEventCbLock) {
286163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
286263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                cb.first.execute(() -> cb.second.onDrmInfo(
28631789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                        mMediaPlayer, mCurrentDSD, drmInfo));
286463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            }
28650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
28660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
28670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
28680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
28690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
2871cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
28720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PLAYBACK_COMPLETE:
2874cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
2875cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                final DataSourceDesc dsd = mCurrentDSD;
2876cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                synchronized (mSrcLock) {
28771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    if (srcId == mCurrentSrcId) {
2878de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
28791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                + ", currentSrcId=" + mCurrentSrcId + ", nextSrcId=" + mNextSrcId);
2880de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        playNextDataSource_l();
2881de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    }
2882de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                }
2883de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
288463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
28851789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
288663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
2887cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                                mMediaPlayer, dsd, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
288863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
28890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                stayAwake(false);
28910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
2892cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
28930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_STOPPED:
2895cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
2896cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                TimeProvider timeProvider = mTimeProvider;
2897cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                if (timeProvider != null) {
2898cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                    timeProvider.onStopped();
28990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
2901cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
29020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_STARTED:
29040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PAUSED:
2905cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
2906cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                TimeProvider timeProvider = mTimeProvider;
2907cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                if (timeProvider != null) {
2908cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                    timeProvider.onPaused(msg.what == MEDIA_PAUSED);
29090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
2911cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
29120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_BUFFERING_UPDATE:
2914cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
291563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int percent = msg.arg1;
291663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
2917c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                    if (srcId == mCurrentSrcId) {
2918c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                        mBufferedPercentageCurrent.set(percent);
2919c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                        for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
2920c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                            cb.first.execute(() -> cb.second.onInfo(
2921c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                                    mMediaPlayer, mCurrentDSD, MEDIA_INFO_BUFFERING_UPDATE,
2922c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                                    percent));
2923c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                        }
2924c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                    } else if (srcId == mNextSrcId && !mNextDSDs.isEmpty()) {
2925c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                        mBufferedPercentageNext.set(percent);
2926c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                        DataSourceDesc nextDSD = mNextDSDs.get(0);
2927c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                        for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
2928c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                            cb.first.execute(() -> cb.second.onInfo(
2929c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                                    mMediaPlayer, nextDSD, MEDIA_INFO_BUFFERING_UPDATE,
2930c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                                    percent));
2931c3725a94bb9840027a42669a659a0fd11d6f69c6Wei Jia                        }
293263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
29330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
2935cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
29360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SEEK_COMPLETE:
2938cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
293969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                synchronized (mTaskLock) {
294069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    if (mCurrentTask != null
294169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                            && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
294269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                            && mCurrentTask.mNeedToWaitForEventToComplete) {
294369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
294469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        mCurrentTask = null;
294569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        processPendingTask_l();
294663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
29470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
2948cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
29490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // fall through
29500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SKIPPED:
2952cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
2953cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                TimeProvider timeProvider = mTimeProvider;
2954cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                if (timeProvider != null) {
2955cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                    timeProvider.onSeekComplete(mMediaPlayer);
29560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
2958cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
29590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SET_VIDEO_SIZE:
2961cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
296263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int width = msg.arg1;
296363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int height = msg.arg2;
296463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
29651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
296663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onVideoSizeChanged(
29671789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, width, height));
296863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
29690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
2971cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
29720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_ERROR:
2974cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
29750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
297663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
29771789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
297863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onError(
29791789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, what, extra));
298063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
29811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
298263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
29830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                stayAwake(false);
29850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
2986cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
29870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_INFO:
2989cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
29900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                switch (msg.arg1) {
2991de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                    case MEDIA_INFO_STARTED_AS_NEXT:
29921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        if (srcId == mCurrentSrcId) {
2993de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                            prepareNextDataSource_l();
2994de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        }
2995de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia                        break;
2996de0c3979ce4bdb9464645d6a898b8e1e042cf33fWei Jia
299763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_VIDEO_TRACK_LAGGING:
299863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
299963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
300063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
300163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_METADATA_UPDATE:
300263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        try {
300363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            scanInternalSubtitleTracks();
300463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        } catch (RuntimeException e) {
300563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            Message msg2 = obtainMessage(
300663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED,
300763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                    null);
300863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            sendMessage(msg2);
300963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
301063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        // fall through
30110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
301263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
301363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
301463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        // update default track selection
301563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (mSubtitleController != null) {
301663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            mSubtitleController.selectDefaultTrack();
301763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
301863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
301963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
302063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_BUFFERING_START:
302163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_BUFFERING_END:
302263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        TimeProvider timeProvider = mTimeProvider;
302363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (timeProvider != null) {
302463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            timeProvider.onBuffering(msg.arg1 == MEDIA_INFO_BUFFERING_START);
302563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
302663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
30270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
302963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
30301789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
303163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
30321789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, what, extra));
303363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
30340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // No real default action so far.
30360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
3037cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
30380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_NOTIFY_TIME:
3040cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
3041cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                TimeProvider timeProvider = mTimeProvider;
3042cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                if (timeProvider != null) {
3043cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                    timeProvider.onNotifyTime();
3044cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                }
30450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
3046cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
30470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TIMED_TEXT:
3049cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
305063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final TimedText text;
305163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                if (msg.obj instanceof Parcel) {
305263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    Parcel parcel = (Parcel)msg.obj;
305363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    text = new TimedText(parcel);
305463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    parcel.recycle();
30550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
305663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    text = null;
305763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
305863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
305963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
30601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
30611789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, mCurrentDSD, text));
30620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
30630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
3065cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
30660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SUBTITLE_DATA:
3068cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
30690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener;
30700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (onSubtitleDataListener == null) {
30710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return;
30720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj instanceof Parcel) {
30740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Parcel parcel = (Parcel) msg.obj;
30750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleData data = new SubtitleData(parcel);
30760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    parcel.recycle();
30770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    onSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
30780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
3080cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
30810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_META_DATA:
3083cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
308463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final TimedMetaData data;
30850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj instanceof Parcel) {
30860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Parcel parcel = (Parcel) msg.obj;
308763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
30880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    parcel.recycle();
308963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                } else {
309063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    data = null;
309163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
309263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
309363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
30941789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
309563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
30961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mMediaPlayer, mCurrentDSD, data));
309763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
30980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
3100cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
31010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_NOP: // interface test message - ignore
3103cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
31040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
3105cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
31060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_AUDIO_ROUTING_CHANGED:
3108cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
31090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                AudioManager.resetAudioPortGeneration();
31100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mRoutingChangeListeners) {
31110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (NativeRoutingEventHandlerDelegate delegate
31120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            : mRoutingChangeListeners.values()) {
31130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        delegate.notifyClient();
31140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
31150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
3117cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
31180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
3120cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            {
31210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "Unknown message type " + msg.what);
31220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
31230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
3124cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia            }
31250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
31260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
31270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
31290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Called from native code when an interesting event happens.  This method
31300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * just uses the EventHandler system to post the event back to the main app thread.
31310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * We use a weak reference to the original MediaPlayer2 object so that the native
31320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * code is safe from the object disappearing from underneath it.  (This is
31330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the cookie passed to native_setup().)
31340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
313534c5bb126b8cc85176645acea841c796a3cc0292Wei Jia    private static void postEventFromNative(Object mediaplayer2_ref, long srcId,
31360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                            int what, int arg1, int arg2, Object obj)
31370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
31380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get();
31390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mp == null) {
31400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
31410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
31420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (what) {
31440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_INFO:
31450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
31460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                new Thread(new Runnable() {
31470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
31480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public void run() {
31490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // this acquires the wakelock if needed, and sets the client side state
31500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mp.play();
31510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
31520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }).start();
31530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Thread.yield();
31540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
31560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_DRM_INFO:
31580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // We need to derive mDrmInfoImpl before prepare() returns so processing it here
31590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // before the notification is sent to EventHandler below. EventHandler runs in the
31600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // notification looper so its handleMessage might process the event after prepare()
31610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // has returned.
31620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
31630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (obj instanceof Parcel) {
31640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Parcel parcel = (Parcel)obj;
31650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                DrmInfoImpl drmInfo = new DrmInfoImpl(parcel);
31660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mp.mDrmLock) {
31670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mp.mDrmInfoImpl = drmInfo;
31680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
31700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + obj);
31710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
31730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_PREPARED:
31750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // By this time, we've learned about DrmInfo's presence or absence. This is meant
31761789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            // mainly for prepare() use case. For prepare(), this still can run to a race
31770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // condition b/c MediaPlayerNative releases the prepare() lock before calling notify
31780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // so we also set mDrmInfoResolved in prepare().
31790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mp.mDrmLock) {
31800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mp.mDrmInfoResolved = true;
31810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
31820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
31830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
31850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mp.mEventHandler != null) {
31870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
318834c5bb126b8cc85176645acea841c796a3cc0292Wei Jia
318934c5bb126b8cc85176645acea841c796a3cc0292Wei Jia            mp.mEventHandler.post(new Runnable() {
319034c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                @Override
319134c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                public void run() {
319234c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                    mp.mEventHandler.handleMessage(m, srcId);
319334c5bb126b8cc85176645acea841c796a3cc0292Wei Jia                }
319434c5bb126b8cc85176645acea841c796a3cc0292Wei Jia            });
31950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
31960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
31970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mEventCbLock = new Object();
31991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    private ArrayList<Pair<Executor, MediaPlayer2EventCallback> > mEventCallbackRecords
32001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        = new ArrayList<Pair<Executor, MediaPlayer2EventCallback> >();
32010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
32030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when the media source is ready
32040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * for playback.
32050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
32060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param eventCallback the callback that will be run
32070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param executor the executor through which the callback should be invoked
32080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
32090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
32101789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setMediaPlayer2EventCallback(@NonNull @CallbackExecutor Executor executor,
32111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            @NonNull MediaPlayer2EventCallback eventCallback) {
32120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (eventCallback == null) {
32131789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
32140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (executor == null) {
32161789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException(
32171789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    "Illegal null Executor for the MediaPlayer2EventCallback");
32180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
322063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.add(new Pair(executor, eventCallback));
32210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
32230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
32251789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Clears the {@link MediaPlayer2EventCallback}.
32260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
32270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
32281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void clearMediaPlayer2EventCallback() {
32290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
3230096d97ac3e01d3a148f6148180c375f9337b64e5Wei Jia            mEventCallbackRecords.clear();
32310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
32330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
32350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when a track has data available.
32360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
32370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener the callback that will be run
32380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
32390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
32400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
32410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
32420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setOnSubtitleDataListener(OnSubtitleDataListener listener) {
32430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnSubtitleDataListener = listener;
32440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
32450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnSubtitleDataListener mOnSubtitleDataListener;
32470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM begin
32500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
32520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked for configuration of the DRM object before
32530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the session is created.
32540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The callback will be invoked synchronously during the execution
32550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * of {@link #prepareDrm(UUID uuid)}.
32560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
32570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener the callback that will be run
32580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
32590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
32600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setOnDrmConfigHelper(OnDrmConfigHelper listener)
32610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
32620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
32630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mOnDrmConfigHelper = listener;
32640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } // synchronized
32650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
32660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnDrmConfigHelper mOnDrmConfigHelper;
32680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mDrmEventCbLock = new Object();
327063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia    private ArrayList<Pair<Executor, DrmEventCallback> > mDrmEventCallbackRecords
327163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        = new ArrayList<Pair<Executor, DrmEventCallback> >();
32720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
32740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when the media source is ready
32750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * for playback.
32760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
32770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param eventCallback the callback that will be run
32780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param executor the executor through which the callback should be invoked
32790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
32800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
32811789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
32820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @NonNull DrmEventCallback eventCallback) {
32830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (eventCallback == null) {
32841789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException("Illegal null MediaPlayer2EventCallback");
32850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (executor == null) {
32871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            throw new IllegalArgumentException(
32881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                    "Illegal null Executor for the MediaPlayer2EventCallback");
32890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
329163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
32920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
32930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
32940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
32961789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * Clears the {@link DrmEventCallback}.
32970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
32980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
32991789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void clearDrmEventCallback() {
33000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
3301096d97ac3e01d3a148f6148180c375f9337b64e5Wei Jia            mDrmEventCallbackRecords.clear();
33020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
33030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
33040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
33070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Retrieves the DRM Info associated with the current source
33080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33091789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException if called before prepare()
33100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
33110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
33120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public DrmInfo getDrmInfo() {
33130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        DrmInfoImpl drmInfo = null;
33140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // there is not much point if the app calls getDrmInfo within an OnDrmInfoListenet;
33160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // regardless below returns drmInfo anyway instead of raising an exception
33170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
33180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mDrmInfoResolved && mDrmInfoImpl == null) {
33190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "The Player has not been prepared yet";
33200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, msg);
33210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
33220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmInfoImpl != null) {
33250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                drmInfo = mDrmInfoImpl.makeCopy();
33260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
33280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return drmInfo;
33300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
33310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
33340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Prepares the DRM for the current source
33350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
33360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmConfigHelper} is registered, it will be called during
33370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * preparation to allow configuration of the DRM properties before opening the
33380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * DRM session. Note that the callback is called synchronously in the thread that called
33390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
33400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and {@code setDrmPropertyString} calls and refrain from any lengthy operation.
33410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
33420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the device has not been provisioned before, this call also provisions the device
33430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * which involves accessing the provisioning server and can take a variable time to
33440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * complete depending on the network connectivity.
33450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
33460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * mode by launching the provisioning in the background and returning. The listener
33470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * will be called when provisioning and preparation has finished. If a
33480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
33490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and preparation has finished, i.e., runs in blocking mode.
33500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
33510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
33520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * session being ready. The application should not make any assumption about its call
33530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * sequence (e.g., before or after prepareDrm returns), or the thread context that will
33540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * execute the listener (unless the listener is registered with a handler thread).
33550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
33560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
33580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
33590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33601789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * @throws IllegalStateException              if called before prepare(), or the DRM was
33610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            prepared already
33620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws UnsupportedSchemeException         if the crypto scheme is not supported
33630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ResourceBusyException              if required DRM resources are in use
33640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ProvisioningNetworkErrorException  if provisioning is required but failed due to a
33650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            network error
33660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ProvisioningServerErrorException   if provisioning is required but failed due to
33670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            the request denied by the provisioning server
33680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
33690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
33700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void prepareDrm(@NonNull UUID uuid)
33710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws UnsupportedSchemeException, ResourceBusyException,
33720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                   ProvisioningNetworkErrorException, ProvisioningServerErrorException
33730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
33740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper);
33750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean allDoneWithoutProvisioning = false;
33770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
33790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // only allowing if tied to a protected source; might relax for releasing offline keys
33810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmInfoImpl == null) {
33820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " +
33830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "DRM info be retrieved before this call.";
33840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
33850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
33860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mActiveDrmScheme) {
33890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: There is already " +
33900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "an active DRM scheme with " + mDrmUUID;
33910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
33920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
33930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mPrepareDrmInProgress) {
33960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: There is already " +
33970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "a pending prepareDrm call.";
33980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
33990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
34000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmProvisioningInProgress) {
34030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Unexpectd: Provisioning is already in progress.";
34040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
34050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
34060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // shouldn't need this; just for safeguard
34090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            cleanDrmObj();
34100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPrepareDrmInProgress = true;
34120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
34140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // only creating the DRM object to allow pre-openSession configuration
3415cde2d3ff1048c13671b0b539f5635a64e088cd7aWei Jia                prepareDrm_createDrmStep(uuid);
34160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
34170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "prepareDrm(): Exception ", e);
34180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPrepareDrmInProgress = false;
34190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
34200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmConfigAllowed = true;
34230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
34240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // call the callback outside the lock
34270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mOnDrmConfigHelper != null)  {
34281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia            mOnDrmConfigHelper.onDrmConfig(this, mCurrentDSD);
34290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
34320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmConfigAllowed = false;
34330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean earlyExit = false;
34340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
34360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                prepareDrm_openSessionStep(uuid);
34370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmUUID = uuid;
34390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mActiveDrmScheme = true;
34400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                allDoneWithoutProvisioning = true;
34420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
34430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: The player must be " +
34440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "in the prepared state to call prepareDrm().";
34450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
34460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                earlyExit = true;
34470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
34480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
34490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "prepareDrm: NotProvisionedException");
34500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // handle provisioning internally; it'll reset mPrepareDrmInProgress
34520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int result = HandleProvisioninig(uuid);
34530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if blocking mode, we're already done;
34550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if non-blocking mode, we attempted to launch background provisioning
34560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (result != PREPARE_DRM_STATUS_SUCCESS) {
34570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    earlyExit = true;
34580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    String msg;
34590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    switch (result) {
34610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
34620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Provisioning was required but failed " +
34630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                "due to a network error.";
34640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
34650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new ProvisioningNetworkErrorExceptionImpl(msg);
34660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
34680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Provisioning was required but the request " +
34690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                "was denied by the server.";
34700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
34710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new ProvisioningServerErrorExceptionImpl(msg);
34720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PREPARATION_ERROR:
34740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    default: // default for safeguard
34750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Post-provisioning preparation failed.";
34760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
34770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new IllegalStateException(msg);
34780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
34790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
34800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // nothing else to do;
34810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup
34820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
34830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "prepareDrm: Exception " + e);
34840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                earlyExit = true;
34850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
34860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } finally {
34870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!mDrmProvisioningInProgress) {// if early exit other than provisioning exception
34880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPrepareDrmInProgress = false;
34890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
34900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (earlyExit) {    // cleaning up object if didn't succeed
34910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    cleanDrmObj();
34920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
34930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } // finally
34940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
34950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // if finished successfully without provisioning, call the callback outside the lock
34980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (allDoneWithoutProvisioning) {
34990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mDrmEventCbLock) {
350063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
350163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    cb.first.execute(() -> cb.second.onDrmPrepared(
35021789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                            this, mCurrentDSD, PREPARE_DRM_STATUS_SUCCESS));
350363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
35040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
35060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
35080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _releaseDrm();
35110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
35130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Releases the DRM session
35140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The player has to have an active DRM session and be in stopped, or prepared
35160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * state before this call is made.
35170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A {@code reset()} call will release the DRM session implicitly.
35180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session to release
35200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
35210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
35220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void releaseDrm()
35230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
35240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
352569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_RELEASE_DRM, false) {
352669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
352769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() throws NoDrmSchemeException {
352869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                synchronized (mDrmLock) {
352969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    Log.v(TAG, "releaseDrm:");
353069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
353169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    if (!mActiveDrmScheme) {
353269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        Log.e(TAG, "releaseDrm(): No active DRM scheme to release.");
353369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        throw new NoDrmSchemeExceptionImpl(
353469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                                "releaseDrm: No active DRM scheme to release.");
353569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
35360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
353769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    try {
353869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        // we don't have the player's state in this layer. The below call raises
353969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        // exception if we're in a non-stopped/prepared state.
354069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
354169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        // for cleaning native/mediaserver crypto object
354269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        _releaseDrm();
354369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
354469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        // for cleaning client-side MediaDrm object; only called if above has succeeded
354569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        cleanDrmObj();
354669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
354769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        mActiveDrmScheme = false;
354869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    } catch (IllegalStateException e) {
354969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        Log.w(TAG, "releaseDrm: Exception ", e);
355069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        throw new IllegalStateException(
355169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                                "releaseDrm: The player is not in a valid state.");
355269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    } catch (Exception e) {
355369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        Log.e(TAG, "releaseDrm: Exception ", e);
355469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
355569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }   // synchronized
35560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
355769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
35580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
35590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
35620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A key request/response exchange occurs between the app and a license server
35630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to obtain or release keys used to decrypt encrypted content.
35640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * getDrmKeyRequest() is used to obtain an opaque key request byte array that is
35660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * delivered to the license server.  The opaque key request byte array is returned
35670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in KeyRequest.data.  The recommended URL to deliver the key request to is
35680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * returned in KeyRequest.defaultUrl.
35690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * After the app has received the key request response from the server,
35710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * it should deliver to the response to the DRM engine plugin using the method
35721789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@link #provideDrmKeyResponse}.
35730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId is the key-set identifier of the offline keys being released when keyType is
35750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
35760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}.
35770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param initData is the container-specific initialization data when the keyType is
35790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is
35800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * interpreted based on the mime type provided in the mimeType parameter.  It could
35810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain, for example, the content ID, key ID or other data obtained from the content
35820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * metadata that is required in generating the key request.
35830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null.
35840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType identifies the mime type of the content
35860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keyType specifies the type of the request. The request may be to acquire
35880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content
35890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired
35900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId.
35910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param optionalParameters are included in the key request message to
35930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * allow a client application to provide additional message parameters to the server.
35940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This may be {@code null} if no additional parameters are to be sent.
35950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session
35970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
35980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
35990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
36001789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public MediaDrm.KeyRequest getDrmKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData,
36010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable String mimeType, @MediaDrm.KeyType int keyType,
36020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable Map<String, String> optionalParameters)
36030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
36040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
36051789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Log.v(TAG, "getDrmKeyRequest: " +
36060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
36070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " keyType: " + keyType + " optionalParameters: " + optionalParameters);
36080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
36100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
36111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
361269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                throw new NoDrmSchemeExceptionImpl(
361369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        "getDrmKeyRequest: Has to set a DRM scheme first.");
36140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
36170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
36180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
36190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        keySetId;       // keySetId for KEY_TYPE_RELEASE
36200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                HashMap<String, String> hmapOptionalParameters =
36220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                (optionalParameters != null) ?
36230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                new HashMap<String, String>(optionalParameters) :
36240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                null;
36250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scope, initData, mimeType,
36270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                              keyType, hmapOptionalParameters);
36281789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.v(TAG, "getDrmKeyRequest:   --> request: " + request);
36290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return request;
36310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
36331789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "getDrmKeyRequest NotProvisionedException: " +
36340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected. Shouldn't have reached here.");
36351789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new IllegalStateException("getDrmKeyRequest: Unexpected provisioning error.");
36360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
36371789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "getDrmKeyRequest Exception " + e);
36380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
36390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
36420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
36430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
36460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A key response is received from the license server by the app, then it is
36471789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * provided to the DRM engine plugin using provideDrmKeyResponse. When the
36480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * response is for an offline key request, a key-set identifier is returned that
36490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * can be used to later restore the keys to a new session with the method
36501789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * {@ link # restoreDrmKeys}.
36510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When the response is for a streaming or release request, null is returned.
36520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
36530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId When the response is for a release request, keySetId identifies
36540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the saved key associated with the release request (i.e., the same keySetId
36551789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * passed to the earlier {@ link #getDrmKeyRequest} call. It MUST be null when the
36560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * response is for either streaming or offline key requests.
36570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
36580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param response the byte array response from the server
36590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
36600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session
36610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws DeniedByServerException if the response indicates that the
36620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * server rejected the request
36630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
36640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
36651789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public byte[] provideDrmKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
36660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException, DeniedByServerException
36670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
36681789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response);
36690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
36710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
36731789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
367469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                throw new NoDrmSchemeExceptionImpl(
367569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        "getDrmKeyRequest: Has to set a DRM scheme first.");
36760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
36790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] scope = (keySetId == null) ?
36800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mDrmSessionId :     // sessionId for KEY_TYPE_STREAMING/OFFLINE
36810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                keySetId;           // keySetId for KEY_TYPE_RELEASE
36820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
36840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
368569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response
368669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        + " --> " + keySetResult);
36870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return keySetResult;
36900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
36921789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "provideDrmKeyResponse NotProvisionedException: " +
36930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected. Shouldn't have reached here.");
36941789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                throw new IllegalStateException("provideDrmKeyResponse: " +
36950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected provisioning error.");
36960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
36971789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                Log.w(TAG, "provideDrmKeyResponse Exception " + e);
36980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
36990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
37000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
37010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Restore persisted offline keys into a new session.  keySetId identifies the
37061789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia     * keys to load, obtained from a prior call to {@link #provideDrmKeyResponse}.
37070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId identifies the saved key set to restore
37090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
37111789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia    public void restoreDrmKeys(@NonNull byte[] keySetId)
37120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
37130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
371469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        addTask(new Task(CALL_COMPLETED_RESTORE_DRM_KEYS, false) {
371569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            @Override
371669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            void process() throws NoDrmSchemeException {
371769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
37180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
371969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                synchronized (mDrmLock) {
37200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
372169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    if (!mActiveDrmScheme) {
372269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
372369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        throw new NoDrmSchemeExceptionImpl(
372469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                                "restoreDrmKeys: Has to set a DRM scheme first.");
372569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
37260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
372769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    try {
372869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        mDrmObj.restoreKeys(mDrmSessionId, keySetId);
372969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    } catch (Exception e) {
373069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        Log.w(TAG, "restoreKeys Exception " + e);
373169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        throw e;
373269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    }
37330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
373469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }   // synchronized
373569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
373669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        });
37370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Read a DRM engine plugin String property value, given the property name string.
37420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
37430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param propertyName the property name
37440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Standard fields names are:
37460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
37470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
37480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
37500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
37510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName)
37520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
37530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
37540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName);
37550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String value;
37570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
37580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme && !mDrmConfigAllowed) {
37600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getDrmPropertyString NoDrmSchemeException");
376169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                throw new NoDrmSchemeExceptionImpl(
376269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        "getDrmPropertyString: Has to prepareDrm() first.");
37630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
37640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
37660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                value = mDrmObj.getPropertyString(propertyName);
37670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
37680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getDrmPropertyString Exception " + e);
37690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
37700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
37710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
37720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName + " --> value: " + value);
37740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return value;
37760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set a DRM engine plugin String property value.
37810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
37820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param propertyName the property name
37830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param value the property value
37840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Standard fields names are:
37860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
37870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
37880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
37900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName,
37910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                     @NonNull String value)
37920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
37930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
37940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "setDrmPropertyString: propertyName: " + propertyName + " value: " + value);
37950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
37970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if ( !mActiveDrmScheme && !mDrmConfigAllowed ) {
37990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setDrmPropertyString NoDrmSchemeException");
380069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                throw new NoDrmSchemeExceptionImpl(
380169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                        "setDrmPropertyString: Has to prepareDrm() first.");
38020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
38050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmObj.setPropertyString(propertyName, value);
38060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch ( Exception e ) {
38070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setDrmPropertyString Exception " + e);
38080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
38090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
38110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
38120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
38140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Encapsulates the DRM properties of the source.
38150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
38160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class DrmInfoImpl extends DrmInfo {
38170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Map<UUID, byte[]> mapPssh;
38180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID[] supportedSchemes;
38190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
38210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Returns the PSSH info of the data source for each supported DRM scheme.
38220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
38230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
38240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public Map<UUID, byte[]> getPssh() {
38250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mapPssh;
38260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
38290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Returns the intersection of the data source and the device DRM schemes.
38300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * It effectively identifies the subset of the source's DRM schemes which
38310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * are supported by the device too.
38320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
38330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
38340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public List<UUID> getSupportedSchemes() {
38350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return Arrays.asList(supportedSchemes);
38360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes) {
38390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mapPssh = Pssh;
38400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            supportedSchemes = SupportedSchemes;
38410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl(Parcel parcel) {
38440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl(" + parcel + ") size " + parcel.dataSize());
38450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int psshsize = parcel.readInt();
38470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] pssh = new byte[psshsize];
38480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            parcel.readByteArray(pssh);
38490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() PSSH: " + arrToHex(pssh));
38510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mapPssh = parsePSSH(pssh, psshsize);
38520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() PSSH: " + mapPssh);
38530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int supportedDRMsCount = parcel.readInt();
38550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            supportedSchemes = new UUID[supportedDRMsCount];
38560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < supportedDRMsCount; i++) {
38570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] uuid = new byte[16];
38580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                parcel.readByteArray(uuid);
38590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                supportedSchemes[i] = bytesToUUID(uuid);
38610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, "DrmInfoImpl() supportedScheme[" + i + "]: " +
38630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                      supportedSchemes[i]);
38640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + psshsize +
38670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                  " supportedDRMsCount: " + supportedDRMsCount);
38680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl makeCopy() {
38710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new DrmInfoImpl(this.mapPssh, this.supportedSchemes);
38720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private String arrToHex(byte[] bytes) {
38750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String out = "0x";
38760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < bytes.length; i++) {
38770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out += String.format("%02x", bytes[i]);
38780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return out;
38810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID bytesToUUID(byte[] uuid) {
38840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long msb = 0, lsb = 0;
38850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < 8; i++) {
38860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                msb |= ( ((long)uuid[i]   & 0xff) << (8 * (7 - i)) );
38870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                lsb |= ( ((long)uuid[i+8] & 0xff) << (8 * (7 - i)) );
38880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new UUID(msb, lsb);
38910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
38920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
38940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Map<UUID, byte[]> result = new HashMap<UUID, byte[]>();
38950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int UUID_SIZE = 16;
38970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int DATALEN_SIZE = 4;
38980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int len = psshsize;
39000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int numentries = 0;
39010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
39020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            while (len > 0) {
39040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < UUID_SIZE) {
39050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
39060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "UUID: (%d < 16) pssh: %d", len, psshsize));
39070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
39080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
39090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] subset = Arrays.copyOfRange(pssh, i, i + UUID_SIZE);
39110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                UUID uuid = bytesToUUID(subset);
39120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += UUID_SIZE;
39130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= UUID_SIZE;
39140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // get data length
39160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < 4) {
39170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
39180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "datalen: (%d < 4) pssh: %d", len, psshsize));
39190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
39200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
39210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                subset = Arrays.copyOfRange(pssh, i, i+DATALEN_SIZE);
39230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) ?
39240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16) |
39250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[1] & 0xff) <<  8) |  (subset[0] & 0xff)          :
39260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16) |
39270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[2] & 0xff) <<  8) |  (subset[3] & 0xff) ;
39280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += DATALEN_SIZE;
39290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= DATALEN_SIZE;
39300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < datalen) {
39320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
39330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "data: (%d < %d) pssh: %d", len, datalen, psshsize));
39340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
39350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
39360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] data = Arrays.copyOfRange(pssh, i, i+datalen);
39380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // skip the data
39400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += datalen;
39410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= datalen;
39420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, String.format("parsePSSH[%d]: <%s, %s> pssh: %d",
39440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                         numentries, uuid, arrToHex(data), psshsize));
39450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                numentries++;
39460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                result.put(uuid, data);
39470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return result;
39500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
39510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };  // DrmInfoImpl
39530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
39550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when a DRM method is called before preparing a DRM scheme through prepareDrm().
39560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
39570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
39580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class NoDrmSchemeExceptionImpl extends NoDrmSchemeException {
39590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public NoDrmSchemeExceptionImpl(String detailMessage) {
39600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
39610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
39620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
39630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
39650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when the device requires DRM provisioning but the provisioning attempt has
39660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * failed due to a network error (Internet reachability, timeout, etc.).
39670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
39680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
39690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class ProvisioningNetworkErrorExceptionImpl
39700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            extends ProvisioningNetworkErrorException {
39710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningNetworkErrorExceptionImpl(String detailMessage) {
39720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
39730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
39740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
39750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
39770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when the device requires DRM provisioning but the provisioning attempt has
39780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * failed due to the provisioning server denying the request.
39790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
39800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
39810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class ProvisioningServerErrorExceptionImpl
39820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            extends ProvisioningServerErrorException {
39830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningServerErrorExceptionImpl(String detailMessage) {
39840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
39850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
39860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
39870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId);
39900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Modular DRM helpers
39920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void prepareDrm_createDrmStep(@NonNull UUID uuid)
39940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws UnsupportedSchemeException {
39950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid);
39960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
39980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj = new MediaDrm(uuid);
39990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj);
40000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) { // UnsupportedSchemeException
40010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e);
40020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw e;
40030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
40050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void prepareDrm_openSessionStep(@NonNull UUID uuid)
40070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NotProvisionedException, ResourceBusyException {
40080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm_openSessionStep: uuid: " + uuid);
40090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: don't need an open session for a future specialKeyReleaseDrm mode but we should do
40110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // it anyway so it raises provisioning error if needed. We'd rather handle provisioning
40121789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia        // at prepareDrm/openSession rather than getDrmKeyRequest/provideDrmKeyResponse
40130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
40140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmSessionId = mDrmObj.openSession();
40150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId);
40160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Sending it down to native/mediaserver to create the crypto object
40180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // This call could simply fail due to bad player state, e.g., after play().
40190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            _prepareDrm(getByteArrayFromUUID(uuid), mDrmSessionId);
40200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_openSessionStep: _prepareDrm/Crypto succeeded");
40210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) { //ResourceBusyException, NotProvisionedException
40230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "prepareDrm_openSessionStep: open/crypto failed with " + e);
40240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw e;
40250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
40280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40298e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    // Called from the native side
40308e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    @SuppressWarnings("unused")
40318e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static boolean setAudioOutputDeviceById(AudioTrack track, int deviceId) {
40328e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        if (track == null) {
40338e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            return false;
40348e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
40358e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40368e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        if (deviceId == 0) {
40378e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            // Use default routing.
40388e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            track.setPreferredDevice(null);
40398e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            return true;
40408e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
40418e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40428e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        // TODO: Unhide AudioManager.getDevicesStatic.
40438e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        AudioDeviceInfo[] outputDevices =
40448e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
40458e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40468e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        boolean success = false;
40478e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        for (AudioDeviceInfo device : outputDevices) {
40488e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            if (device.getId() == deviceId) {
40498e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                track.setPreferredDevice(device);
40508e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                success = true;
40518e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                break;
40528e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            }
40538e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
40548e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        return success;
40558e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    }
40568e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40578e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    // Instantiated from the native side
40588e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    @SuppressWarnings("unused")
40598e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static class StreamEventCallback extends AudioTrack.StreamEventCallback {
40608e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mJAudioTrackPtr;
40618e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mNativeCallbackPtr;
40628e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mUserDataPtr;
40638e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40648e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public StreamEventCallback(long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr) {
40658e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            super();
40668e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mJAudioTrackPtr = jAudioTrackPtr;
40678e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mNativeCallbackPtr = nativeCallbackPtr;
40688e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mUserDataPtr = userDataPtr;
40698e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
40708e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40718e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
40728e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onTearDown(AudioTrack track) {
40738e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onTearDown(mNativeCallbackPtr, mUserDataPtr);
40748e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
40758e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40768e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
40778e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onStreamPresentationEnd(AudioTrack track) {
40788e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onStreamPresentationEnd(mNativeCallbackPtr, mUserDataPtr);
40798e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
40808e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40818e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
40828e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onStreamDataRequest(AudioTrack track) {
40838e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onStreamDataRequest(
40848e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                    mJAudioTrackPtr, mNativeCallbackPtr, mUserDataPtr);
40858e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
40868e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    }
40878e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
40880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private class ProvisioningThread extends Thread {
40890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public static final int TIMEOUT_MS = 60000;
40900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID uuid;
40920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private String urlStr;
40930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Object drmLock;
40940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mediaPlayer;
40950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private int status;
40960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean finished;
40970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public  int status() {
40980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return status;
40990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningThread initialize(MediaDrm.ProvisionRequest request,
41020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                          UUID uuid, MediaPlayer2Impl mediaPlayer) {
41030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // lock is held by the caller
41040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            drmLock = mediaPlayer.mDrmLock;
41050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            this.mediaPlayer = mediaPlayer;
41060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
41080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            this.uuid = uuid;
41090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
41110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "HandleProvisioninig: Thread is initialised url: " + urlStr);
41130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return this;
41140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void run() {
41170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] response = null;
41190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean provisioningSucceeded = false;
41200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
41210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                URL url = new URL(urlStr);
41220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
41230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
41240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setRequestMethod("POST");
41250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setDoOutput(false);
41260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setDoInput(true);
41270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setConnectTimeout(TIMEOUT_MS);
41280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setReadTimeout(TIMEOUT_MS);
41290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.connect();
41310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    response = Streams.readFully(connection.getInputStream());
41320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.v(TAG, "HandleProvisioninig: Thread run: response " +
41340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            response.length + " " + response);
41350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
41360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
41370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url);
41380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } finally {
41390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.disconnect();
41400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
41410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e)   {
41420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
41430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "HandleProvisioninig: Thread run: openConnection " + e);
41440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (response != null) {
41470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
41480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mDrmObj.provideProvisionResponse(response);
41490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.v(TAG, "HandleProvisioninig: Thread run: " +
41500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            "provideProvisionResponse SUCCEEDED!");
41510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    provisioningSucceeded = true;
41530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
41540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR;
41550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "HandleProvisioninig: Thread run: " +
41560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            "provideProvisionResponse " + e);
41570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
41580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean succeeded = false;
41610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
416263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            boolean hasCallback = false;
41630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mDrmEventCbLock) {
416463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                hasCallback = !mDrmEventCallbackRecords.isEmpty();
41650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // non-blocking mode needs the lock
416763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            if (hasCallback) {
41680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (drmLock) {
41700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // continuing with prepareDrm
41710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (provisioningSucceeded) {
41720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        succeeded = mediaPlayer.resumePrepareDrm(uuid);
41730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        status = (succeeded) ?
41740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                PREPARE_DRM_STATUS_SUCCESS :
41750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                PREPARE_DRM_STATUS_PREPARATION_ERROR;
41760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
41770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mediaPlayer.mDrmProvisioningInProgress = false;
41780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mediaPlayer.mPrepareDrmInProgress = false;
41790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (!succeeded) {
41800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        cleanDrmObj();  // cleaning up if it hasn't gone through while in the lock
41810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
41820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } // synchronized
41830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // calling the callback outside the lock
418563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mDrmEventCbLock) {
418663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
41871789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                        cb.first.execute(() -> cb.second.onDrmPrepared(
41881789cc7f8221fd1f682fa08a1aeb1e37c2315887Wei Jia                                mediaPlayer, mCurrentDSD, status));
418963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
419063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
41910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {   // blocking mode already has the lock
41920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // continuing with prepareDrm
41940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (provisioningSucceeded) {
41950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    succeeded = mediaPlayer.resumePrepareDrm(uuid);
41960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = (succeeded) ?
41970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            PREPARE_DRM_STATUS_SUCCESS :
41980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            PREPARE_DRM_STATUS_PREPARATION_ERROR;
41990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mediaPlayer.mDrmProvisioningInProgress = false;
42010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mediaPlayer.mPrepareDrmInProgress = false;
42020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!succeeded) {
42030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    cleanDrmObj();  // cleaning up if it hasn't gone through
42040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            finished = true;
42080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // run()
42090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }   // ProvisioningThread
42110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int HandleProvisioninig(UUID uuid) {
42130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the lock is already held by the caller
42140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmProvisioningInProgress) {
42160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress");
42170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
42180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
42210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (provReq == null) {
42220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null.");
42230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
42240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "HandleProvisioninig provReq " +
42270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
42280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // networking in a background thread
42300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningInProgress = true;
42310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this);
42330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningThread.start();
42340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int result;
42360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // non-blocking: this is not the final result
423863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        boolean hasCallback = false;
42390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
424063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            hasCallback = !mDrmEventCallbackRecords.isEmpty();
42410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
424263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        if (hasCallback) {
42430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            result = PREPARE_DRM_STATUS_SUCCESS;
42440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
42450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // if blocking mode, wait till provisioning is done
42460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
42470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmProvisioningThread.join();
42480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
42490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e);
42500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
42510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            result = mDrmProvisioningThread.status();
42520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // no longer need the thread
42530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmProvisioningThread = null;
42540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return result;
42570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
42580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean resumePrepareDrm(UUID uuid) {
42600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "resumePrepareDrm: uuid: " + uuid);
42610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // mDrmLock is guaranteed to be held
42630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean success = false;
42640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
42650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // resuming
42660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            prepareDrm_openSessionStep(uuid);
42670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmUUID = uuid;
42690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mActiveDrmScheme = true;
42700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            success = true;
42720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) {
42730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "HandleProvisioninig: Thread run _prepareDrm resume failed with " + e);
42740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // mDrmObj clean up is done by the caller
42750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return success;
42780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
42790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void resetDrmState() {
42810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
42820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "resetDrmState: " +
42830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mDrmInfoImpl=" + mDrmInfoImpl +
42840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mDrmProvisioningThread=" + mDrmProvisioningThread +
42850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mPrepareDrmInProgress=" + mPrepareDrmInProgress +
42860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mActiveDrmScheme=" + mActiveDrmScheme);
42870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmInfoResolved = false;
42890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmInfoImpl = null;
42900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmProvisioningThread != null) {
42920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // timeout; relying on HttpUrlConnection
42930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
42940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mDrmProvisioningThread.join();
42950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                catch (InterruptedException e) {
42970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "resetDrmState: ProvThread.join Exception " + e);
42980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
42990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmProvisioningThread = null;
43000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPrepareDrmInProgress = false;
43030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mActiveDrmScheme = false;
43040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            cleanDrmObj();
43060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
43070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
43080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void cleanDrmObj() {
43100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the caller holds mDrmLock
43110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj + " mDrmSessionId=" + mDrmSessionId);
43120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmSessionId != null)    {
43140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj.closeSession(mDrmSessionId);
43150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmSessionId = null;
43160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
43170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmObj != null) {
43180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj.release();
43190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj = null;
43200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
43210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
43220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
43240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long msb = uuid.getMostSignificantBits();
43250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long lsb = uuid.getLeastSignificantBits();
43260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        byte[] uuidBytes = new byte[16];
43280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (int i = 0; i < 8; ++i) {
43290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
43300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
43310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
43320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return uuidBytes;
43340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
43350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM end
43370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
43390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Test whether a given video scaling mode is supported.
43400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
43410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean isVideoScalingModeSupported(int mode) {
43420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return (mode == VIDEO_SCALING_MODE_SCALE_TO_FIT ||
43430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
43440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
43450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
43470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    static class TimeProvider implements MediaTimeProvider {
43480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final String TAG = "MTP";
43490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long MAX_NS_WITHOUT_POSITION_CHECK = 5000000000L;
43500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long MAX_EARLY_CALLBACK_US = 1000;
43510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long TIME_ADJUSTMENT_RATE = 2;  /* meaning 1/2 */
43520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mLastTimeUs = 0;
43530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mPlayer;
43540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mPaused = true;
43550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mStopped = true;
43560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mBuffering;
43570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mLastReportedTime;
43580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // since we are expecting only a handful listeners per stream, there is
43590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // no need for log(N) search performance
43600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaTimeProvider.OnMediaTimeListener mListeners[];
43610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mTimes[];
436234c5bb126b8cc85176645acea841c796a3cc0292Wei Jia        private EventHandler mEventHandler;
43630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mRefresh = false;
43640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mPausing = false;
43650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mSeeking = false;
43660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY = 1;
43670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_TIME = 0;
43680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_STOP = 2;
43690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_SEEK = 3;
43700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_TRACK_DATA = 4;
43710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private HandlerThread mHandlerThread;
43720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
43740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public boolean DEBUG = false;
43750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public TimeProvider(MediaPlayer2Impl mp) {
43770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPlayer = mp;
43780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
43790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                getCurrentTimeUs(true, false);
43800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
43810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we assume starting position
43820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRefresh = true;
43830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Looper looper;
43860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if ((looper = Looper.myLooper()) == null &&
43870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                (looper = Looper.getMainLooper()) == null) {
43880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // Create our own looper here in case MP was created without one
43890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread = new HandlerThread("MediaPlayer2MTPEventThread",
43900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                      Process.THREAD_PRIORITY_FOREGROUND);
43910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.start();
43920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                looper = mHandlerThread.getLooper();
43930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(looper);
43950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
43970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimes = new long[0];
43980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mLastTimeUs = 0;
43990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private void scheduleNotification(int type, long delayUs) {
44020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // ignore time notifications until seek is handled
44030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSeeking && type == NOTIFY_TIME) {
44040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
44050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (DEBUG) Log.v(TAG, "scheduleNotification " + type + " in " + delayUs);
44080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeMessages(NOTIFY);
44090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Message msg = mEventHandler.obtainMessage(NOTIFY, type, 0);
44100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.sendMessageDelayed(msg, (int) (delayUs / 1000));
44110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void close() {
44150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeMessages(NOTIFY);
44160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mHandlerThread != null) {
44170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.quitSafely();
44180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread = null;
44190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        protected void finalize() {
44240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mHandlerThread != null) {
44250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.quitSafely();
44260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onNotifyTime() {
44310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
44320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onNotifyTime: ");
44330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
44340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onPaused(boolean paused) {
44390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
44400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onPaused: " + paused);
44410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mStopped) { // handle as seek if we were stopped
44420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mStopped = false;
44430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = true;
44440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
44450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
44460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPausing = paused;  // special handling if player disappeared
44470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = false;
44480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
44490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onBuffering(boolean buffering) {
44550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
44560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onBuffering: " + buffering);
44570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mBuffering = buffering;
44580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
44590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onStopped() {
44640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
44650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onStopped");
44660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPaused = true;
44670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mStopped = true;
44680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSeeking = false;
44690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mBuffering = false;
44700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_STOP, 0 /* delay */);
44710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onSeekComplete(MediaPlayer2Impl mp) {
44760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
44770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mStopped = false;
44780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSeeking = true;
44790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
44800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
44840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onNewPlayer() {
44850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mRefresh) {
44860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized(this) {
44870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mStopped = false;
44880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = true;
44890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mBuffering = false;
44900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
44910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifySeek() {
44960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSeeking = false;
44970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
44980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long timeUs = getCurrentTimeUs(true, false);
44990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onSeekComplete at " + timeUs);
45000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
45020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (listener == null) {
45030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
45040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
45050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    listener.onSeek(timeUs);
45060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
45070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
45080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we should not be there, but at least signal pause
45090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onSeekComplete but no player");
45100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPausing = true;  // special handling if player disappeared
45110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                notifyTimedEvent(false /* refreshTime */);
45120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyTrackData(Pair<SubtitleTrack, byte[]> trackData) {
45160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleTrack track = trackData.first;
45170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] data = trackData.second;
45180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            track.onData(data, true /* eos */, ~0 /* runID: keep forever */);
45190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyStop() {
45220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
45230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (listener == null) {
45240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
45250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
45260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                listener.onStop();
45270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private int registerListener(MediaTimeProvider.OnMediaTimeListener listener) {
45310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
45320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (; i < mListeners.length; i++) {
45330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mListeners[i] == listener || mListeners[i] == null) {
45340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
45350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
45360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // new listener
45390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (i >= mListeners.length) {
45400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaTimeProvider.OnMediaTimeListener[] newListeners =
45410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    new MediaTimeProvider.OnMediaTimeListener[i + 1];
45420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long[] newTimes = new long[i + 1];
45430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                System.arraycopy(mListeners, 0, newListeners, 0, mListeners.length);
45440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                System.arraycopy(mTimes, 0, newTimes, 0, mTimes.length);
45450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mListeners = newListeners;
45460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes = newTimes;
45470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mListeners[i] == null) {
45500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mListeners[i] = listener;
45510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes[i] = MediaTimeProvider.NO_TIME;
45520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return i;
45540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void notifyAt(
45570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long timeUs, MediaTimeProvider.OnMediaTimeListener listener) {
45580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
45590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "notifyAt " + timeUs);
45600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes[registerListener(listener)] = timeUs;
45610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
45620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void scheduleUpdate(MediaTimeProvider.OnMediaTimeListener listener) {
45660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
45670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "scheduleUpdate");
45680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int i = registerListener(listener);
45690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!mStopped) {
45710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mTimes[i] = 0;
45720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
45730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
45740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void cancelNotifications(
45780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaTimeProvider.OnMediaTimeListener listener) {
45790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
45800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int i = 0;
45810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (; i < mListeners.length; i++) {
45820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mListeners[i] == listener) {
45830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        System.arraycopy(mListeners, i + 1,
45840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mListeners, i, mListeners.length - i - 1);
45850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        System.arraycopy(mTimes, i + 1,
45860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mTimes, i, mTimes.length - i - 1);
45870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mListeners[mListeners.length - 1] = null;
45880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mTimes[mTimes.length - 1] = NO_TIME;
45890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
45900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    } else if (mListeners[i] == null) {
45910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
45920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
45930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
45940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
45960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyTimedEvent(boolean refreshTime) {
46000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // figure out next callback
46010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long nowUs;
46020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
46030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                nowUs = getCurrentTimeUs(refreshTime, true);
46040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
46050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // assume we paused until new player arrives
46060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRefresh = true;
46070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPausing = true; // this ensures that call succeeds
46080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                nowUs = getCurrentTimeUs(refreshTime, true);
46090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long nextTimeUs = nowUs;
46110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSeeking) {
46130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // skip timed-event notifications until seek is complete
46140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
46150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (DEBUG) {
46180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                StringBuilder sb = new StringBuilder();
46190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                sb.append("notifyTimedEvent(").append(mLastTimeUs).append(" -> ")
46200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        .append(nowUs).append(") from {");
46210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                boolean first = true;
46220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (long time: mTimes) {
46230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (time == NO_TIME) {
46240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        continue;
46250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
46260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (!first) sb.append(", ");
46270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    sb.append(time);
46280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    first = false;
46290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                sb.append("}");
46310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.d(TAG, sb.toString());
46320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Vector<MediaTimeProvider.OnMediaTimeListener> activatedListeners =
46350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                new Vector<MediaTimeProvider.OnMediaTimeListener>();
46360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int ix = 0; ix < mTimes.length; ix++) {
46370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mListeners[ix] == null) {
46380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
46390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mTimes[ix] <= NO_TIME) {
46410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // ignore, unless we were stopped
46420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (mTimes[ix] <= nowUs + MAX_EARLY_CALLBACK_US) {
46430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    activatedListeners.add(mListeners[ix]);
46440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (DEBUG) Log.d(TAG, "removed");
46450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mTimes[ix] = NO_TIME;
46460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (nextTimeUs == nowUs || mTimes[ix] < nextTimeUs) {
46470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    nextTimeUs = mTimes[ix];
46480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (nextTimeUs > nowUs && !mPaused) {
46520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // schedule callback at nextTimeUs
46530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "scheduling for " + nextTimeUs + " and " + nowUs);
46540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPlayer.notifyAt(nextTimeUs);
46550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
46560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mEventHandler.removeMessages(NOTIFY);
46570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // no more callbacks
46580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (MediaTimeProvider.OnMediaTimeListener listener: activatedListeners) {
46610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                listener.onTimedEvent(nowUs);
46620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public long getCurrentTimeUs(boolean refreshTime, boolean monotonic)
46660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throws IllegalStateException {
46670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
46680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we always refresh the time when the paused-state changes, because
46690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we expect to have received the pause-change event delayed.
46700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mPaused && !refreshTime) {
46710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return mLastReportedTime;
46720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
46750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mLastTimeUs = mPlayer.getCurrentPosition() * 1000L;
46760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPaused = !mPlayer.isPlaying() || mBuffering;
46770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (DEBUG) Log.v(TAG, (mPaused ? "paused" : "playing") + " at " + mLastTimeUs);
46780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (IllegalStateException e) {
46790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mPausing) {
46800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // if we were pausing, get last estimated timestamp
46810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mPausing = false;
46820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (!monotonic || mLastReportedTime < mLastTimeUs) {
46830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            mLastReportedTime = mLastTimeUs;
46840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
46850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mPaused = true;
46860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (DEBUG) Log.d(TAG, "illegal state, but pausing: estimating at " + mLastReportedTime);
46870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return mLastReportedTime;
46880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
46890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // TODO get time when prepared
46900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    throw e;
46910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (monotonic && mLastTimeUs < mLastReportedTime) {
46930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    /* have to adjust time */
46940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mLastReportedTime - mLastTimeUs > 1000000) {
46950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // schedule seeked event if time jumped significantly
46960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // TODO: do this properly by introducing an exception
46970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mStopped = false;
46980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mSeeking = true;
46990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
47000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
47010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
47020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mLastReportedTime = mLastTimeUs;
47030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
47040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return mLastReportedTime;
47060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private class EventHandler extends Handler {
47100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public EventHandler(Looper looper) {
47110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                super(looper);
47120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Override
47150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void handleMessage(Message msg) {
47160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.what == NOTIFY) {
47170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    switch (msg.arg1) {
47180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_TIME:
47190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyTimedEvent(true /* refreshTime */);
47200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
47210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_STOP:
47220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyStop();
47230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
47240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_SEEK:
47250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifySeek();
47260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
47270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_TRACK_DATA:
47280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyTrackData((Pair<SubtitleTrack, byte[]>)msg.obj);
47290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
47300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
47310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
47320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
4735adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
4736adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    private abstract class Task implements Runnable {
4737adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        private final int mMediaCallType;
4738adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        private final boolean mNeedToWaitForEventToComplete;
473969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        private DataSourceDesc mDSD;
4740adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
4741adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        public Task (int mediaCallType, boolean needToWaitForEventToComplete) {
4742adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            mMediaCallType = mediaCallType;
4743adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            mNeedToWaitForEventToComplete = needToWaitForEventToComplete;
4744adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        }
4745adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
474669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        abstract void process() throws IOException, NoDrmSchemeException;
4747adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
4748adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        @Override
4749adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        public void run() {
475069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            int status = CALL_STATUS_NO_ERROR;
475169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            try {
475269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                process();
475369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            } catch (IllegalStateException e) {
475469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                status = CALL_STATUS_INVALID_OPERATION;
475569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            } catch (IllegalArgumentException e) {
475669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                status = CALL_STATUS_BAD_VALUE;
475769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            } catch (SecurityException e) {
475869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                status = CALL_STATUS_PERMISSION_DENIED;
475969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            } catch (IOException e) {
476069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                status = CALL_STATUS_ERROR_IO;
476169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            } catch (NoDrmSchemeException e) {
476269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                status = CALL_STATUS_NO_DRM_SCHEME;
476369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            } catch (Exception e) {
476469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                status = CALL_STATUS_ERROR_UNKNOWN;
476569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
476669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            synchronized (mSrcLock) {
476769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                mDSD = mCurrentDSD;
476869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
476969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
477069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            // TODO: Make native implementations asynchronous and let them send notifications.
477169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            if (!mNeedToWaitForEventToComplete || status != CALL_STATUS_NO_ERROR) {
477269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
477369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                sendCompleteNotification(status);
4774adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang
4775adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                synchronized (mTaskLock) {
4776adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                    mCurrentTask = null;
4777adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                    processPendingTask_l();
4778adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang                }
4779adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang            }
4780adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang        }
478169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang
478269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        private void sendCompleteNotification(int status) {
478369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            // In {@link #notifyWhenCommandLabelReached} case, a separate callback
478469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            // {#link #onCommandLabelReached} is already called in {@code process()}.
478569d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
478669d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                return;
478769d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
478869d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            synchronized (mEventCbLock) {
478969d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
479069d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                    cb.first.execute(() -> cb.second.onCallCompleted(
479169d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                            MediaPlayer2Impl.this, mDSD, mMediaCallType, status));
479269d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang                }
479369d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang            }
479469d2d51a59ecb30742673fbe56b68397185a08c5Dongwon Kang        }
4795adf77a01e8142a5abb496997beddead7b48f43b7Dongwon Kang    };
47960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
4797