MediaPlayer2Impl.java revision 8e5ef909c789d4d8825cf775d90fa9aa251f10b4
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;
270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.net.Uri;
280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Handler;
290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.HandlerThread;
300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Looper;
310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Message;
320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Parcel;
330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Parcelable;
340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.PersistableBundle;
350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.Process;
360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.PowerManager;
370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.os.SystemProperties;
380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.provider.Settings;
390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.system.ErrnoException;
400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.system.Os;
410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.system.OsConstants;
420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.Log;
430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.Pair;
440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.util.ArrayMap;
450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.view.Surface;
460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.view.SurfaceHolder;
470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.widget.VideoView;
480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.graphics.SurfaceTexture;
490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.media.SubtitleController.Anchor;
500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport android.media.SubtitleTrack.RenderingWidget;
510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport com.android.internal.annotations.GuardedBy;
530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport com.android.internal.util.Preconditions;
540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport dalvik.system.CloseGuard;
560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport libcore.io.IoBridge;
580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport libcore.io.Streams;
590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.ByteArrayOutputStream;
610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.File;
620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.FileDescriptor;
630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.FileInputStream;
640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.IOException;
650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.io.InputStream;
660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.lang.Runnable;
670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.lang.ref.WeakReference;
680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.CookieHandler;
690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.CookieManager;
700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.HttpCookie;
710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.HttpURLConnection;
720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.net.URL;
730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.nio.ByteOrder;
740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.ArrayList;
750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Arrays;
760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.BitSet;
770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Collections;
780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.concurrent.Executor;
790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.HashMap;
800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.HashSet;
810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.List;
820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Map;
830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Scanner;
840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Set;
850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.UUID;
860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiaimport java.util.Vector;
870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia/**
900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * MediaPlayer2 class can be used to control playback
910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * of audio/video files and streams. An example on how to use the methods in
920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * this class can be found in {@link android.widget.VideoView}.
930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p>Topics covered here are:
950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <ol>
960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <li><a href="#StateDiagram">State Diagram</a>
970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <li><a href="#Valid_and_Invalid_States">Valid and Invalid States</a>
980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <li><a href="#Permissions">Permissions</a>
990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <li><a href="#Callbacks">Register informational and error callbacks</a>
1000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * </ol>
1010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
1020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <div class="special reference">
1030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <h3>Developer Guides</h3>
1040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p>For more information about how to use MediaPlayer2, read the
1050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a> developer guide.</p>
1060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * </div>
1070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
1080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <a name="StateDiagram"></a>
1090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <h3>State Diagram</h3>
1100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
1110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p>Playback control of audio/video files and streams is managed as a state
1120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * machine. The following diagram shows the life cycle and the states of a
1130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * MediaPlayer2 object driven by the supported playback control operations.
1140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * The ovals represent the states a MediaPlayer2 object may reside
1150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * in. The arcs represent the playback control operations that drive the object
1160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * state transition. There are two types of arcs. The arcs with a single arrow
1170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * head represent synchronous method calls, while those with
1180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * a double arrow head represent asynchronous method calls.</p>
1190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
1200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p><img src="../../../images/mediaplayer_state_diagram.gif"
1210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         alt="MediaPlayer State diagram"
1220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         border="0" /></p>
1230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
1240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p>From this state diagram, one can see that a MediaPlayer2 object has the
1250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *    following states:</p>
1260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <ul>
1270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>When a MediaPlayer2 object is just created using <code>new</code> or
1280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         after {@link #reset()} is called, it is in the <em>Idle</em> state; and after
1290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #close()} is called, it is in the <em>End</em> state. Between these
1300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         two states is the life cycle of the MediaPlayer2 object.
1310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
1320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>There is a subtle but important difference between a newly constructed
1330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         MediaPlayer2 object and the MediaPlayer2 object after {@link #reset()}
1340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         is called. It is a programming error to invoke methods such
1350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         as {@link #getCurrentPosition()},
1360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #getDuration()}, {@link #getVideoHeight()},
1370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
1380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #setLooping(boolean)},
1390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #setVolume(float, float)}, {@link #pause()}, {@link #play()},
1400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #seekTo(long, int)}, {@link #prepare()} or
1410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these
1420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         methods is called right after a MediaPlayer2 object is constructed,
1430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the user supplied callback method OnErrorListener.onError() won't be
1440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         called by the internal player engine and the object state remains
1450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         unchanged; but if these methods are called right after {@link #reset()},
1460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the user supplied callback method OnErrorListener.onError() will be
1470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invoked by the internal player engine and the object will be
1480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         transfered to the <em>Error</em> state. </li>
1490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>It is also recommended that once
1500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         a MediaPlayer2 object is no longer being used, call {@link #close()} immediately
1510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         so that resources used by the internal player engine associated with the
1520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         MediaPlayer2 object can be released immediately. Resource may include
1530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         singleton resources such as hardware acceleration components and
1540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         failure to call {@link #close()} may cause subsequent instances of
1550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         MediaPlayer2 objects to fallback to software implementations or fail
1560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         altogether. Once the MediaPlayer2
1570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object is in the <em>End</em> state, it can no longer be used and
1580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         there is no way to bring it back to any other state. </li>
1590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>Furthermore,
1600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the MediaPlayer2 objects created using <code>new</code> is in the
1610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <em>Idle</em> state.
1620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
1630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </ul>
1640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
1650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>In general, some playback control operation may fail due to various
1660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         reasons, such as unsupported audio/video format, poorly interleaved
1670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         audio/video, resolution too high, streaming timeout, and the like.
1680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         Thus, error reporting and recovery is an important concern under
1690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         these circumstances. Sometimes, due to programming errors, invoking a playback
1700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         control operation in an invalid state may also occur. Under all these
1710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         error conditions, the internal player engine invokes a user supplied
1720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         EventCallback.onError() method if an EventCallback has been
1730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         registered beforehand via
1740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #registerEventCallback(Executor, EventCallback)}.
1750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
1760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>It is important to note that once an error occurs, the
1770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         MediaPlayer2 object enters the <em>Error</em> state (except as noted
1780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         above), even if an error listener has not been registered by the application.</li>
1790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>In order to reuse a MediaPlayer2 object that is in the <em>
1800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         Error</em> state and recover from the error,
1810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #reset()} can be called to restore the object to its <em>Idle</em>
1820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         state.</li>
1830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>It is good programming practice to have your application
1840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         register a OnErrorListener to look out for error notifications from
1850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the internal player engine.</li>
1860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>IllegalStateException is
1870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         thrown to prevent programming errors such as calling {@link #prepare()},
1880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #prepareAsync()}, {@link #setDataSource(DataSourceDesc)}, or
1890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@code setPlaylist} methods in an invalid state. </li>
1900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </ul>
1910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
1920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>Calling
1930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #setDataSource(DataSourceDesc)}, or
1940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@code setPlaylist} transfers a
1950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         MediaPlayer2 object in the <em>Idle</em> state to the
1960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <em>Initialized</em> state.
1970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
1980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>An IllegalStateException is thrown if
1990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         setDataSource() or setPlaylist() is called in any other state.</li>
2000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>It is good programming
2010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         practice to always look out for <code>IllegalArgumentException</code>
2020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         and <code>IOException</code> that may be thrown from
2030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <code>setDataSource</code> and <code>setPlaylist</code> methods.</li>
2040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </ul>
2050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
2060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>A MediaPlayer2 object must first enter the <em>Prepared</em> state
2070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         before playback can be started.
2080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
2090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>There are two ways (synchronous vs.
2100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         asynchronous) that the <em>Prepared</em> state can be reached:
2110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         either a call to {@link #prepare()} (synchronous) which
2120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         transfers the object to the <em>Prepared</em> state once the method call
2130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         returns, or a call to {@link #prepareAsync()} (asynchronous) which
2140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         first transfers the object to the <em>Preparing</em> state after the
2150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         call returns (which occurs almost right way) while the internal
2160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         player engine continues working on the rest of preparation work
2170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         until the preparation work completes. When the preparation completes or when {@link #prepare()} call returns,
2180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the internal player engine then calls a user supplied callback method,
2190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         onPrepared() of the EventCallback interface, if an
2200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         EventCallback is registered beforehand via {@link
2210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         #registerEventCallback(Executor, EventCallback)}.</li>
2220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>It is important to note that
2230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the <em>Preparing</em> state is a transient state, and the behavior
2240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         of calling any method with side effect while a MediaPlayer2 object is
2250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         in the <em>Preparing</em> state is undefined.</li>
2260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>An IllegalStateException is
2270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         thrown if {@link #prepare()} or {@link #prepareAsync()} is called in
2280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         any other state.</li>
2290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>While in the <em>Prepared</em> state, properties
2300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         such as audio/sound volume, screenOnWhilePlaying, looping can be
2310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         adjusted by invoking the corresponding set methods.</li>
2320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </ul>
2330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
2340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>To start the playback, {@link #play()} must be called. After
2350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #play()} returns successfully, the MediaPlayer2 object is in the
2360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <em>Started</em> state. {@link #isPlaying()} can be called to test
2370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         whether the MediaPlayer2 object is in the <em>Started</em> state.
2380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
2390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>While in the <em>Started</em> state, the internal player engine calls
2400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         a user supplied EventCallback.onBufferingUpdate() callback
2410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         method if an EventCallback has been registered beforehand
2420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         via {@link #registerEventCallback(Executor, EventCallback)}.
2430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         This callback allows applications to keep track of the buffering status
2440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         while streaming audio/video.</li>
2450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>Calling {@link #play()} has not effect
2460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         on a MediaPlayer2 object that is already in the <em>Started</em> state.</li>
2470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </ul>
2480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
2490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>Playback can be paused and stopped, and the current playback position
2500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         can be adjusted. Playback can be paused via {@link #pause()}. When the call to
2510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #pause()} returns, the MediaPlayer2 object enters the
2520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <em>Paused</em> state. Note that the transition from the <em>Started</em>
2530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         state to the <em>Paused</em> state and vice versa happens
2540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         asynchronously in the player engine. It may take some time before
2550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the state is updated in calls to {@link #isPlaying()}, and it can be
2560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         a number of seconds in the case of streamed content.
2570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
2580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>Calling {@link #play()} to resume playback for a paused
2590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         MediaPlayer2 object, and the resumed playback
2600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         position is the same as where it was paused. When the call to
2610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #play()} returns, the paused MediaPlayer2 object goes back to
2620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the <em>Started</em> state.</li>
2630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>Calling {@link #pause()} has no effect on
2640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         a MediaPlayer2 object that is already in the <em>Paused</em> state.</li>
2650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </ul>
2660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
2670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>The playback position can be adjusted with a call to
2680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #seekTo(long, int)}.
2690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
2700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>Although the asynchronuous {@link #seekTo(long, int)}
2710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         call returns right away, the actual seek operation may take a while to
2720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         finish, especially for audio/video being streamed. When the actual
2730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         seek operation completes, the internal player engine calls a user
2740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         supplied EventCallback.onSeekComplete() if an EventCallback
2750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         has been registered beforehand via
2760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #registerEventCallback(Executor, EventCallback)}.</li>
2770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>Please
2780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         note that {@link #seekTo(long, int)} can also be called in the other states,
2790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted
2800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </em> state. When {@link #seekTo(long, int)} is called in those states,
2810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         one video frame will be displayed if the stream has video and the requested
2820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         position is valid.
2830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
2840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>Furthermore, the actual current playback position
2850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         can be retrieved with a call to {@link #getCurrentPosition()}, which
2860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         is helpful for applications such as a Music player that need to keep
2870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         track of the playback progress.</li>
2880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </ul>
2890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </li>
2900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <li>When the playback reaches the end of stream, the playback completes.
2910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <ul>
2920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>If the looping mode was being set to <var>true</var>with
2930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         {@link #setLooping(boolean)}, the MediaPlayer2 object shall remain in
2940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the <em>Started</em> state.</li>
2950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>If the looping mode was set to <var>false
2960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </var>, the player engine calls a user supplied callback method,
2970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         EventCallback.onCompletion(), if an EventCallback is registered
2980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         beforehand via {@link #registerEventCallback(Executor, EventCallback)}.
2990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         The invoke of the callback signals that the object is now in the <em>
3000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         PlaybackCompleted</em> state.</li>
3010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         <li>While in the <em>PlaybackCompleted</em>
3020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         state, calling {@link #play()} can restart the playback from the
3030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         beginning of the audio/video source.</li>
3040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * </ul>
3050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
3060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
3070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <a name="Valid_and_Invalid_States"></a>
3080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <h3>Valid and invalid states</h3>
3090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
3100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <table border="0" cellspacing="0" cellpadding="0">
3110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>Method Name </p></td>
3120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Valid Sates </p></td>
3130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Invalid States </p></td>
3140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Comments </p></td></tr>
3150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>attachAuxEffect </p></td>
3160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
3170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Error} </p></td>
3180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method must be called after setDataSource or setPlaylist.
3190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     Calling it does not change the object state. </p></td></tr>
3200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>getAudioSessionId </p></td>
3210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
3220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
3230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
3240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state. </p></td></tr>
3250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>getCurrentPosition </p></td>
3260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
3270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         PlaybackCompleted} </p></td>
3280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
3290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state does not change the
3300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         state. Calling this method in an invalid state transfers the object
3310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         to the <em>Error</em> state. </p></td></tr>
3320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>getDuration </p></td>
3330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
3340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Error} </p></td>
3350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state does not change the
3360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         state. Calling this method in an invalid state transfers the object
3370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         to the <em>Error</em> state. </p></td></tr>
3380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>getVideoHeight </p></td>
3390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
3400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         PlaybackCompleted}</p></td>
3410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
3420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state does not change the
3430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         state. Calling this method in an invalid state transfers the object
3440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         to the <em>Error</em> state.  </p></td></tr>
3450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>getVideoWidth </p></td>
3460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
3470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         PlaybackCompleted}</p></td>
3480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
3490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state does not change
3500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the state. Calling this method in an invalid state transfers the
3510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Error</em> state. </p></td></tr>
3520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>isPlaying </p></td>
3530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
3540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *          PlaybackCompleted}</p></td>
3550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
3560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state does not change
3570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the state. Calling this method in an invalid state transfers the
3580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Error</em> state. </p></td></tr>
3590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>pause </p></td>
3600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Started, Paused, PlaybackCompleted}</p></td>
3610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Prepared, Stopped, Error}</p></td>
3620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state transfers the
3630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Paused</em> state. Calling this method in an
3640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
3650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>prepare </p></td>
3660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Stopped} </p></td>
3670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td>
3680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state transfers the
3690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Prepared</em> state. Calling this method in an
3700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state throws an IllegalStateException.</p></td></tr>
3710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>prepareAsync </p></td>
3720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Stopped} </p></td>
3730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td>
3740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state transfers the
3750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Preparing</em> state. Calling this method in an
3760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state throws an IllegalStateException.</p></td></tr>
3770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>release </p></td>
3780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
3790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
3800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>After {@link #close()}, the object is no longer available. </p></td></tr>
3810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>reset </p></td>
3820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
3830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         PlaybackCompleted, Error}</p></td>
3840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{}</p></td>
3850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>After {@link #reset()}, the object is like being just created.</p></td></tr>
3860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>seekTo </p></td>
3870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Paused, PlaybackCompleted} </p></td>
3880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Stopped, Error}</p></td>
3890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state does not change
3900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the state. Calling this method in an invalid state transfers the
3910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Error</em> state. </p></td></tr>
3920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setAudioAttributes </p></td>
3930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
3940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *          PlaybackCompleted}</p></td>
3950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
3960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state. In order for the
3970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         target audio attributes type to become effective, this method must be called before
3980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         prepare() or prepareAsync().</p></td></tr>
3990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setAudioSessionId </p></td>
4000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle} </p></td>
4010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
4020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *          Error} </p></td>
4030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method must be called in idle state as the audio session ID must be known before
4040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         calling setDataSource or setPlaylist. Calling it does not change the object
4050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         state. </p></td></tr>
4060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setAudioStreamType (deprecated)</p></td>
4070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
4080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *          PlaybackCompleted}</p></td>
4090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
4100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state. In order for the
4110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         target audio stream type to become effective, this method must be called before
4120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         prepare() or prepareAsync().</p></td></tr>
4130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setAuxEffectSendLevel </p></td>
4140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any</p></td>
4150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Calling this method does not change the object state. </p></td></tr>
4170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setDataSource </p></td>
4180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle} </p></td>
4190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
4200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *          Error} </p></td>
4210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state transfers the
4220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Initialized</em> state. Calling this method in an
4230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state throws an IllegalStateException.</p></td></tr>
4240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setPlaylist </p></td>
4250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle} </p></td>
4260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
4270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *          Error} </p></td>
4280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state transfers the
4290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Initialized</em> state. Calling this method in an
4300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state throws an IllegalStateException.</p></td></tr>
4310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setDisplay </p></td>
4320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
4330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
4350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state. </p></td></tr>
4360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setSurface </p></td>
4370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
4380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
4400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state. </p></td></tr>
4410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setVideoScalingMode </p></td>
4420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
4430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Error}</p></td>
4440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state.</p></td></tr>
4450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setLooping </p></td>
4460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
4470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         PlaybackCompleted}</p></td>
4480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
4490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state does not change
4500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the state. Calling this method in an
4510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
4520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>isLooping </p></td>
4530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
4540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
4560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state. </p></td></tr>
4570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>registerDrmEventCallback </p></td>
4580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
4590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
4610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state. </p></td></tr>
4620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>registerEventCallback </p></td>
4630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
4640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
4660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state. </p></td></tr>
4670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setPlaybackParams</p></td>
4680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Initialized, Prepared, Started, Paused, PlaybackCompleted, Error}</p></td>
4690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Stopped} </p></td>
4700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method will change state in some cases, depending on when it's called.
4710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         </p></td></tr>
4720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setScreenOnWhilePlaying</></td>
4730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
4740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
4760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state.  </p></td></tr>
4770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setVolume </p></td>
4780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
4790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *          PlaybackCompleted}</p></td>
4800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Error}</p></td>
4810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state.
4820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>setWakeMode </p></td>
4830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>any </p></td>
4840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{} </p></td>
4850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>This method can be called in any state and calling it does not change
4860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         the object state.</p></td></tr>
4870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>start </p></td>
4880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Paused, PlaybackCompleted}</p></td>
4890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Stopped, Error}</p></td>
4900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state transfers the
4910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Started</em> state. Calling this method in an
4920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
4930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>stop </p></td>
4940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
4950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Error}</p></td>
4960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method in a valid state transfers the
4970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         object to the <em>Stopped</em> state. Calling this method in an
4980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
4990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>getTrackInfo </p></td>
5000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
5010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Error}</p></td>
5020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state.</p></td></tr>
5030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>addTimedTextSource </p></td>
5040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
5050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Error}</p></td>
5060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state.</p></td></tr>
5070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>selectTrack </p></td>
5080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
5090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Error}</p></td>
5100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state.</p></td></tr>
5110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <tr><td>deselectTrack </p></td>
5120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
5130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>{Idle, Initialized, Error}</p></td>
5140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     <td>Successful invoke of this method does not change the state.</p></td></tr>
5150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
5160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * </table>
5170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
5180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <a name="Permissions"></a>
5190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <h3>Permissions</h3>
5200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p>One may need to declare a corresponding WAKE_LOCK permission {@link
5210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
5220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * element.
5230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
5240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
5250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * when used with network-based content.
5260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
5270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <a name="Callbacks"></a>
5280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <h3>Callbacks</h3>
5290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * <p>Applications may want to register for informational and error
5300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * events in order to be informed of some internal state update and
5310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * possible runtime errors during playback or streaming. Registration for
5320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * these events is done by properly setting the appropriate listeners (via calls
5330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * to
5340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * {@link #registerEventCallback(Executor, EventCallback)},
5350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * {@link #registerDrmEventCallback(Executor, DrmEventCallback)}).
5360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * In order to receive the respective callback
5370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * associated with these listeners, applications are required to create
5380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * MediaPlayer2 objects on a thread with its own Looper running (main UI
5390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * thread by default has a Looper running).
5400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
5410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * @hide
5420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia */
5430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiapublic final class MediaPlayer2Impl extends MediaPlayer2 {
5440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    static {
5450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        System.loadLibrary("media2_jni");
5460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_init();
5470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
5480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final static String TAG = "MediaPlayer2Impl";
5500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private long mNativeContext; // accessed by native methods
5520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private long mNativeSurfaceTexture;  // accessed by native methods
5530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mListenerContext; // accessed by native methods
5540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private SurfaceHolder mSurfaceHolder;
5550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private EventHandler mEventHandler;
5560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private PowerManager.WakeLock mWakeLock = null;
5570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mScreenOnWhilePlaying;
5580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mStayAwake;
5590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
5600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mUsage = -1;
5610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mBypassInterruptionPolicy;
5620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final CloseGuard mGuard = CloseGuard.get();
5630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private List<DataSourceDesc> mPlaylist;
5650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mPLCurrentIndex = 0;
5660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mPLNextIndex = -1;
5670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mLoopingMode = LOOPING_MODE_NONE;
5680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM
5700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private UUID mDrmUUID;
5710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mDrmLock = new Object();
5720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private DrmInfoImpl mDrmInfoImpl;
5730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private MediaDrm mDrmObj;
5740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private byte[] mDrmSessionId;
5750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmInfoResolved;
5760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mActiveDrmScheme;
5770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmConfigAllowed;
5780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mDrmProvisioningInProgress;
5790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean mPrepareDrmInProgress;
5800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private ProvisioningThread mDrmProvisioningThread;
5810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
5830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Default constructor.
5840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>When done with the MediaPlayer2Impl, you should call  {@link #close()},
5850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to free the resources. If not released, too many MediaPlayer2Impl instances may
5860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * result in an exception.</p>
5870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
5880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaPlayer2Impl() {
5890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Looper looper;
5900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ((looper = Looper.myLooper()) != null) {
5910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(this, looper);
5920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if ((looper = Looper.getMainLooper()) != null) {
5930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(this, looper);
5940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
5950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = null;
5960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
5970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
5980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mTimeProvider = new TimeProvider(this);
5990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOpenSubtitleSources = new Vector<InputStream>();
6000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mGuard.open("close");
6010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* Native setup requires a weak reference to our object.
6030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * It's easier to create it here than in C++.
6040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
6050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_setup(new WeakReference<MediaPlayer2Impl>(this));
6060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
6090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Update the MediaPlayer2Impl SurfaceTexture.
6100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Call after setting a new display surface.
6110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _setVideoSurface(Surface surface);
6130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /* Do not change these values (starting with INVOKE_ID) without updating
6150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * their counterparts in include/media/mediaplayer2.h!
6160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int INVOKE_ID_GET_TRACK_INFO = 1;
6180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE = 2;
6190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3;
6200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int INVOKE_ID_SELECT_TRACK = 4;
6210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int INVOKE_ID_DESELECT_TRACK = 5;
6220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int INVOKE_ID_SET_VIDEO_SCALE_MODE = 6;
6230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
6240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Create a request parcel which can be routed to the native media
6270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * player using {@link #invoke(Parcel, Parcel)}. The Parcel
6280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * returned has the proper InterfaceToken set. The caller should
6290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * not overwrite that token, i.e it can only append data to the
6300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Parcel.
6310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return A parcel suitable to hold a request for the native
6330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * player.
6340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
6350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public Parcel newRequest() {
6380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel parcel = Parcel.obtain();
6390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return parcel;
6400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Invoke a generic method on the native player using opaque
6440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * parcels for the request and reply. Both payloads' format is a
6450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * convention between the java caller and the native player.
6460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Must be called after setDataSource or setPlaylist to make sure a native player
6470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * exists. On failure, a RuntimeException is thrown.
6480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param request Parcel with the data for the extension. The
6500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * caller must use {@link #newRequest()} to get one.
6510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param reply Output parcel with the data returned by the
6530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * native player.
6540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
6550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void invoke(Parcel request, Parcel reply) {
6580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int retcode = native_invoke(request, reply);
6590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        reply.setDataPosition(0);
6600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (retcode != 0) {
6610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new RuntimeException("failure code: " + retcode);
6620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
6630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the {@link SurfaceHolder} to use for displaying the video
6670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * portion of the media.
6680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Either a surface holder or surface must be set if a display or video sink
6700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is needed.  Not calling this method or {@link #setSurface(Surface)}
6710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when playing back a video will result in only the audio track being played.
6720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A null surface holder or surface will result in only the audio track being
6730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * played.
6740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
6750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param sh the SurfaceHolder to use for video display
6760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
6770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
6780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
6790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
6800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
6810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setDisplay(SurfaceHolder sh) {
6820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSurfaceHolder = sh;
6830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Surface surface;
6840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (sh != null) {
6850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            surface = sh.getSurface();
6860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
6870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            surface = null;
6880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
6890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _setVideoSurface(surface);
6900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
6910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
6920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
6930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
6940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the {@link Surface} to be used as the sink for the video portion of
6950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but
6960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * does not support {@link #setScreenOnWhilePlaying(boolean)}.  Setting a
6970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Surface will un-set any Surface or SurfaceHolder that was previously set.
6980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A null surface will result in only the audio track being played.
6990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps
7010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * returned from {@link SurfaceTexture#getTimestamp()} will have an
7020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * unspecified zero point.  These timestamps cannot be directly compared
7030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * between different media sources, different instances of the same media
7040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * source, or multiple runs of the same program.  The timestamp is normally
7050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * monotonically increasing and is unaffected by time-of-day adjustments,
7060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * but it is reset when the position is set.
7070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param surface The {@link Surface} to be used for the video portion of
7090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the media.
7100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
7110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
7120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
7130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
7140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setSurface(Surface surface) {
7150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mScreenOnWhilePlaying && surface != null) {
7160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
7170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
7180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSurfaceHolder = null;
7190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _setVideoSurface(surface);
7200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
7210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets video scaling mode. To make the target video scaling mode
7250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * effective during playback, this method must be called after
7260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * data source is set. If not called, the default video
7270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}.
7280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p> The supported video scaling modes are:
7300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <ul>
7310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}
7320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING}
7330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </ul>
7340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode target video scaling mode. Must be one of the supported
7360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * video scaling modes; otherwise, IllegalArgumentException will be thrown.
7370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT
7390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
7400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
7410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
7420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
7430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setVideoScalingMode(int mode) {
7440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!isVideoScalingModeSupported(mode)) {
7450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Scaling mode " + mode + " is not supported";
7460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
7470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
7480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
7490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
7500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
7510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE);
7520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(mode);
7530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
7540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
7550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
7560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
7570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
7580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Discards all pending commands.
7620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
7630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
7640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void clearPendingCommands() {
7650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the data source as described by a DataSourceDesc.
7690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param dsd the descriptor of data source you want to play
7710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
7720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException if dsd is null
7730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
7740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
7750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setDataSource(@NonNull DataSourceDesc dsd) throws IOException {
7760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
7770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
7780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPlaylist.add(dsd);
7790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPLCurrentIndex = 0;
7800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setDataSourcePriv(dsd);
7810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the current data source as described by a DataSourceDesc.
7850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the current DataSourceDesc
7870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
7880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
7890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public DataSourceDesc getCurrentDataSource() {
7900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
7910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
7920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
7930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mPlaylist.get(mPLCurrentIndex);
7940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
7950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
7960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
7970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the play list.
7980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
7990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If startIndex falls outside play list range, it will be clamped to the nearest index
8000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in the play list.
8010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
8020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param pl the play list of data source you want to play
8030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param startIndex the index of the DataSourceDesc in the play list you want to play first
8040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
8050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if pl is null or empty, or pl contains null DataSourceDesc
8060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
8070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
8080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setPlaylist(@NonNull List<DataSourceDesc> pl, int startIndex)
8090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
8100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (pl == null || pl.size() == 0) {
8110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("play list cannot be null or empty.");
8120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        HashSet ids = new HashSet(pl.size());
8140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (DataSourceDesc dsd : pl) {
8150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (dsd == null) {
8160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalArgumentException("DataSourceDesc in play list cannot be null.");
8170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
8180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (ids.add(dsd.getId()) == false) {
8190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalArgumentException("DataSourceDesc Id in play list should be unique.");
8200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
8210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (startIndex < 0) {
8240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            startIndex = 0;
8250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (startIndex >= pl.size()) {
8260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            startIndex = pl.size() - 1;
8270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPlaylist = Collections.synchronizedList(new ArrayList(pl));
8300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPLCurrentIndex = startIndex;
8310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setDataSourcePriv(mPlaylist.get(startIndex));
8320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: handle the preparation of next source in the play list.
8330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // It should be processed after current source is prepared.
8340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
8370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets a copy of the play list.
8380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
8390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return a copy of the play list used by {@link MediaPlayer2}
8400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
8410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
8420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public List<DataSourceDesc> getPlaylist() {
8430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
8440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
8450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return new ArrayList(mPlaylist);
8470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
8500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the index of current DataSourceDesc in the play list to be played.
8510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
8520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of DataSourceDesc in the play list you want to play
8530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the play list is null
8540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException if index is outside play list range
8550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
8560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
8570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setCurrentPlaylistItem(int index) {
8580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
8590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("play list has not been set yet.");
8600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (index < 0 || index >= mPlaylist.size()) {
8620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IndexOutOfBoundsException("index is out of play list range.");
8630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (index == mPLCurrentIndex) {
8660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
8670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: in playing state, stop current source and start to play source of index.
8700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPLCurrentIndex = index;
8710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
8740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the index of next-to-be-played DataSourceDesc in the play list.
8750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
8760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of next-to-be-played DataSourceDesc in the play list
8770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the play list is null
8780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException if index is outside play list range
8790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
8800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
8810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setNextPlaylistItem(int index) {
8820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
8830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("play list has not been set yet.");
8840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (index < 0 || index >= mPlaylist.size()) {
8860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IndexOutOfBoundsException("index is out of play list range.");
8870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (index == mPLNextIndex) {
8900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
8910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
8920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: prepare the new next-to-be-played DataSourceDesc
8940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPLNextIndex = index;
8950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
8960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
8970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
8980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the current index of play list.
8990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the index of the current DataSourceDesc in the play list
9010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
9020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
9030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int getCurrentPlaylistItemIndex() {
9040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mPLCurrentIndex;
9050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the looping mode of the play list.
9090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The mode shall be one of {@link #LOOPING_MODE_NONE}, {@link #LOOPING_MODE_FULL},
9100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #LOOPING_MODE_SINGLE}, {@link #LOOPING_MODE_SHUFFLE}.
9110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode the mode in which the play list will be played
9130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if mode is not supported
9140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
9150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
9160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setLoopingMode(@LoopingMode int mode) {
9170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mode != LOOPING_MODE_NONE
9180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            && mode != LOOPING_MODE_FULL
9190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            && mode != LOOPING_MODE_SINGLE
9200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            && mode != LOOPING_MODE_SHUFFLE) {
9210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("mode is not supported.");
9220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mLoopingMode = mode;
9240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
9250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
9260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: handle the new mode if necessary.
9290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the looping mode of play list.
9330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the looping mode of the play list
9350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
9360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
9370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int getLoopingMode() {
9380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mPLCurrentIndex;
9390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Moves the DataSourceDesc at indexFrom in the play list to indexTo.
9430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the play list is null
9450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IndexOutOfBoundsException if indexFrom or indexTo is outside play list range
9460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
9470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
9480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void movePlaylistItem(int indexFrom, int indexTo) {
9490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
9500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("play list has not been set yet.");
9510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: move the DataSourceDesc from indexFrom to indexTo.
9530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Removes the DataSourceDesc at index in the play list.
9570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If index is same as the current index of the play list, current DataSourceDesc
9590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * will be stopped and playback moves to next source in the list.
9600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the removed DataSourceDesc at index in the play list
9620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the play list is null
9630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IndexOutOfBoundsException if index is outside play list range
9640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
9650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
9660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public DataSourceDesc removePlaylistItem(int index) {
9670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
9680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("play list has not been set yet.");
9690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
9700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        DataSourceDesc oldDsd = mPlaylist.remove(index);
9720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: if index == mPLCurrentIndex, stop current source and move to next one.
9730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // if index == mPLNextIndex, prepare the new next-to-be-played source.
9740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return oldDsd;
9750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
9760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
9780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Inserts the DataSourceDesc to the play list at position index.
9790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This will not change the DataSourceDesc currently being played.
9810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If index is less than or equal to the current index of the play list,
9820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the current index of the play list will be incremented correspondingly.
9830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
9840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index you want to add dsd to the play list
9850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param dsd the descriptor of data source you want to add to the play list
9860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IndexOutOfBoundsException if index is outside play list range
9870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException if dsd is null
9880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
9890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
9900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addPlaylistItem(int index, DataSourceDesc dsd) {
9910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
9920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
9930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mPlaylist == null) {
9940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (index == 0) {
9950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
9960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPlaylist.add(dsd);
9970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPLCurrentIndex = 0;
9980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
9990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
10000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
10010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long id = dsd.getId();
10040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (DataSourceDesc pldsd : mPlaylist) {
10050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (id == pldsd.getId()) {
10060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalArgumentException("Id of dsd already exists in the play list.");
10070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
10080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mPlaylist.add(index, dsd);
10110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (index <= mPLCurrentIndex) {
10120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            ++mPLCurrentIndex;
10130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * replaces the DataSourceDesc at index in the play list with given dsd.
10180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
10190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When index is same as the current index of the play list, the current source
10200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * will be stopped and the new source will be played, except that if new
10210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and old source only differ on end position and current media position is
10220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * smaller then the new end position.
10230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
10240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This will not change the DataSourceDesc currently being played.
10250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If index is less than or equal to the current index of the play list,
10260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the current index of the play list will be incremented correspondingly.
10270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
10280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index you want to add dsd to the play list
10290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param dsd the descriptor of data source you want to add to the play list
10300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IndexOutOfBoundsException if index is outside play list range
10310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException if dsd is null
10320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
10330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
10340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public DataSourceDesc editPlaylistItem(int index, DataSourceDesc dsd) {
10350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
10360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(mPlaylist, "the play list cannot be null");
10370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long id = dsd.getId();
10390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (int i = 0; i < mPlaylist.size(); ++i) {
10400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (i == index) {
10410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                continue;
10420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
10430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (id == mPlaylist.get(i).getId()) {
10440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalArgumentException("Id of dsd already exists in the play list.");
10450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
10460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: if needed, stop playback of current source, and start new dsd.
10490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
10500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mPlaylist.set(index, dsd);
10510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void setDataSourcePriv(@NonNull DataSourceDesc dsd) throws IOException {
10540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
10550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (dsd.getType()) {
10570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_CALLBACK:
10580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                setDataSourcePriv(dsd.getId(),
10590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getMedia2DataSource());
10600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
10610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_FD:
10630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                setDataSourcePriv(dsd.getId(),
10640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getFileDescriptor(),
10650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getFileDescriptorOffset(),
10660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getFileDescriptorLength());
10670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
10680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case DataSourceDesc.TYPE_URI:
10700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                setDataSourcePriv(dsd.getId(),
10710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getUriContext(),
10720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getUri(),
10730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getUriHeaders(),
10740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  dsd.getUriCookies());
10750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
10760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
10780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
10790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
10800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
10810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
10820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
10830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * To provide cookies for the subsequent HTTP requests, you can install your own default cookie
10840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * handler and use other variants of setDataSource APIs instead. Alternatively, you can use
10850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this API to pass the cookies as a list of HttpCookie. If the app has not installed
10860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a CookieHandler already, this API creates a CookieManager and populates its CookieStore with
10870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the provided cookies. If the app has installed its own handler already, this API requires the
10880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * handler to be of CookieManager type such that the API can update the manager’s CookieStore.
10890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
10900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p><strong>Note</strong> that the cross domain redirection is allowed by default,
10910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * but that can be changed with key/value pairs through the headers parameter with
10920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
10930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * disallow or allow cross domain redirection.
10940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
10950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if cookies are provided and the installed handler is not
10960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                  a CookieManager
10970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException    if it is called in an invalid state
10980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NullPointerException     if context or uri is null
10990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException              if uri has a file scheme and an I/O error occurs
11000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
11010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void setDataSourcePriv(long srcId, @NonNull Context context, @NonNull Uri uri,
11020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
11030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
11040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (context == null) {
11050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new NullPointerException("context param can not be null.");
11060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (uri == null) {
11090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new NullPointerException("uri param can not be null.");
11100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (cookies != null) {
11130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            CookieHandler cookieHandler = CookieHandler.getDefault();
11140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
11150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalArgumentException("The cookie handler has to be of CookieManager "
11160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        + "type when cookies are provided.");
11170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // The context and URI usually belong to the calling user. Get a resolver for that user
11210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // and strip out the userId from the URI if present.
11220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final ContentResolver resolver = context.getContentResolver();
11230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String scheme = uri.getScheme();
11240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
11250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
11260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setDataSourcePriv(srcId, uri.getPath(), null, null);
11270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
11280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
11290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                && Settings.AUTHORITY.equals(authority)) {
11300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Try cached ringtone first since the actual provider may not be
11310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // encryption aware, or it may be stored on CE media storage
11320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int type = RingtoneManager.getDefaultType(uri);
11330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
11340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
11350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (attemptDataSource(srcId, resolver, cacheUri)) {
11360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
11370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else if (attemptDataSource(srcId, resolver, actualUri)) {
11380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
11390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
11400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                setDataSourcePriv(srcId, uri.toString(), headers, cookies);
11410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
11430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Try requested Uri locally first, or fallback to media server
11440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (attemptDataSource(srcId, resolver, uri)) {
11450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
11460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
11470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                setDataSourcePriv(srcId, uri.toString(), headers, cookies);
11480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean attemptDataSource(long srcId, ContentResolver resolver, Uri uri) {
11530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
11540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (afd.getDeclaredLength() < 0) {
11550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                setDataSourcePriv(srcId, afd.getFileDescriptor(), 0, DataSourceDesc.LONG_MAX);
11560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
11570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                setDataSourcePriv(srcId,
11580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  afd.getFileDescriptor(),
11590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  afd.getStartOffset(),
11600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                  afd.getDeclaredLength());
11610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return true;
11630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (NullPointerException | SecurityException | IOException ex) {
11640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "Couldn't open " + uri + ": " + ex);
11650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return false;
11660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void setDataSourcePriv(
11700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long srcId, String path, Map<String, String> headers, List<HttpCookie> cookies)
11710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
11720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
11730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String[] keys = null;
11740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String[] values = null;
11750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (headers != null) {
11770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            keys = new String[headers.size()];
11780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            values = new String[headers.size()];
11790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
11810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (Map.Entry<String, String> entry: headers.entrySet()) {
11820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                keys[i] = entry.getKey();
11830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                values[i] = entry.getValue();
11840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                ++i;
11850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
11860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
11870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setDataSourcePriv(srcId, path, keys, values, cookies);
11880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
11890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
11900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void setDataSourcePriv(long srcId, String path, String[] keys, String[] values,
11910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            List<HttpCookie> cookies)
11920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
11930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final Uri uri = Uri.parse(path);
11940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final String scheme = uri.getScheme();
11950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ("file".equals(scheme)) {
11960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            path = uri.getPath();
11970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (scheme != null) {
11980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // handle non-file sources
11990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            nativeSetDataSource(
12000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Media2HTTPService.createHTTPService(path, cookies),
12010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                path,
12020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                keys,
12030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                values);
12040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
12050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final File file = new File(path);
12080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (file.exists()) {
12090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileInputStream is = new FileInputStream(file);
12100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileDescriptor fd = is.getFD();
12110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setDataSourcePriv(srcId, fd, 0, DataSourceDesc.LONG_MAX);
12120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            is.close();
12130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
12140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IOException("setDataSourcePriv failed.");
12150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void nativeSetDataSource(
12190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Media2HTTPService httpService, String path, String[] keys, String[] values)
12200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
12210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
12240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
12250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to close the file descriptor. It is safe to do so as soon as this call returns.
12260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
12280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if fd is not a valid FileDescriptor
12290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if fd can not be read
12300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void setDataSourcePriv(long srcId, FileDescriptor fd, long offset, long length)
12320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
12330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _setDataSource(fd, offset, length);
12340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _setDataSource(FileDescriptor fd, long offset, long length)
12370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException;
12380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
12410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
12420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void setDataSourcePriv(long srcId, Media2DataSource dataSource) {
12440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _setDataSource(dataSource);
12450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _setDataSource(Media2DataSource dataSource);
12480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Prepares the player for playback, synchronously.
12510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * After setting the datasource and the display surface, you need to either
12530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
12540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * which blocks until MediaPlayer2 is ready for playback.
12550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if source can not be accessed
12570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
12580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
12590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void prepare() throws IOException {
12620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _prepare();
12630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        scanInternalSubtitleTracks();
12640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // DrmInfo, if any, has been resolved by now.
12660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
12670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmInfoResolved = true;
12680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
12690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _prepare() throws IOException, IllegalStateException;
12720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Prepares the player for playback, asynchronously.
12750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * After setting the datasource and the display surface, you need to either
12770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * call prepare() or prepareAsync(). For streams, you should call prepareAsync(),
12780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * which returns immediately, rather than blocking until enough data has been
12790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * buffered.
12800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
12820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void prepareAsync();
12850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
12860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
12870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Starts or resumes playback. If playback had previously been paused,
12880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * playback will continue from where it was paused. If playback had
12890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * been stopped, or never started before, playback will start at the
12900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * beginning.
12910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
12920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
12930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
12940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
12950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void play() {
12960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(true);
12970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _start();
12980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
12990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _start() throws IllegalStateException;
13010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int getAudioStreamType() {
13040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
13050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mStreamType = _getAudioStreamType();
13060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mStreamType;
13080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native int _getAudioStreamType() throws IllegalStateException;
13110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Stops playback after playback has been started or paused.
13140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
13170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #hide
13180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void stop() {
13210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
13220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _stop();
13230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _stop() throws IllegalStateException;
13260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Pauses playback. Call play() to resume.
13290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
13300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
13310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
13320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void pause() {
13350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
13360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _pause();
13370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _pause() throws IllegalStateException;
13400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //--------------------------------------------------------------------------
13420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Explicit Routing
13430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //--------------------
13440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private AudioDeviceInfo mPreferredDevice = null;
13450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
13480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the output from this MediaPlayer2.
13490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
13500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  If deviceInfo is null, default routing is restored.
13510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
13520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * does not correspond to a valid audio device.
13530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
13560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (deviceInfo != null && !deviceInfo.isSink()) {
13570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return false;
13580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
13600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean status = native_setOutputDevice(preferredDeviceId);
13610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (status == true) {
13620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
13630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPreferredDevice = deviceInfo;
13640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
13650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return status;
13670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
13710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is not guaranteed to correspond to the actual device being used for playback.
13720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public AudioDeviceInfo getPreferredDevice() {
13750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (this) {
13760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mPreferredDevice;
13770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
13790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
13800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
13810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2
13820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note: The query is only valid if the MediaPlayer2 is currently playing.
13830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the player is not playing, the returned device can be null or correspond to previously
13840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * selected device when the player was last active.
13850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
13860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
13870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public AudioDeviceInfo getRoutedDevice() {
13880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int deviceId = native_getRoutedDeviceId();
13890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (deviceId == 0) {
13900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
13910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        AudioDeviceInfo[] devices =
13930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
13940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (int i = 0; i < devices.length; i++) {
13950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (devices[i].getId() == deviceId) {
13960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return devices[i];
13970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
13980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
13990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return null;
14000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
14010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
14030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
14040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
140557d03914a1d5680cfe0727c15a3a82e4dfeb0adeAndreas Gampe    @GuardedBy("mRoutingChangeListeners")
14060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void enableNativeRoutingCallbacksLocked(boolean enabled) {
14070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mRoutingChangeListeners.size() == 0) {
14080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            native_enableDeviceCallback(enabled);
14090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
14110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
14140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
14150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * by an app to receive (re)routing notifications.
14160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @GuardedBy("mRoutingChangeListeners")
14180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private ArrayMap<AudioRouting.OnRoutingChangedListener,
14190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
14200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
14230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * changes on this MediaPlayer2.
14240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
14250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notifications of rerouting events.
14260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
14270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the callback. If <code>null</code>, the handler on the main looper will be used.
14280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
14310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Handler handler) {
14320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mRoutingChangeListeners) {
14330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
14340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                enableNativeRoutingCallbacksLocked(true);
14350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRoutingChangeListeners.put(
14360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        listener, new NativeRoutingEventHandlerDelegate(this, listener,
14370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                handler != null ? handler : mEventHandler));
14380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
14390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
14410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
14440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to receive rerouting notifications.
14450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
14460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to remove.
14470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
14500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mRoutingChangeListeners) {
14510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mRoutingChangeListeners.containsKey(listener)) {
14520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRoutingChangeListeners.remove(listener);
14530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                enableNativeRoutingCallbacksLocked(false);
14540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
14550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
14570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final boolean native_setOutputDevice(int deviceId);
14590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_getRoutedDeviceId();
14600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_enableDeviceCallback(boolean enabled);
14610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
14630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set the low-level power management behavior for this MediaPlayer2.  This
14640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
14650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
14660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
14670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>This function has the MediaPlayer2 access the low-level power manager
14690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * service to control the device's power usage while playing is occurring.
14700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The parameter is a combination of {@link android.os.PowerManager} wake flags.
14710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
14720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * permission.
14730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * By default, no attempt is made to keep the device awake during playback.
14740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
14750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param context the Context to use
14760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode    the power/wake mode to set
14770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.os.PowerManager
14780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
14790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
14800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
14810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setWakeMode(Context context, int mode) {
14820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean washeld = false;
14830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* Disable persistant wakelocks in media player based on property */
14850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (SystemProperties.getBoolean("audio.offload.ignore_setawake", false) == true) {
14860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "IGNORING setWakeMode " + mode);
14870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
14880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mWakeLock != null) {
14910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mWakeLock.isHeld()) {
14920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                washeld = true;
14930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.release();
14940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
14950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mWakeLock = null;
14960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
14970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
14980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
14990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer2Impl.class.getName());
15000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mWakeLock.setReferenceCounted(false);
15010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (washeld) {
15020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mWakeLock.acquire();
15030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Control whether we should use the attached SurfaceHolder to keep the
15080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * screen on while video playback is occurring.  This is the preferred
15090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * method over {@link #setWakeMode} where possible, since it doesn't
15100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * require that the application have permission for low-level wake lock
15110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * access.
15120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param screenOn Supply true to keep the screen on, false to allow it
15140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to turn off.
15150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
15160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setScreenOnWhilePlaying(boolean screenOn) {
15190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mScreenOnWhilePlaying != screenOn) {
15200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (screenOn && mSurfaceHolder == null) {
15210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
15220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
15230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mScreenOnWhilePlaying = screenOn;
15240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            updateSurfaceScreenOn();
15250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void stayAwake(boolean awake) {
15290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mWakeLock != null) {
15300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (awake && !mWakeLock.isHeld()) {
15310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.acquire();
15320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else if (!awake && mWakeLock.isHeld()) {
15330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mWakeLock.release();
15340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
15350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mStayAwake = awake;
15370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
15380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void updateSurfaceScreenOn() {
15410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSurfaceHolder != null) {
15420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
15430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
15440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the width of the video.
15480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the width of the video, or 0 if there is no video,
15500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * no display surface was set, or the width has not been determined
15510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * yet. The {@code EventCallback} can be registered via
15520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #registerEventCallback(Executor, EventCallback)} to provide a
15530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notification {@code EventCallback.onVideoSizeChanged} when the width is available.
15540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getVideoWidth();
15570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the height of the video.
15600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the height of the video, or 0 if there is no video,
15620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * no display surface was set, or the height has not been determined
15630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * yet. The {@code EventCallback} can be registered via
15640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #registerEventCallback(Executor, EventCallback)} to provide a
15650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notification {@code EventCallback.onVideoSizeChanged} when the height is available.
15660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getVideoHeight();
15690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Return Metrics data about the current player.
15720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return a {@link PersistableBundle} containing the set of attributes and values
15740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * available for the media being handled by this instance of MediaPlayer2
15750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The attributes are descibed in {@link MetricsConstants}.
15760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  Additional vendor-specific fields may also be present in
15780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *  the return value.
15790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public PersistableBundle getMetrics() {
15820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PersistableBundle bundle = native_getMetrics();
15830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return bundle;
15840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
15850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native PersistableBundle native_getMetrics();
15870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Checks whether the MediaPlayer2 is playing.
15900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
15910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if currently playing, false otherwise
15920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
15930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
15940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
15950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
15960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native boolean isPlaying();
15970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
15980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
15990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the current buffering management params used by the source component.
16000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Calling it only after {@code setDataSource} has been called.
16010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Each type of data source might have different set of default params.
16020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the current buffering management params used by the source component.
16040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
16050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized, or {@code setDataSource} has not been called.
16060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
16070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
16100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native BufferingParams getBufferingParams();
16110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets buffering management params.
16140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The object sets its internal BufferingParams to the input, except that the input is
16150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * invalid or not supported.
16160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Call it only after {@code setDataSource} has been called.
16170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The input is a hint to MediaPlayer2.
16180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the buffering management params.
16200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
16220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released, or {@code setDataSource} has not been called.
16230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params is invalid or not supported.
16240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
16250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setBufferingParams(@NonNull BufferingParams params);
16280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets playback rate and audio mode.
16310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param rate the ratio between desired playback rate and normal one.
16330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param audioMode audio playback mode. Must be one of the supported
16340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * audio modes.
16350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
16370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
16380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if audioMode is not supported.
16390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
16410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
16440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public PlaybackParams easyPlaybackParams(float rate, @PlaybackRateAudioMode int audioMode) {
16450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        PlaybackParams params = new PlaybackParams();
16460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        params.allowDefaults();
16470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (audioMode) {
16480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_DEFAULT:
16490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(1.0f);
16500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
16510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_STRETCH:
16520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(1.0f)
16530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    .setAudioFallbackMode(params.AUDIO_FALLBACK_MODE_FAIL);
16540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
16550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE:
16560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            params.setSpeed(rate).setPitch(rate);
16570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
16580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        default:
16590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Audio playback mode " + audioMode + " is not supported";
16600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
16610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
16620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return params;
16630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
16640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets playback rate using {@link PlaybackParams}. The object sets its internal
16670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * PlaybackParams to the input, except that the object remembers previous speed
16680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when input speed is zero. This allows the object to resume at previous speed
16690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when play() is called. Calling it before the object is prepared does not change
16700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the object state. After the object is prepared, calling it with zero speed is
16710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * equivalent to calling pause(). After the object is prepared, calling it with
16720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * non-zero speed is equivalent to calling play().
16730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the playback params.
16750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
16770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized or has been released.
16780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params is not supported.
16790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setPlaybackParams(@NonNull PlaybackParams params);
16820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the playback params, containing the current playback rate.
16850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the playback params.
16870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
16880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
16890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
16900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
16910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
16920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native PlaybackParams getPlaybackParams();
16930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
16940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
16950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets A/V sync mode.
16960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param params the A/V sync params to apply
16980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
16990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
17000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
17010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if params are not supported.
17020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
17040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setSyncParams(@NonNull SyncParams params);
17050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the A/V sync mode.
17080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the A/V sync params
17100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
17120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized.
17130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
17150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
17160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native SyncParams getSyncParams();
17170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void _seekTo(long msec, int mode);
17190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Moves the media to specified time position by considering the given mode.
17220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
17230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When seekTo is finished, the user will be notified via OnSeekComplete supplied by the user.
17240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * There is at most one active seekTo processed at any time. If there is a to-be-completed
17250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * seekTo, new seekTo requests will be queued in such a way that only the last request
17260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is kept. When current seekTo is completed, the queued request will be processed if
17270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that request is different from just-finished seekTo operation, i.e., the requested
17280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * position or mode is different.
17290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param msec the offset in milliseconds from the start to seek to.
17310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When seeking to the given time position, there is no guarantee that the data source
17320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * has a frame located at the position. When this happens, a frame nearby will be rendered.
17330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If msec is negative, time position zero will be used.
17340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If msec is larger than duration, duration will be used.
17350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mode the mode indicating where exactly to seek to.
17360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame
17370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp earlier than or the same as msec. Use
17380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame
17390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp later than or the same as msec. Use
17400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame
17410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * that has a timestamp closest to or the same as msec. Use
17420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may
17430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * or may not be a sync frame but is closest to or the same as msec.
17440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #SEEK_CLOSEST} often has larger performance overhead compared
17450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to the other options if there is no sync frame located at msec.
17460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if the internal player engine has not been
17470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * initialized
17480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mode is invalid.
17490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
17510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void seekTo(long msec, @SeekMode int mode) {
17520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
17530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Illegal seek mode: " + mode;
17540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
17550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: pass long to native, instead of truncating here.
17570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (msec > Integer.MAX_VALUE) {
17580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "seekTo offset " + msec + " is too large, cap to " + Integer.MAX_VALUE);
17590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            msec = Integer.MAX_VALUE;
17600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else if (msec < Integer.MIN_VALUE) {
17610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "seekTo offset " + msec + " is too small, cap to " + Integer.MIN_VALUE);
17620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            msec = Integer.MIN_VALUE;
17630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _seekTo(msec, mode);
17650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
17660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
17670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
17680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Get current playback position as a {@link MediaTimestamp}.
17690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
17700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The MediaTimestamp represents how the media time correlates to the system time in
17710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a linear fashion using an anchor and a clock rate. During regular playback, the media
17720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * time moves fairly constantly (though the anchor frame may be rebased to a current
17730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * system time, the linear correlation stays steady). Therefore, this method does not
17740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * need to be called often.
17750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
17760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * To help users get current playback position, this method always anchors the timestamp
17770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to the current {@link System#nanoTime system time}, so
17780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
17790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
17810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *         is available, e.g. because the media player has not been initialized.
17820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
17830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see MediaTimestamp
17840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
17850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
17860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Nullable
17870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaTimestamp getTimestamp()
17880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
17890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
17900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // TODO: get the timestamp from native side
17910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new MediaTimestamp(
17920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    getCurrentPosition() * 1000L,
17930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    System.nanoTime(),
17940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    isPlaying() ? getPlaybackParams().getSpeed() : 0.f);
17950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (IllegalStateException e) {
17960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
17970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
17980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
17990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the current playback position.
18020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the current position in milliseconds
18040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
18060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getCurrentPosition();
18070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the duration of the file.
18100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the duration in milliseconds, if no duration is available
18120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *         (for example, if streaming live content), -1 is returned.
18130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
18150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getDuration();
18160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Gets the media metadata.
18190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param update_only controls whether the full set of available
18210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * metadata is returned or just the set that changed since the
18220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
18230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #METADATA_ALL}.
18240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param apply_filter if true only metadata that matches the
18260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
18270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * #BYPASS_METADATA_FILTER}.
18280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The metadata, possibly empty. null if an error occured.
18300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     // FIXME: unhide.
18310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
18320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
18340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public Metadata getMetadata(final boolean update_only,
18350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                final boolean apply_filter) {
18360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
18370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Metadata data = new Metadata();
18380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!native_getMetadata(update_only, apply_filter, reply)) {
18400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
18410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
18420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Metadata takes over the parcel, don't recycle it unless
18450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // there is an error.
18460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!data.parse(reply)) {
18470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
18480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
18490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return data;
18510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
18520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
18540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set a filter for the metadata update notification and update
18550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * retrieval. The caller provides 2 set of metadata keys, allowed
18560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and blocked. The blocked set always takes precedence over the
18570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * allowed one.
18580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
18590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * shorthands to allow/block all or no metadata.
18600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * By default, there is no filter set.
18620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param allow Is the set of metadata the client is interested
18640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *              in receiving new notifications for.
18650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param block Is the set of metadata the client is not interested
18660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *              in receiving new notifications for.
18670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The call status code.
18680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
18690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     // FIXME: unhide.
18700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
18710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
18720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
18730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
18740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Do our serialization manually instead of calling
18750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Parcel.writeArray since the sets are made of the same type
18760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // we avoid paying the price of calling writeValue (used by
18770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // writeArray) which burns an extra int per element to encode
18780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the type.
18790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request =  newRequest();
18800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // The parcel starts already with an interface token. There
18820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // are 2 filters. Each one starts with a 4bytes number to
18830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // store the len followed by a number of int (4 bytes as well)
18840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // representing the metadata type.
18850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
18860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (request.dataCapacity() < capacity) {
18880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.setDataCapacity(capacity);
18890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
18910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        request.writeInt(allow.size());
18920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for(Integer t: allow) {
18930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(t);
18940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        request.writeInt(block.size());
18960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for(Integer t: block) {
18970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(t);
18980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
18990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return native_setMetadataFilter(request);
19000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
19030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set the MediaPlayer2 to start when this MediaPlayer2 finishes playback
19040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * (i.e. reaches the end of the stream).
19050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The media framework will attempt to transition from this player to
19060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the next as seamlessly as possible. The next player can be set at
19070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * any time before completion, but shall be after setDataSource has been
19080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * called successfully. The next player must be prepared by the
19090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * app, and the application should not call play() on it.
19100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The next MediaPlayer2 must be different from 'this'. An exception
19110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * will be thrown if next == this.
19120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The application may call setNextMediaPlayer(null) to indicate no
19130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * next player should be started at the end of playback.
19140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the current player is looping, it will keep looping and the next
19150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * player will not be started.
19160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
19170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param next the player to start after this one completes playback.
19180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
19190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
19200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
19210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
19220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setNextMediaPlayer(MediaPlayer2 next);
19230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
19250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Resets the MediaPlayer2 to its uninitialized state. After calling
19260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method, you will have to initialize it again by setting the
19270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * data source and calling prepare().
19280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
19290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
19300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void reset() {
19310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSelectedSubtitleTrackIndex = -1;
19320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized(mOpenSubtitleSources) {
19330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (final InputStream is: mOpenSubtitleSources) {
19340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
19350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    is.close();
19360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (IOException e) {
19370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
19380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
19390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mOpenSubtitleSources.clear();
19400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null) {
19420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.reset();
19430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider != null) {
19450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider.close();
19460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = null;
19470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
194963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        synchronized (mEventCbLock) {
195063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.clear();
195163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        }
195263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        synchronized (mDrmEventCbLock) {
195363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.clear();
195463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        }
195563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
19560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
19570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _reset();
19580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // make sure none of the listeners get called anymore
19590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mEventHandler != null) {
19600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeCallbacksAndMessages(null);
19610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
19620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
19640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mIndexTrackPairs.clear();
19650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mInbandTrackIndices.clear();
19660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        };
19670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        resetDrmState();
19690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _reset();
19720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
19740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
19750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * notified when the presentation time reaches (becomes greater than or equal to)
19760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the value specified.
19770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
19780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mediaTimeUs presentation time to get timed event callback at
19790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
19800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
19810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
19820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void notifyAt(long mediaTimeUs) {
19830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _notifyAt(mediaTimeUs);
19840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
19850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _notifyAt(long mediaTimeUs);
19870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Keep KEY_PARAMETER_* in sync with include/media/mediaplayer2.h
19890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
19900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
19910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the parameter indicated by key.
19920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param key key indicates the parameter to be set.
19930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param value value of the parameter to be set.
19940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if the parameter is set successfully, false otherwise
19950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@hide}
19960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
19970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native boolean setParameter(int key, Parcel value);
19980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
19990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the audio attributes for this MediaPlayer2.
20010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * See {@link AudioAttributes} for how to build and configure an instance of this class.
20020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * You must call this method before {@link #prepare()} or {@link #prepareAsync()} in order
20030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * for the audio attributes to become effective thereafter.
20040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param attributes a non-null set of audio attributes
20050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the attributes are null or invalid.
20060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setAudioAttributes(AudioAttributes attributes) {
20090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (attributes == null) {
20100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Cannot set AudioAttributes to null";
20110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
20120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
20130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mUsage = attributes.getUsage();
20140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mBypassInterruptionPolicy = (attributes.getAllFlags()
20150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
20160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel pattributes = Parcel.obtain();
20170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
20180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
20190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        pattributes.recycle();
20200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
20210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the player to be looping or non-looping.
20240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
20250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param looping whether to loop or not
20260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
20270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setLooping(boolean looping);
20300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Checks whether the MediaPlayer2 is looping or non-looping.
20330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
20340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return true if the MediaPlayer2 is currently looping, false otherwise
20350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
20360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native boolean isLooping();
20390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the volume on this player.
20420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This API is recommended for balancing the output of audio streams
20430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * within an application. Unless you are writing an application to
20440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * control user settings, this API should be used in preference to
20450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link AudioManager#setStreamVolume(int, int, int)} which sets the volume of ALL streams of
20460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a particular type. Note that the passed volume values are raw scalars in range 0.0 to 1.0.
20470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * UI controls should be scaled logarithmically.
20480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
20490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param leftVolume left volume scalar
20500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param rightVolume right volume scalar
20510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
20530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * FIXME: Merge this into javadoc comment above when setVolume(float) is not @hide.
20540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The single parameter form below is preferred if the channel volumes don't need
20550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to be set independently.
20560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setVolume(float leftVolume, float rightVolume) {
20590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _setVolume(leftVolume, rightVolume);
20600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
20610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _setVolume(float leftVolume, float rightVolume);
20630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Similar, excepts sets volume of all channels to same value.
20660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
20670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setVolume(float volume) {
20700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setVolume(volume, volume);
20710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
20720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the audio session ID.
20750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
20760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param sessionId the audio session ID.
20770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The audio session ID is a system wide unique identifier for the audio stream played by
20780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this MediaPlayer2 instance.
20790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The primary use of the audio session ID  is to associate audio effects to a particular
20800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * instance of MediaPlayer2: if an audio session ID is provided when creating an audio effect,
20810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this effect will be applied only to the audio content of media players within the same
20820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * audio session and not to the output mix.
20830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When created, a MediaPlayer2 instance automatically generates its own audio session ID.
20840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * However, it is possible to force this player to be part of an already existing audio session
20850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * by calling this method.
20860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This method must be called before one of the overloaded <code> setDataSource </code> methods.
20870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state
20880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the sessionId is invalid.
20890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
20910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void setAudioSessionId(int sessionId);
20920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
20930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
20940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the audio session ID.
20950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
20960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return the audio session ID. {@see #setAudioSessionId(int)}
20970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was contructed.
20980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
20990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
21000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native int getAudioSessionId();
21010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
21030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Attaches an auxiliary effect to the player. A typical auxiliary effect is a reverberation
21040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * effect which can be applied on any sound source that directs a certain amount of its
21050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * energy to this effect. This amount is defined by setAuxEffectSendLevel().
21060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * See {@link #setAuxEffectSendLevel(float)}.
21070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>After creating an auxiliary effect (e.g.
21080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with
21090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling this method
21100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to attach the player to the effect.
21110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>To detach the effect from the player, call this method with a null effect id.
21120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>This method must be called after one of the overloaded <code> setDataSource </code>
21130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * methods.
21140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param effectId system wide unique id of the effect to attach
21150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
21170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public native void attachAuxEffect(int effectId);
21180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
21210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Sets the send level of the player to the attached auxiliary effect.
21220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
21230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>By default the send level is 0, so even if an effect is attached to the player
21240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method must be called for the effect to be applied.
21250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
21260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
21270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * so an appropriate conversion from linear UI input x to level is:
21280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * x == 0 -> level = 0
21290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
21300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param level send level scalar
21310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
21330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setAuxEffectSendLevel(float level) {
21340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _setAuxEffectSendLevel(level);
21350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
21360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _setAuxEffectSendLevel(float level);
21380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
21400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param request Parcel destinated to the media player.
21410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param reply[out] Parcel that will contain the reply.
21420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
21430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_invoke(Parcel request, Parcel reply);
21450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
21480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param update_only If true fetch only the set of metadata that have
21490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    changed since the last invocation of getMetadata.
21500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    The set is built using the unfiltered
21510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    notifications the native player sent to the
21520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    MediaPlayer2Manager during that period of
21530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                    time. If false, all the metadatas are considered.
21540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param apply_filter  If true, once the metadata set has been built based on
21550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                     the value update_only, the current filter is applied.
21560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param reply[out] On return contains the serialized
21570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                   metadata. Valid only if the call was successful.
21580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
21590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final boolean native_getMetadata(boolean update_only,
21610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                    boolean apply_filter,
21620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                    Parcel reply);
21630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
21650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param request Parcel with the 2 serialized lists of allowed
21660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                metadata types followed by the one to be
21670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                dropped. Each list starts with an integer
21680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                indicating the number of metadata type elements.
21690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return The status code.
21700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final int native_setMetadataFilter(Parcel request);
21720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static native final void native_init();
21740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_setup(Object mediaplayer2_this);
21750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native final void native_finalize();
21760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21778e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onTearDown(
21788e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long nativeCallbackPtr, long userDataPtr);
21798e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onStreamPresentationEnd(
21808e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long nativeCallbackPtr, long userDataPtr);
21818e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static native final void native_stream_event_onStreamDataRequest(
21828e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr);
21838e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
21840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
21850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Class for MediaPlayer2 to return each audio/video/subtitle track's metadata.
21860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
21870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
21880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
21890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class TrackInfoImpl extends TrackInfo {
21900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
21910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the track type.
21920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @return TrackType which indicates if the track is video, audio, timed text.
21930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
21940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
21950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public int getTrackType() {
21960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mTrackType;
21970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
21980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
21990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
22000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the language code of the track.
22010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @return a language code in either way of ISO-639-1 or ISO-639-2.
22020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * When the language is unknown or could not be determined,
22030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * ISO-639-2 language code, "und", is returned.
22040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
22050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
22060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public String getLanguage() {
22070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String language = mFormat.getString(MediaFormat.KEY_LANGUAGE);
22080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return language == null ? "und" : language;
22090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
22120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Gets the {@link MediaFormat} of the track.  If the format is
22130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * unknown or could not be determined, null is returned.
22140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
22150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
22160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public MediaFormat getFormat() {
22170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
22180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
22190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return mFormat;
22200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return null;
22220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final int mTrackType;
22250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat mFormat;
22260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl(Parcel in) {
22280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTrackType = in.readInt();
22290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat
22300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // even for audio/video tracks, meaning we only set the mime and language.
22310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String mime = in.readString();
22320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String language = in.readString();
22330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mFormat = MediaFormat.createSubtitleFormat(mime, language);
22340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
22360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
22370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
22380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
22390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
22430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl(int type, MediaFormat format) {
22440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTrackType = type;
22450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mFormat = format;
22460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
22490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Flatten this object in to a Parcel.
22500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         *
22510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @param dest The Parcel in which the object should be written.
22520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * @param flags Additional flags about how the object should be written.
22530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * May be 0 or {@link android.os.Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
22540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
22550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* package private */ void writeToParcel(Parcel dest, int flags) {
22560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dest.writeInt(mTrackType);
22570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dest.writeString(getLanguage());
22580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
22600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
22610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
22620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
22630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
22640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
22680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public String toString() {
22690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            StringBuilder out = new StringBuilder(128);
22700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append(getClass().getName());
22710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append('{');
22720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            switch (mTrackType) {
22730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_VIDEO:
22740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("VIDEO");
22750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
22760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_AUDIO:
22770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("AUDIO");
22780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
22790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_TIMEDTEXT:
22800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("TIMEDTEXT");
22810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
22820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TRACK_TYPE_SUBTITLE:
22830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("SUBTITLE");
22840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
22850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
22860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out.append("UNKNOWN");
22870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
22880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
22890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append(", " + mFormat.toString());
22900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            out.append("}");
22910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return out.toString();
22920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
22930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
22940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
22950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Used to read a TrackInfoImpl from a Parcel.
22960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
22970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /* package private */ static final Parcelable.Creator<TrackInfoImpl> CREATOR
22980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                = new Parcelable.Creator<TrackInfoImpl>() {
22990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
23000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public TrackInfoImpl createFromParcel(Parcel in) {
23010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return new TrackInfoImpl(in);
23020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
23030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
23050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public TrackInfoImpl[] newArray(int size) {
23060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return new TrackInfoImpl[size];
23070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
23080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                };
23090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };
23110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // We would like domain specific classes with more informative names than the `first` and `second`
23130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
23140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // we document the meanings of `first` and `second` here:
23150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //
23160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Pair.first - inband track index; non-null iff representing an inband track.
23170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
23180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    //               an inband subtitle track or any out-of-band track (subtitle or timedtext).
23190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
23200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private BitSet mInbandTrackIndices = new BitSet();
23210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
23230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns a List of track information.
23240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
23250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return List of track info. The total number of tracks is the array length.
23260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Must be called again if an external timed text source has been added after
23270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * addTimedTextSource method is called.
23280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if it is called in an invalid state.
23290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
23310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public List<TrackInfo> getTrackInfo() {
23320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl trackInfo[] = getInbandTrackInfoImpl();
23330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // add out-of-band tracks
23340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
23350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            TrackInfoImpl allTrackInfo[] = new TrackInfoImpl[mIndexTrackPairs.size()];
23360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < allTrackInfo.length; i++) {
23370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
23380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (p.first != null) {
23390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // inband track
23400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    allTrackInfo[i] = trackInfo[p.first];
23410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
23420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleTrack track = p.second;
23430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    allTrackInfo[i] = new TrackInfoImpl(track.getTrackType(), track.getFormat());
23440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
23450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
23460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return Arrays.asList(allTrackInfo);
23470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
23490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException {
23510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
23520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
23530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
23540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(INVOKE_ID_GET_TRACK_INFO);
23550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
23560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            TrackInfoImpl trackInfo[] = reply.createTypedArray(TrackInfoImpl.CREATOR);
23570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return trackInfo;
23580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
23590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
23600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
23610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
23630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
23650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A helper function to check if the mime type is supported by media framework.
23660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static boolean availableMimeTypeForExternalSource(String mimeType) {
23680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (MEDIA_MIMETYPE_TEXT_SUBRIP.equals(mimeType)) {
23690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return true;
23700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
23710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return false;
23720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
23730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private SubtitleController mSubtitleController;
23750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
23770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
23780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setSubtitleAnchor(
23790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleController controller,
23800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleController.Anchor anchor) {
23810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: create SubtitleController in MediaPlayer2
23820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController = controller;
23830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController.setAnchor(anchor);
23840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
23850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
23860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
23870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The private version of setSubtitleAnchor is used internally to set mSubtitleController if
23880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * necessary when clients don't provide their own SubtitleControllers using the public version
23890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #setSubtitleAnchor(SubtitleController, Anchor)} (e.g. {@link VideoView} provides one).
23900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
23910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private synchronized void setSubtitleAnchor() {
23920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
23930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
23940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            thread.start();
23950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Handler handler = new Handler(thread.getLooper());
23960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            handler.post(new Runnable() {
23970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                @Override
23980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                public void run() {
23990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Context context = ActivityThread.currentApplication();
24000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer2Impl.this);
24010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSubtitleController.setAnchor(new Anchor() {
24020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        @Override
24030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        public void setSubtitleWidget(RenderingWidget subtitleWidget) {
24040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
24050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        @Override
24070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        public Looper getSubtitleLooper() {
24080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            return Looper.getMainLooper();
24090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
24100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    });
24110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    thread.getLooper().quitSafely();
24120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
24130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            });
24140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
24150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.join();
24160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (InterruptedException e) {
24170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Thread.currentThread().interrupt();
24180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "failed to join SetSubtitleAnchorThread");
24190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
24220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int mSelectedSubtitleTrackIndex = -1;
24240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private Vector<InputStream> mOpenSubtitleSources;
24250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() {
24270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
24280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
24290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int index = data.getTrackIndex();
24300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
24310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
24320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p.first != null && p.first == index && p.second != null) {
24330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // inband subtitle track that owns data
24340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        SubtitleTrack track = p.second;
24350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        track.onData(data);
24360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
24370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
24380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };
24410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
24430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
24440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void onSubtitleTrackSelected(SubtitleTrack track) {
24450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSelectedSubtitleTrackIndex >= 0) {
24460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
24470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
24480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
24490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSelectedSubtitleTrackIndex = -1;
24510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setOnSubtitleDataListener(null);
24530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track == null) {
24540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
24550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
24580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
24590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (p.first != null && p.second == track) {
24600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // inband subtitle track that is selected
24610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSelectedSubtitleTrackIndex = p.first;
24620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
24630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
24640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSelectedSubtitleTrackIndex >= 0) {
24680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
24690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
24700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
24710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setOnSubtitleDataListener(mSubtitleDataListener);
24730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // no need to select out-of-band tracks
24750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
24760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
24780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
24790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addSubtitleSource(InputStream is, MediaFormat format)
24800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException
24810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
24820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final InputStream fIs = is;
24830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat fFormat = format;
24840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (is != null) {
24860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Ensure all input streams are closed.  It is also a handy
24870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // way to implement timeouts in the future.
24880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(mOpenSubtitleSources) {
24890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mOpenSubtitleSources.add(is);
24900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
24910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
24920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "addSubtitleSource called with null InputStream");
24930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
24940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        getMediaTimeProvider();
24960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
24970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // process each subtitle in its own thread
24980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final HandlerThread thread = new HandlerThread("SubtitleReadThread",
24990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia              Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
25000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        thread.start();
25010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Handler handler = new Handler(thread.getLooper());
25020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        handler.post(new Runnable() {
25030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            private int addTrack() {
25040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (fIs == null || mSubtitleController == null) {
25050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
25060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                SubtitleTrack track = mSubtitleController.addTrack(fFormat);
25090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (track == null) {
25100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
25110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // TODO: do the conversion in the subtitle track
25140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Scanner scanner = new Scanner(fIs, "UTF-8");
25150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                String contents = scanner.useDelimiter("\\A").next();
25160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized(mOpenSubtitleSources) {
25170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mOpenSubtitleSources.remove(fIs);
25180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scanner.close();
25200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mIndexTrackPairs) {
25210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
25220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Handler h = mTimeProvider.mEventHandler;
25240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int what = TimeProvider.NOTIFY;
25250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
25260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, contents.getBytes());
25270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Message m = h.obtainMessage(what, arg1, 0, trackData);
25280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                h.sendMessage(m);
25290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
25300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
25310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void run() {
25330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int res = addTrack();
25340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mEventHandler != null) {
25350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
25360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mEventHandler.sendMessage(m);
25370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.getLooper().quitSafely();
25390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
25400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        });
25410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void scanInternalSubtitleTracks() {
25440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        setSubtitleAnchor();
25450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        populateInbandTracks();
25470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null) {
25490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.selectDefaultTrack();
25500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void populateInbandTracks() {
25540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        TrackInfoImpl[] tracks = getInbandTrackInfoImpl();
25550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
25560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < tracks.length; i++) {
25570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mInbandTrackIndices.get(i)) {
25580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    continue;
25590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
25600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mInbandTrackIndices.set(i);
25610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // newly appeared inband track
25640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
25650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleTrack track = mSubtitleController.addTrack(
25660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            tracks[i].getFormat());
25670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.create(i, track));
25680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
25690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
25700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
25710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
25720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
25740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
25750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /* TODO: Limit the total number of external timed text source to a reasonable number.
25760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
25770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
25780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file.
25790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
25800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip with the file extension .srt, case insensitive.
25810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that a single external timed text source may contain multiple tracks in it.
25820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
25830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * additional tracks become available after this method call.
25840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
25850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param path The file path of external timed text source file.
25860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
25870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if the file cannot be accessed or is corrupted.
25880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
25890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
25900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
25910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
25920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
25930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(String path, String mimeType)
25940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
25950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!availableMimeTypeForExternalSource(mimeType)) {
25960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final String msg = "Illegal mimeType for timed text source: " + mimeType;
25970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException(msg);
25980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
25990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        File file = new File(path);
26010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (file.exists()) {
26020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileInputStream is = new FileInputStream(file);
26030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            FileDescriptor fd = is.getFD();
26040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(fd, mimeType);
26050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            is.close();
26060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
26070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // We do not support the case where the path is not a file.
26080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IOException(path);
26090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
26110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
26140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file (Uri).
26150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip with the file extension .srt, case insensitive.
26170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Note that a single external timed text source may contain multiple tracks in it.
26180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
26190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * additional tracks become available after this method call.
26200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param context the Context to use when resolving the Uri
26220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param uri the Content URI of the data you want to play
26230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
26240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IOException if the file cannot be accessed or is corrupted.
26250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
26260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
26270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
26280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
26290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
26300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(Context context, Uri uri, String mimeType)
26310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IOException {
26320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String scheme = uri.getScheme();
26330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if(scheme == null || scheme.equals("file")) {
26340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(uri.getPath(), mimeType);
26350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
26360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        AssetFileDescriptor fd = null;
26390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
26400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            ContentResolver resolver = context.getContentResolver();
26410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            fd = resolver.openAssetFileDescriptor(uri, "r");
26420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (fd == null) {
26430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
26440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
26450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            addTimedTextSource(fd.getFileDescriptor(), mimeType);
26460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
26470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (SecurityException ex) {
26480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (IOException ex) {
26490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
26500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (fd != null) {
26510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                fd.close();
26520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
26530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
26540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
26550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
26570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text source file (FileDescriptor).
26580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is the caller's responsibility to close the file descriptor.
26600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is safe to do so as soon as this call returns.
26610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip. Note that a single external timed text source may
26630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain multiple tracks in it. One can find the total number of available tracks
26640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * using {@link #getTrackInfo()} to see what additional tracks become available
26650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * after this method call.
26660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param fd the FileDescriptor for the file you want to play
26680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
26690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
26700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
26710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
26720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
26730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
26740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(FileDescriptor fd, String mimeType) {
26750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // intentionally less than LONG_MAX
26760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        addTimedTextSource(fd, 0, 0x7ffffffffffffffL, mimeType);
26770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
26780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
26790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
26800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Adds an external timed text file (FileDescriptor).
26810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is the caller's responsibility to close the file descriptor.
26830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is safe to do so as soon as this call returns.
26840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently supported format is SubRip. Note that a single external timed text source may
26860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain multiple tracks in it. One can find the total number of available tracks
26870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * using {@link #getTrackInfo()} to see what additional tracks become available
26880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * after this method call.
26890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
26900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param fd the FileDescriptor for the file you want to play
26910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param offset the offset into the file where the data to be played starts, in bytes
26920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param length the length in bytes of the data to be played
26930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mime The mime type of the file. Must be one of the mime types listed above.
26940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalArgumentException if the mimeType is not supported.
26950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
26960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
26970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
26980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
26990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime) {
27000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!availableMimeTypeForExternalSource(mime)) {
27010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mime);
27020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final FileDescriptor dupedFd;
27050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
27060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            dupedFd = Os.dup(fd);
27070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (ErrnoException ex) {
27080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, ex.getMessage(), ex);
27090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new RuntimeException(ex);
27100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaFormat fFormat = new MediaFormat();
27130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        fFormat.setString(MediaFormat.KEY_MIME, mime);
27140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        fFormat.setInteger(MediaFormat.KEY_IS_TIMED_TEXT, 1);
27150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // A MediaPlayer2 created by a VideoView should already have its mSubtitleController set.
27170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController == null) {
27180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            setSubtitleAnchor();
27190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!mSubtitleController.hasRendererFor(fFormat)) {
27220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // test and add not atomic
27230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Context context = ActivityThread.currentApplication();
27240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler));
27250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
27270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mIndexTrackPairs) {
27280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
27290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
27300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        getMediaTimeProvider();
27320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final long offset2 = offset;
27340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final long length2 = length;
27350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final HandlerThread thread = new HandlerThread(
27360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                "TimedTextReadThread",
27370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
27380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        thread.start();
27390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Handler handler = new Handler(thread.getLooper());
27400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        handler.post(new Runnable() {
27410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            private int addTrack() {
27420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final ByteArrayOutputStream bos = new ByteArrayOutputStream();
27430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
27440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
27450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    byte[] buffer = new byte[4096];
27460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (long total = 0; total < length2;) {
27470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        int bytesToRead = (int) Math.min(buffer.length, length2 - total);
27480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        int bytes = IoBridge.read(dupedFd, buffer, 0, bytesToRead);
27490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (bytes < 0) {
27500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            break;
27510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        } else {
27520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            bos.write(buffer, 0, bytes);
27530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            total += bytes;
27540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
27550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
27560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Handler h = mTimeProvider.mEventHandler;
27570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    int what = TimeProvider.NOTIFY;
27580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
27590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, bos.toByteArray());
27600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = h.obtainMessage(what, arg1, 0, trackData);
27610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    h.sendMessage(m);
27620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
27630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
27640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.e(TAG, e.getMessage(), e);
27650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return MEDIA_INFO_TIMED_TEXT_ERROR;
27660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } finally {
27670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    try {
27680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Os.close(dupedFd);
27690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    } catch (ErrnoException e) {
27700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, e.getMessage(), e);
27710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
27720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
27740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void run() {
27760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int res = addTrack();
27770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mEventHandler != null) {
27780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
27790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mEventHandler.sendMessage(m);
27800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
27810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                thread.getLooper().quitSafely();
27820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
27830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        });
27840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
27850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
27860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
27870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Returns the index of the audio, video, or subtitle track currently selected for playback,
27880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The return value is an index into the array returned by {@link #getTrackInfo()}, and can
27890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * be used in calls to {@link #selectTrack(int)} or {@link #deselectTrack(int)}.
27900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
27910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
27920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
27930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
27940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @return index of the audio, video, or subtitle track currently selected for playback;
27950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * a negative integer is returned when there is no selected track for {@code trackType} or
27960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * when {@code trackType} is not one of audio, video, or subtitle.
27970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called after {@link #close()}
27980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
27990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #getTrackInfo()
28000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #selectTrack(int)
28010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see #deselectTrack(int)
28020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
28030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
28040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public int getSelectedTrack(int trackType) {
28050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController != null
28060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
28070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
28080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
28090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (subtitleTrack != null) {
28100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mIndexTrackPairs) {
28110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (int i = 0; i < mIndexTrackPairs.size(); i++) {
28120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
28130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
28140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            return i;
28150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
28160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
28170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
28190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
28200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
28220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
28230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
28240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(INVOKE_ID_GET_SELECTED_TRACK);
28250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(trackType);
28260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
28270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int inbandTrackIndex = reply.readInt();
28280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
28290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (int i = 0; i < mIndexTrackPairs.size(); i++) {
28300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
28310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p.first != null && p.first == inbandTrackIndex) {
28320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return i;
28330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
28340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
28350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
28360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return -1;
28370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
28380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
28390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
28400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
28410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
28420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
28440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Selects a track.
28450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
28460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is in invalid state, it throws an IllegalStateException exception.
28470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is in <em>Started</em> state, the selected track is presented immediately.
28480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If a MediaPlayer2 is not in Started state, it just marks the track to be played.
28490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
28500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
28510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * In any valid state, if it is called multiple times on the same type of track (ie. Video,
28520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Audio, Timed Text), the most recent one will be chosen.
28530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
28540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
28550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The first audio and video tracks are selected by default if available, even though
28560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this method is not called. However, no timed text track will be selected until
28570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * this function is called.
28580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
28590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
28600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently, only timed text tracks or audio tracks can be selected via this method.
28610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * In addition, the support for selecting an audio track at runtime is pretty limited
28620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in that an audio track can only be selected in the <em>Prepared</em> state.
28630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
28640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of the track to be selected. The valid range of the index
28650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is 0..total number of track - 1. The total number of tracks as well as the type of
28660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * each individual track can be found by calling {@link #getTrackInfo()} method.
28670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
28680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
28690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
28700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
28710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
28720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void selectTrack(int index) {
28730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        selectOrDeselectTrack(index, true /* select */);
28740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
28750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
28770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Deselect a track.
28780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
28790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Currently, the track must be a timed text track and no audio or video tracks can be
28800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * deselected. If the timed text track identified by index has not been
28810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * selected before, it throws an exception.
28820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * </p>
28830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param index the index of the track to be deselected. The valid range of the index
28840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
28850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * each individual track can be found by calling {@link #getTrackInfo()} method.
28860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called in an invalid state.
28870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
28880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @see android.media.MediaPlayer2#getTrackInfo
28890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
28900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
28910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void deselectTrack(int index) {
28920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        selectOrDeselectTrack(index, false /* select */);
28930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
28940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
28950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void selectOrDeselectTrack(int index, boolean select)
28960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException {
28970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // handle subtitle track through subtitle controller
28980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        populateInbandTracks();
28990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Pair<Integer,SubtitleTrack> p = null;
29010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
29020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            p = mIndexTrackPairs.get(index);
29030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (ArrayIndexOutOfBoundsException e) {
29040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // ignore bad index
29050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
29060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        SubtitleTrack track = p.second;
29090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track == null) {
29100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // inband (de)select
29110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            selectOrDeselectInbandTrack(p.first, select);
29120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
29130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mSubtitleController == null) {
29160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
29170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (!select) {
29200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // out-of-band deselect
29210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSubtitleController.getSelectedTrack() == track) {
29220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSubtitleController.selectTrack(null);
29230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
29240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "trying to deselect track that was not selected");
29250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
29260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
29270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // out-of-band select
29300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
29310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
29320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mIndexTrackPairs) {
29330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
29340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
29350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (p2.first != null && p2.second == null) {
29360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // deselect inband counterpart
29370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        selectOrDeselectInbandTrack(p2.first, false);
29380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
29390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
29400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
29410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mSubtitleController.selectTrack(track);
29430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
29440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void selectOrDeselectInbandTrack(int index, boolean select)
29460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws IllegalStateException {
29470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel request = Parcel.obtain();
29480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Parcel reply = Parcel.obtain();
29490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
29500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK);
29510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.writeInt(index);
29520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            invoke(request, reply);
29530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } finally {
29540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            request.recycle();
29550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            reply.recycle();
29560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
29580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
29600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Releases the resources held by this {@code MediaPlayer2} object.
29610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
29620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * It is considered good practice to call this method when you're
29630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * done using the MediaPlayer2. In particular, whenever an Activity
29640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * of an application is paused (its onPause() method is called),
29650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * or stopped (its onStop() method is called), this method should be
29660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * invoked to release the MediaPlayer2 object, unless the application
29670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * has a special need to keep the object around. In addition to
29680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * unnecessary resources (such as memory and instances of codecs)
29690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * being held, failure to call this method immediately if a
29700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * MediaPlayer2 object is no longer needed may also lead to
29710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * continuous battery consumption for mobile devices, and playback
29720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * failure for other applications if no multiple instances of the
29730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * same codec are supported on a device. Even if multiple instances
29740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * of the same codec are supported, some performance degradation
29750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * may be expected when unnecessary multiple instances are used
29760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * at the same time.
29770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
29780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@code close()} may be safely called after a prior {@code close()}.
29790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This class implements the Java {@code AutoCloseable} interface and
29800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * may be used with try-with-resources.
29810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
29820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
29830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void close() {
29840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mGuard) {
29850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            release();
29860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
29880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Have to declare protected for finalize() since it is protected
29900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // in the base class Object.
29910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
29920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    protected void finalize() throws Throwable {
29930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mGuard != null) {
29940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mGuard.warnIfOpen();
29950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
29960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
29970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        close();
29980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        native_finalize();
29990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void release() {
30020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        stayAwake(false);
30030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        updateSurfaceScreenOn();
30040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
300563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.clear();
30060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider != null) {
30080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider.close();
30090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = null;
30100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnSubtitleDataListener = null;
30120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Modular DRM clean up
30140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnDrmConfigHelper = null;
30150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
301663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.clear();
30170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        resetDrmState();
30190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        _release();
30210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _release();
30240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /* Do not change these values without updating their counterparts
30260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in include/media/mediaplayer2.h!
30270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
30280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_NOP = 0; // interface test message
30290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PREPARED = 1;
30300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PLAYBACK_COMPLETE = 2;
30310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_BUFFERING_UPDATE = 3;
30320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SEEK_COMPLETE = 4;
30330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SET_VIDEO_SIZE = 5;
30340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_STARTED = 6;
30350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_PAUSED = 7;
30360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_STOPPED = 8;
30370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SKIPPED = 9;
30380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_NOTIFY_TIME = 98;
30390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_TIMED_TEXT = 99;
30400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_ERROR = 100;
30410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_INFO = 200;
30420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_SUBTITLE_DATA = 201;
30430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_META_DATA = 202;
30440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_DRM_INFO = 210;
30450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
30460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private TimeProvider mTimeProvider;
30480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
30500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
30510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaTimeProvider getMediaTimeProvider() {
30520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mTimeProvider == null) {
30530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimeProvider = new TimeProvider(this);
30540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return mTimeProvider;
30560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
30570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private class EventHandler extends Handler {
30590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mMediaPlayer;
30600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public EventHandler(MediaPlayer2Impl mp, Looper looper) {
30620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(looper);
30630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mMediaPlayer = mp;
30640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
30650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
30670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void handleMessage(Message msg) {
30680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mMediaPlayer.mNativeContext == 0) {
30690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "mediaplayer2 went away with unhandled events");
30700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
30710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
307263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            final int what = msg.arg1;
307363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            final int extra = msg.arg2;
30740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            switch(msg.what) {
30750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PREPARED:
30760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
30770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scanInternalSubtitleTracks();
30780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (RuntimeException e) {
30790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // send error message instead of crashing;
30800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // send error message instead of inlining a call to onError
30810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // to avoid code duplication.
30820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Message msg2 = obtainMessage(
30830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
30840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    sendMessage(msg2);
30850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
308763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
308863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
308963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
309063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, MEDIA_INFO_PREPARED, 0));
309163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
30920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
30930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
30940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
30950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_DRM_INFO:
30960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj == null) {
30970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
30980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (msg.obj instanceof Parcel) {
309963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    // The parcel was parsed already in postEventFromNative
310063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    final DrmInfoImpl drmInfo;
310163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
310263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    synchronized (mDrmLock) {
310363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (mDrmInfoImpl != null) {
310463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            drmInfo = mDrmInfoImpl.makeCopy();
310563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        } else {
310663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            drmInfo = null;
31070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
310863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
31090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
311063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    // notifying the client outside the lock
311163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    if (drmInfo != null) {
311263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        synchronized (mEventCbLock) {
311363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
311463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                cb.first.execute(() -> cb.second.onDrmInfo(
311563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                        mMediaPlayer, drmInfo));
311663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            }
31170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
31180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
31190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
31200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
31210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
31230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PLAYBACK_COMPLETE:
312563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
312663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
312763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
312863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
312963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
31300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                stayAwake(false);
31320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
31330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_STOPPED:
31350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                {
31360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
31370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
31380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onStopped();
31390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
31400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
31420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_STARTED:
31440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_PAUSED:
31450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                {
31460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
31470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
31480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onPaused(msg.what == MEDIA_PAUSED);
31490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
31500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
31520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_BUFFERING_UPDATE:
315463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int percent = msg.arg1;
315563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
315663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
315763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onBufferingUpdate(
315863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, percent));
315963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
31600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
31620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SEEK_COMPLETE:
316463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
316563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
316663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
316763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, MEDIA_INFO_COMPLETE_CALL_SEEK, 0));
316863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
31690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // fall through
31710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SKIPPED:
31730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                {
31740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
31750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
31760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onSeekComplete(mMediaPlayer);
31770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
31780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
31800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SET_VIDEO_SIZE:
318263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int width = msg.arg1;
318363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final int height = msg.arg2;
318463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
318563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
318663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onVideoSizeChanged(
318763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, width, height));
318863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
31890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
31900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
31910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
31920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_ERROR:
31930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
319463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
319563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
319663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onError(
319763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, what, extra));
319863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
319963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
320063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
32010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                stayAwake(false);
32030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
32040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_INFO:
32060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                switch (msg.arg1) {
320763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_VIDEO_TRACK_LAGGING:
320863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
320963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
321063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
321163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_METADATA_UPDATE:
321263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        try {
321363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            scanInternalSubtitleTracks();
321463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        } catch (RuntimeException e) {
321563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            Message msg2 = obtainMessage(
321663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED,
321763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                    null);
321863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            sendMessage(msg2);
321963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
322063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        // fall through
32210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
322263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
322363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
322463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        // update default track selection
322563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (mSubtitleController != null) {
322663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            mSubtitleController.selectDefaultTrack();
322763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
322863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
322963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
323063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_BUFFERING_START:
323163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    case MEDIA_INFO_BUFFERING_END:
323263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        TimeProvider timeProvider = mTimeProvider;
323363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        if (timeProvider != null) {
323463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            timeProvider.onBuffering(msg.arg1 == MEDIA_INFO_BUFFERING_START);
323563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        }
323663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        break;
32370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
323963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
324063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
324163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onInfo(
324263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, what, extra));
324363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
32440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // No real default action so far.
32460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
32470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_NOTIFY_TIME:
32490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    TimeProvider timeProvider = mTimeProvider;
32500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (timeProvider != null) {
32510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        timeProvider.onNotifyTime();
32520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
32530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
32540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_TIMED_TEXT:
325663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final TimedText text;
325763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                if (msg.obj instanceof Parcel) {
325863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    Parcel parcel = (Parcel)msg.obj;
325963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    text = new TimedText(parcel);
326063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    parcel.recycle();
32610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
326263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    text = null;
326363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
326463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
326563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
326663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
326763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, 0, text));
32680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
32690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
32710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_SUBTITLE_DATA:
32730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener;
32740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (onSubtitleDataListener == null) {
32750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return;
32760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj instanceof Parcel) {
32780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Parcel parcel = (Parcel) msg.obj;
32790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    SubtitleData data = new SubtitleData(parcel);
32800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    parcel.recycle();
32810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    onSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
32820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
32830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
32840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
32850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_META_DATA:
328663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                final TimedMetaData data;
32870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.obj instanceof Parcel) {
32880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Parcel parcel = (Parcel) msg.obj;
328963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
32900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    parcel.recycle();
329163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                } else {
329263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    data = null;
329363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
329463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia
329563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mEventCbLock) {
329663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
329763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
329863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                                mMediaPlayer, 0, data));
329963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
33000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
33010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
33020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_NOP: // interface test message - ignore
33040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                break;
33050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            case MEDIA_AUDIO_ROUTING_CHANGED:
33070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                AudioManager.resetAudioPortGeneration();
33080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mRoutingChangeListeners) {
33090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    for (NativeRoutingEventHandlerDelegate delegate
33100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            : mRoutingChangeListeners.values()) {
33110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        delegate.notifyClient();
33120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
33130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
33140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
33150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            default:
33170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "Unknown message type " + msg.what);
33180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
33190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
33210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
33220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
33240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Called from native code when an interesting event happens.  This method
33250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * just uses the EventHandler system to post the event back to the main app thread.
33260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * We use a weak reference to the original MediaPlayer2 object so that the native
33270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * code is safe from the object disappearing from underneath it.  (This is
33280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the cookie passed to native_setup().)
33290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
33300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static void postEventFromNative(Object mediaplayer2_ref,
33310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                            int what, int arg1, int arg2, Object obj)
33320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
33330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get();
33340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mp == null) {
33350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return;
33360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
33370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        switch (what) {
33390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_INFO:
33400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
33410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                new Thread(new Runnable() {
33420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    @Override
33430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    public void run() {
33440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // this acquires the wakelock if needed, and sets the client side state
33450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mp.play();
33460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
33470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }).start();
33480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Thread.yield();
33490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
33510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_DRM_INFO:
33530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // We need to derive mDrmInfoImpl before prepare() returns so processing it here
33540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // before the notification is sent to EventHandler below. EventHandler runs in the
33550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // notification looper so its handleMessage might process the event after prepare()
33560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // has returned.
33570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
33580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (obj instanceof Parcel) {
33590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Parcel parcel = (Parcel)obj;
33600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                DrmInfoImpl drmInfo = new DrmInfoImpl(parcel);
33610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (mp.mDrmLock) {
33620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mp.mDrmInfoImpl = drmInfo;
33630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
33640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
33650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + obj);
33660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
33680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        case MEDIA_PREPARED:
33700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // By this time, we've learned about DrmInfo's presence or absence. This is meant
33710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // mainly for prepareAsync() use case. For prepare(), this still can run to a race
33720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // condition b/c MediaPlayerNative releases the prepare() lock before calling notify
33730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // so we also set mDrmInfoResolved in prepare().
33740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mp.mDrmLock) {
33750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mp.mDrmInfoResolved = true;
33760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
33770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            break;
33780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
33800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mp.mEventHandler != null) {
33820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
33830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mp.mEventHandler.sendMessage(m);
33840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
33850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
33860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mEventCbLock = new Object();
338863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia    private ArrayList<Pair<Executor, EventCallback> > mEventCallbackRecords
338963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        = new ArrayList<Pair<Executor, EventCallback> >();
33900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
33910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
33920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when the media source is ready
33930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * for playback.
33940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
33950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param eventCallback the callback that will be run
33960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param executor the executor through which the callback should be invoked
33970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
33980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
33990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void registerEventCallback(@NonNull @CallbackExecutor Executor executor,
34000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @NonNull EventCallback eventCallback) {
34010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (eventCallback == null) {
34020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("Illegal null EventCallback");
34030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (executor == null) {
34050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("Illegal null Executor for the EventCallback");
34060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
340863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mEventCallbackRecords.add(new Pair(executor, eventCallback));
34090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Unregisters an {@link EventCallback}.
34140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param callback an {@link EventCallback} to unregister
34160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
34170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
34180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void unregisterEventCallback(EventCallback callback) {
34190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mEventCbLock) {
342063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
342163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                if (cb.second == callback) {
342263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    mEventCallbackRecords.remove(cb);
342363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
34240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
34250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when a track has data available.
34300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener the callback that will be run
34320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @hide
34340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
34350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
34360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setOnSubtitleDataListener(OnSubtitleDataListener listener) {
34370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mOnSubtitleDataListener = listener;
34380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnSubtitleDataListener mOnSubtitleDataListener;
34410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM begin
34440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked for configuration of the DRM object before
34470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the session is created.
34480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The callback will be invoked synchronously during the execution
34490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * of {@link #prepareDrm(UUID uuid)}.
34500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param listener the callback that will be run
34520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
34530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
34540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setOnDrmConfigHelper(OnDrmConfigHelper listener)
34550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
34560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
34570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mOnDrmConfigHelper = listener;
34580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } // synchronized
34590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private OnDrmConfigHelper mOnDrmConfigHelper;
34620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private final Object mDrmEventCbLock = new Object();
346463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia    private ArrayList<Pair<Executor, DrmEventCallback> > mDrmEventCallbackRecords
346563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        = new ArrayList<Pair<Executor, DrmEventCallback> >();
34660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Register a callback to be invoked when the media source is ready
34690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * for playback.
34700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param eventCallback the callback that will be run
34720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param executor the executor through which the callback should be invoked
34730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
34740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
34750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
34760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @NonNull DrmEventCallback eventCallback) {
34770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (eventCallback == null) {
34780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("Illegal null EventCallback");
34790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (executor == null) {
34810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw new IllegalArgumentException("Illegal null Executor for the EventCallback");
34820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
348463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
34850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
34860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
34870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
34880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
34890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Unregisters a {@link DrmEventCallback}.
34900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
34910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param callback a {@link DrmEventCallback} to unregister
34920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
34930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
34940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void unregisterDrmEventCallback(DrmEventCallback callback) {
34950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
349663f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
349763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                if (cb.second == callback) {
349863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    mDrmEventCallbackRecords.remove(cb);
349963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    break;
350063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
35010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
35030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
35040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
35070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Retrieves the DRM Info associated with the current source
35080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException if called before prepare()
35100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
35110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
35120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public DrmInfo getDrmInfo() {
35130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        DrmInfoImpl drmInfo = null;
35140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // there is not much point if the app calls getDrmInfo within an OnDrmInfoListenet;
35160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // regardless below returns drmInfo anyway instead of raising an exception
35170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
35180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mDrmInfoResolved && mDrmInfoImpl == null) {
35190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "The Player has not been prepared yet";
35200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, msg);
35210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
35220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmInfoImpl != null) {
35250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                drmInfo = mDrmInfoImpl.makeCopy();
35260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
35280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return drmInfo;
35300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
35310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
35340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Prepares the DRM for the current source
35350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmConfigHelper} is registered, it will be called during
35370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * preparation to allow configuration of the DRM properties before opening the
35380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * DRM session. Note that the callback is called synchronously in the thread that called
35390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString}
35400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and {@code setDrmPropertyString} calls and refrain from any lengthy operation.
35410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If the device has not been provisioned before, this call also provisions the device
35430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * which involves accessing the provisioning server and can take a variable time to
35440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * complete depending on the network connectivity.
35450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
35460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * mode by launching the provisioning in the background and returning. The listener
35470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * will be called when provisioning and preparation has finished. If a
35480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
35490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * and preparation has finished, i.e., runs in blocking mode.
35500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
35520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * session being ready. The application should not make any assumption about its call
35530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * sequence (e.g., before or after prepareDrm returns), or the thread context that will
35540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * execute the listener (unless the listener is registered with a handler thread).
35550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
35560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
35580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
35590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
35600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws IllegalStateException              if called before prepare(), or the DRM was
35610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            prepared already
35620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws UnsupportedSchemeException         if the crypto scheme is not supported
35630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ResourceBusyException              if required DRM resources are in use
35640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ProvisioningNetworkErrorException  if provisioning is required but failed due to a
35650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            network error
35660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws ProvisioningServerErrorException   if provisioning is required but failed due to
35670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *                                            the request denied by the provisioning server
35680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
35690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
35700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void prepareDrm(@NonNull UUID uuid)
35710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws UnsupportedSchemeException, ResourceBusyException,
35720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                   ProvisioningNetworkErrorException, ProvisioningServerErrorException
35730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
35740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + mOnDrmConfigHelper);
35750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean allDoneWithoutProvisioning = false;
35770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
35790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // only allowing if tied to a protected source; might relax for releasing offline keys
35810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmInfoImpl == null) {
35820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " +
35830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "DRM info be retrieved before this call.";
35840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
35850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
35860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mActiveDrmScheme) {
35890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: There is already " +
35900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "an active DRM scheme with " + mDrmUUID;
35910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
35920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
35930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
35940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
35950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mPrepareDrmInProgress) {
35960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: There is already " +
35970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "a pending prepareDrm call.";
35980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
35990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
36000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmProvisioningInProgress) {
36030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Unexpectd: Provisioning is already in progress.";
36040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
36050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
36060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // shouldn't need this; just for safeguard
36090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            cleanDrmObj();
36100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPrepareDrmInProgress = true;
36120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
36140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // only creating the DRM object to allow pre-openSession configuration
36150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                prepareDrm_createDrmStep(uuid);
36160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
36170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "prepareDrm(): Exception ", e);
36180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPrepareDrmInProgress = false;
36190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
36200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
36210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmConfigAllowed = true;
36230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
36240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // call the callback outside the lock
36270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mOnDrmConfigHelper != null)  {
36280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mOnDrmConfigHelper.onDrmConfig(this);
36290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
36300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
36320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmConfigAllowed = false;
36330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean earlyExit = false;
36340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
36360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                prepareDrm_openSessionStep(uuid);
36370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmUUID = uuid;
36390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mActiveDrmScheme = true;
36400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                allDoneWithoutProvisioning = true;
36420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
36430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final String msg = "prepareDrm(): Wrong usage: The player must be " +
36440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "in the prepared state to call prepareDrm().";
36450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, msg);
36460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                earlyExit = true;
36470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException(msg);
36480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
36490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "prepareDrm: NotProvisionedException");
36500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // handle provisioning internally; it'll reset mPrepareDrmInProgress
36520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int result = HandleProvisioninig(uuid);
36530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if blocking mode, we're already done;
36550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if non-blocking mode, we attempted to launch background provisioning
36560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (result != PREPARE_DRM_STATUS_SUCCESS) {
36570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    earlyExit = true;
36580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    String msg;
36590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    switch (result) {
36610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
36620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Provisioning was required but failed " +
36630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                "due to a network error.";
36640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
36650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new ProvisioningNetworkErrorExceptionImpl(msg);
36660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
36680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Provisioning was required but the request " +
36690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                "was denied by the server.";
36700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
36710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new ProvisioningServerErrorExceptionImpl(msg);
36720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case PREPARE_DRM_STATUS_PREPARATION_ERROR:
36740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    default: // default for safeguard
36750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        msg = "prepareDrm: Post-provisioning preparation failed.";
36760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        Log.e(TAG, msg);
36770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        throw new IllegalStateException(msg);
36780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
36790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
36800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // nothing else to do;
36810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup
36820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
36830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "prepareDrm: Exception " + e);
36840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                earlyExit = true;
36850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
36860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } finally {
36870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!mDrmProvisioningInProgress) {// if early exit other than provisioning exception
36880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPrepareDrmInProgress = false;
36890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
36900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (earlyExit) {    // cleaning up object if didn't succeed
36910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    cleanDrmObj();
36920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
36930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } // finally
36940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
36950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
36970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // if finished successfully without provisioning, call the callback outside the lock
36980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (allDoneWithoutProvisioning) {
36990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mDrmEventCbLock) {
370063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
370163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    cb.first.execute(() -> cb.second.onDrmPrepared(
370263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                            this, PREPARE_DRM_STATUS_SUCCESS));
370363f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
37040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
37050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
37060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _releaseDrm();
37110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Releases the DRM session
37140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
37150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * The player has to have an active DRM session and be in stopped, or prepared
37160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * state before this call is made.
37170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A {@code reset()} call will release the DRM session implicitly.
37180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session to release
37200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
37220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void releaseDrm()
37230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
37240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
37250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "releaseDrm:");
37260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
37280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
37290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "releaseDrm(): No active DRM scheme to release.");
37300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("releaseDrm: No active DRM scheme to release.");
37310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
37320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
37340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we don't have the player's state in this layer. The below call raises
37350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // exception if we're in a non-stopped/prepared state.
37360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // for cleaning native/mediaserver crypto object
37380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                _releaseDrm();
37390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // for cleaning client-side MediaDrm object; only called if above has succeeded
37410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                cleanDrmObj();
37420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mActiveDrmScheme = false;
37440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
37450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "releaseDrm: Exception ", e);
37460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException("releaseDrm: The player is not in a valid state.");
37470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
37480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "releaseDrm: Exception ", e);
37490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
37500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
37510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
37520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
37540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
37550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A key request/response exchange occurs between the app and a license server
37560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * to obtain or release keys used to decrypt encrypted content.
37570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
37580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * getKeyRequest() is used to obtain an opaque key request byte array that is
37590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * delivered to the license server.  The opaque key request byte array is returned
37600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * in KeyRequest.data.  The recommended URL to deliver the key request to is
37610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * returned in KeyRequest.defaultUrl.
37620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
37630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * After the app has received the key request response from the server,
37640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * it should deliver to the response to the DRM engine plugin using the method
37650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link #provideKeyResponse}.
37660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId is the key-set identifier of the offline keys being released when keyType is
37680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
37690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}.
37700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param initData is the container-specific initialization data when the keyType is
37720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is
37730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * interpreted based on the mime type provided in the mimeType parameter.  It could
37740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * contain, for example, the content ID, key ID or other data obtained from the content
37750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * metadata that is required in generating the key request.
37760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null.
37770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param mimeType identifies the mime type of the content
37790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keyType specifies the type of the request. The request may be to acquire
37810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content
37820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired
37830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId.
37840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param optionalParameters are included in the key request message to
37860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * allow a client application to provide additional message parameters to the server.
37870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * This may be {@code null} if no additional parameters are to be sent.
37880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
37890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session
37900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
37910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
37920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
37930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public MediaDrm.KeyRequest getKeyRequest(@Nullable byte[] keySetId, @Nullable byte[] initData,
37940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable String mimeType, @MediaDrm.KeyType int keyType,
37950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Nullable Map<String, String> optionalParameters)
37960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
37970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
37980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "getKeyRequest: " +
37990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
38000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " keyType: " + keyType + " optionalParameters: " + optionalParameters);
38010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
38030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
38040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "getKeyRequest NoDrmSchemeException");
38050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("getKeyRequest: Has to set a DRM scheme first.");
38060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
38090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
38100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
38110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        keySetId;       // keySetId for KEY_TYPE_RELEASE
38120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                HashMap<String, String> hmapOptionalParameters =
38140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                (optionalParameters != null) ?
38150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                new HashMap<String, String>(optionalParameters) :
38160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                null;
38170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scope, initData, mimeType,
38190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                                              keyType, hmapOptionalParameters);
38200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, "getKeyRequest:   --> request: " + request);
38210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return request;
38230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
38250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getKeyRequest NotProvisionedException: " +
38260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected. Shouldn't have reached here.");
38270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException("getKeyRequest: Unexpected provisioning error.");
38280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
38290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getKeyRequest Exception " + e);
38300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
38310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
38340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
38350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
38380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * A key response is received from the license server by the app, then it is
38390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * provided to the DRM engine plugin using provideKeyResponse. When the
38400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * response is for an offline key request, a key-set identifier is returned that
38410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * can be used to later restore the keys to a new session with the method
38420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@ link # restoreKeys}.
38430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * When the response is for a streaming or release request, null is returned.
38440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
38450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId When the response is for a release request, keySetId identifies
38460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * the saved key associated with the release request (i.e., the same keySetId
38470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * passed to the earlier {@ link # getKeyRequest} call. It MUST be null when the
38480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * response is for either streaming or offline key requests.
38490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
38500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param response the byte array response from the server
38510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
38520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws NoDrmSchemeException if there is no active DRM session
38530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @throws DeniedByServerException if the response indicates that the
38540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * server rejected the request
38550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
38560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
38570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public byte[] provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
38580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException, DeniedByServerException
38590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
38600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response);
38610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
38630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
38650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.e(TAG, "getKeyRequest NoDrmSchemeException");
38660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("getKeyRequest: Has to set a DRM scheme first.");
38670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
38700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] scope = (keySetId == null) ?
38710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mDrmSessionId :     // sessionId for KEY_TYPE_STREAMING/OFFLINE
38720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                keySetId;           // keySetId for KEY_TYPE_RELEASE
38730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
38750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response +
38770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        " --> " + keySetResult);
38780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return keySetResult;
38810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (NotProvisionedException e) {
38830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "provideKeyResponse NotProvisionedException: " +
38840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected. Shouldn't have reached here.");
38850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new IllegalStateException("provideKeyResponse: " +
38860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        "Unexpected provisioning error.");
38870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
38880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "provideKeyResponse Exception " + e);
38890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
38900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
38910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
38920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
38930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
38950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
38960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Restore persisted offline keys into a new session.  keySetId identifies the
38970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
38980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
38990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param keySetId identifies the saved key set to restore
39000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
39010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
39020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void restoreKeys(@NonNull byte[] keySetId)
39030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
39040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
39050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "restoreKeys: keySetId: " + keySetId);
39060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
39080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme) {
39100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "restoreKeys NoDrmSchemeException");
39110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("restoreKeys: Has to set a DRM scheme first.");
39120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
39150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmObj.restoreKeys(mDrmSessionId, keySetId);
39160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
39170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "restoreKeys Exception " + e);
39180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
39190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
39220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
39230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
39260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Read a DRM engine plugin String property value, given the property name string.
39270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
39280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param propertyName the property name
39290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
39300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Standard fields names are:
39310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
39320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
39330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
39340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
39350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @NonNull
39360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName)
39370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
39380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
39390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName);
39400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        String value;
39420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
39430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (!mActiveDrmScheme && !mDrmConfigAllowed) {
39450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getDrmPropertyString NoDrmSchemeException");
39460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("getDrmPropertyString: Has to prepareDrm() first.");
39470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
39500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                value = mDrmObj.getPropertyString(propertyName);
39510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
39520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "getDrmPropertyString Exception " + e);
39530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
39540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
39560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName + " --> value: " + value);
39580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return value;
39600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
39610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
39640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Set a DRM engine plugin String property value.
39650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * <p>
39660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param propertyName the property name
39670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * @param value the property value
39680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     *
39690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Standard fields names are:
39700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
39710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
39720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
39730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    @Override
39740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public void setDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName,
39750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                     @NonNull String value)
39760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NoDrmSchemeException
39770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    {
39780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "setDrmPropertyString: propertyName: " + propertyName + " value: " + value);
39790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
39810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if ( !mActiveDrmScheme && !mDrmConfigAllowed ) {
39830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setDrmPropertyString NoDrmSchemeException");
39840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw new NoDrmSchemeExceptionImpl("setDrmPropertyString: Has to prepareDrm() first.");
39850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
39880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmObj.setPropertyString(propertyName, value);
39890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch ( Exception e ) {
39900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "setDrmPropertyString Exception " + e);
39910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throw e;
39920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
39930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
39940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
39950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
39960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
39970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Encapsulates the DRM properties of the source.
39980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
39990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class DrmInfoImpl extends DrmInfo {
40000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Map<UUID, byte[]> mapPssh;
40010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID[] supportedSchemes;
40020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
40040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Returns the PSSH info of the data source for each supported DRM scheme.
40050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
40060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
40070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public Map<UUID, byte[]> getPssh() {
40080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return mapPssh;
40090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /**
40120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * Returns the intersection of the data source and the device DRM schemes.
40130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * It effectively identifies the subset of the source's DRM schemes which
40140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         * are supported by the device too.
40150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia         */
40160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        @Override
40170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public List<UUID> getSupportedSchemes() {
40180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return Arrays.asList(supportedSchemes);
40190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl(Map<UUID, byte[]> Pssh, UUID[] SupportedSchemes) {
40220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mapPssh = Pssh;
40230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            supportedSchemes = SupportedSchemes;
40240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl(Parcel parcel) {
40270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl(" + parcel + ") size " + parcel.dataSize());
40280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int psshsize = parcel.readInt();
40300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] pssh = new byte[psshsize];
40310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            parcel.readByteArray(pssh);
40320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() PSSH: " + arrToHex(pssh));
40340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mapPssh = parsePSSH(pssh, psshsize);
40350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() PSSH: " + mapPssh);
40360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int supportedDRMsCount = parcel.readInt();
40380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            supportedSchemes = new UUID[supportedDRMsCount];
40390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < supportedDRMsCount; i++) {
40400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] uuid = new byte[16];
40410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                parcel.readByteArray(uuid);
40420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                supportedSchemes[i] = bytesToUUID(uuid);
40440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, "DrmInfoImpl() supportedScheme[" + i + "]: " +
40460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                      supportedSchemes[i]);
40470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
40480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + psshsize +
40500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                  " supportedDRMsCount: " + supportedDRMsCount);
40510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private DrmInfoImpl makeCopy() {
40540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new DrmInfoImpl(this.mapPssh, this.supportedSchemes);
40550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private String arrToHex(byte[] bytes) {
40580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            String out = "0x";
40590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < bytes.length; i++) {
40600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                out += String.format("%02x", bytes[i]);
40610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
40620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return out;
40640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID bytesToUUID(byte[] uuid) {
40670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long msb = 0, lsb = 0;
40680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int i = 0; i < 8; i++) {
40690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                msb |= ( ((long)uuid[i]   & 0xff) << (8 * (7 - i)) );
40700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                lsb |= ( ((long)uuid[i+8] & 0xff) << (8 * (7 - i)) );
40710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
40720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return new UUID(msb, lsb);
40740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
40750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
40770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Map<UUID, byte[]> result = new HashMap<UUID, byte[]>();
40780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int UUID_SIZE = 16;
40800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            final int DATALEN_SIZE = 4;
40810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int len = psshsize;
40830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int numentries = 0;
40840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
40850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            while (len > 0) {
40870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < UUID_SIZE) {
40880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
40890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "UUID: (%d < 16) pssh: %d", len, psshsize));
40900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
40910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
40920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] subset = Arrays.copyOfRange(pssh, i, i + UUID_SIZE);
40940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                UUID uuid = bytesToUUID(subset);
40950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += UUID_SIZE;
40960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= UUID_SIZE;
40970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
40980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // get data length
40990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < 4) {
41000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
41010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "datalen: (%d < 4) pssh: %d", len, psshsize));
41020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
41030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
41040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                subset = Arrays.copyOfRange(pssh, i, i+DATALEN_SIZE);
41060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) ?
41070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16) |
41080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[1] & 0xff) <<  8) |  (subset[0] & 0xff)          :
41090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16) |
41100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    ((subset[2] & 0xff) <<  8) |  (subset[3] & 0xff) ;
41110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += DATALEN_SIZE;
41120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= DATALEN_SIZE;
41130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (len < datalen) {
41150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, String.format("parsePSSH: len is too short to parse " +
41160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                             "data: (%d < %d) pssh: %d", len, datalen, psshsize));
41170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return null;
41180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
41190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                byte[] data = Arrays.copyOfRange(pssh, i, i+datalen);
41210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // skip the data
41230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                i += datalen;
41240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                len -= datalen;
41250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.v(TAG, String.format("parsePSSH[%d]: <%s, %s> pssh: %d",
41270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                         numentries, uuid, arrToHex(data), psshsize));
41280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                numentries++;
41290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                result.put(uuid, data);
41300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
41310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return result;
41330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    };  // DrmInfoImpl
41360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
41380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when a DRM method is called before preparing a DRM scheme through prepareDrm().
41390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
41400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
41410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class NoDrmSchemeExceptionImpl extends NoDrmSchemeException {
41420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public NoDrmSchemeExceptionImpl(String detailMessage) {
41430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
41440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
41460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
41480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when the device requires DRM provisioning but the provisioning attempt has
41490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * failed due to a network error (Internet reachability, timeout, etc.).
41500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
41510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
41520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class ProvisioningNetworkErrorExceptionImpl
41530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            extends ProvisioningNetworkErrorException {
41540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningNetworkErrorExceptionImpl(String detailMessage) {
41550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
41560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
41580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /**
41600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Thrown when the device requires DRM provisioning but the provisioning attempt has
41610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * failed due to the provisioning server denying the request.
41620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Extends MediaDrm.MediaDrmException
41630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
41640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    public static final class ProvisioningServerErrorExceptionImpl
41650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            extends ProvisioningServerErrorException {
41660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningServerErrorExceptionImpl(String detailMessage) {
41670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            super(detailMessage);
41680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
41700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private native void _prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId);
41730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // Modular DRM helpers
41750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void prepareDrm_createDrmStep(@NonNull UUID uuid)
41770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws UnsupportedSchemeException {
41780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid);
41790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
41810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj = new MediaDrm(uuid);
41820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj);
41830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) { // UnsupportedSchemeException
41840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e);
41850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw e;
41860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
41870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
41880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void prepareDrm_openSessionStep(@NonNull UUID uuid)
41900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throws NotProvisionedException, ResourceBusyException {
41910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "prepareDrm_openSessionStep: uuid: " + uuid);
41920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
41930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // TODO: don't need an open session for a future specialKeyReleaseDrm mode but we should do
41940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // it anyway so it raises provisioning error if needed. We'd rather handle provisioning
41950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // at prepareDrm/openSession rather than getKeyRequest/provideKeyResponse
41960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
41970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmSessionId = mDrmObj.openSession();
41980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId);
41990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // Sending it down to native/mediaserver to create the crypto object
42010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // This call could simply fail due to bad player state, e.g., after play().
42020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            _prepareDrm(getByteArrayFromUUID(uuid), mDrmSessionId);
42030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "prepareDrm_openSessionStep: _prepareDrm/Crypto succeeded");
42040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) { //ResourceBusyException, NotProvisionedException
42060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "prepareDrm_openSessionStep: open/crypto failed with " + e);
42070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            throw e;
42080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
42110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42128e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    // Called from the native side
42138e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    @SuppressWarnings("unused")
42148e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static boolean setAudioOutputDeviceById(AudioTrack track, int deviceId) {
42158e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        if (track == null) {
42168e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            return false;
42178e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
42188e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42198e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        if (deviceId == 0) {
42208e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            // Use default routing.
42218e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            track.setPreferredDevice(null);
42228e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            return true;
42238e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
42248e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42258e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        // TODO: Unhide AudioManager.getDevicesStatic.
42268e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        AudioDeviceInfo[] outputDevices =
42278e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
42288e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42298e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        boolean success = false;
42308e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        for (AudioDeviceInfo device : outputDevices) {
42318e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            if (device.getId() == deviceId) {
42328e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                track.setPreferredDevice(device);
42338e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                success = true;
42348e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                break;
42358e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            }
42368e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
42378e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        return success;
42388e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    }
42398e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42408e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    // Instantiated from the native side
42418e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    @SuppressWarnings("unused")
42428e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    private static class StreamEventCallback extends AudioTrack.StreamEventCallback {
42438e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mJAudioTrackPtr;
42448e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mNativeCallbackPtr;
42458e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public long mUserDataPtr;
42468e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42478e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public StreamEventCallback(long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr) {
42488e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            super();
42498e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mJAudioTrackPtr = jAudioTrackPtr;
42508e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mNativeCallbackPtr = nativeCallbackPtr;
42518e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            mUserDataPtr = userDataPtr;
42528e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
42538e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42548e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
42558e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onTearDown(AudioTrack track) {
42568e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onTearDown(mNativeCallbackPtr, mUserDataPtr);
42578e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
42588e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42598e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
42608e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onStreamPresentationEnd(AudioTrack track) {
42618e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onStreamPresentationEnd(mNativeCallbackPtr, mUserDataPtr);
42628e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
42638e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42648e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        @Override
42658e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        public void onStreamDataRequest(AudioTrack track) {
42668e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon            native_stream_event_onStreamDataRequest(
42678e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon                    mJAudioTrackPtr, mNativeCallbackPtr, mUserDataPtr);
42688e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon        }
42698e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon    }
42708e5ef909c789d4d8825cf775d90fa9aa251f10b4Hyundo Moon
42710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private class ProvisioningThread extends Thread {
42720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public static final int TIMEOUT_MS = 60000;
42730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private UUID uuid;
42750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private String urlStr;
42760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Object drmLock;
42770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mediaPlayer;
42780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private int status;
42790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean finished;
42800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public  int status() {
42810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return status;
42820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public ProvisioningThread initialize(MediaDrm.ProvisionRequest request,
42850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                          UUID uuid, MediaPlayer2Impl mediaPlayer) {
42860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // lock is held by the caller
42870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            drmLock = mediaPlayer.mDrmLock;
42880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            this.mediaPlayer = mediaPlayer;
42890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
42910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            this.uuid = uuid;
42920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
42940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "HandleProvisioninig: Thread is initialised url: " + urlStr);
42960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return this;
42970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
42980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
42990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void run() {
43000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] response = null;
43020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean provisioningSucceeded = false;
43030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
43040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                URL url = new URL(urlStr);
43050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
43060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
43070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setRequestMethod("POST");
43080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setDoOutput(false);
43090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setDoInput(true);
43100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setConnectTimeout(TIMEOUT_MS);
43110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.setReadTimeout(TIMEOUT_MS);
43120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.connect();
43140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    response = Streams.readFully(connection.getInputStream());
43150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.v(TAG, "HandleProvisioninig: Thread run: response " +
43170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            response.length + " " + response);
43180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
43190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
43200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url);
43210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } finally {
43220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    connection.disconnect();
43230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e)   {
43250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
43260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "HandleProvisioninig: Thread run: openConnection " + e);
43270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (response != null) {
43300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
43310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mDrmObj.provideProvisionResponse(response);
43320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.v(TAG, "HandleProvisioninig: Thread run: " +
43330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            "provideProvisionResponse SUCCEEDED!");
43340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    provisioningSucceeded = true;
43360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (Exception e) {
43370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR;
43380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "HandleProvisioninig: Thread run: " +
43390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            "provideProvisionResponse " + e);
43400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            boolean succeeded = false;
43440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
434563f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            boolean hasCallback = false;
43460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (mDrmEventCbLock) {
434763f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                hasCallback = !mDrmEventCallbackRecords.isEmpty();
43480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // non-blocking mode needs the lock
435063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            if (hasCallback) {
43510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized (drmLock) {
43530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // continuing with prepareDrm
43540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (provisioningSucceeded) {
43550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        succeeded = mediaPlayer.resumePrepareDrm(uuid);
43560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        status = (succeeded) ?
43570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                PREPARE_DRM_STATUS_SUCCESS :
43580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                PREPARE_DRM_STATUS_PREPARATION_ERROR;
43590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
43600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mediaPlayer.mDrmProvisioningInProgress = false;
43610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mediaPlayer.mPrepareDrmInProgress = false;
43620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (!succeeded) {
43630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        cleanDrmObj();  // cleaning up if it hasn't gone through while in the lock
43640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
43650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } // synchronized
43660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // calling the callback outside the lock
436863f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                synchronized (mDrmEventCbLock) {
436963f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
437063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                        cb.first.execute(() -> cb.second.onDrmPrepared(mediaPlayer, status));
437163f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                    }
437263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia                }
43730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {   // blocking mode already has the lock
43740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // continuing with prepareDrm
43760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (provisioningSucceeded) {
43770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    succeeded = mediaPlayer.resumePrepareDrm(uuid);
43780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    status = (succeeded) ?
43790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            PREPARE_DRM_STATUS_SUCCESS :
43800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            PREPARE_DRM_STATUS_PREPARATION_ERROR;
43810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mediaPlayer.mDrmProvisioningInProgress = false;
43830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mediaPlayer.mPrepareDrmInProgress = false;
43840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!succeeded) {
43850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    cleanDrmObj();  // cleaning up if it hasn't gone through
43860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
43870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
43880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            finished = true;
43900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // run()
43910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }   // ProvisioningThread
43930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private int HandleProvisioninig(UUID uuid) {
43950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the lock is already held by the caller
43960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
43970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmProvisioningInProgress) {
43980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress");
43990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
44000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
44030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (provReq == null) {
44040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null.");
44050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return PREPARE_DRM_STATUS_PREPARATION_ERROR;
44060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "HandleProvisioninig provReq " +
44090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
44100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // networking in a background thread
44120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningInProgress = true;
44130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningThread = new ProvisioningThread().initialize(provReq, uuid, this);
44150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mDrmProvisioningThread.start();
44160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        int result;
44180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // non-blocking: this is not the final result
442063f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        boolean hasCallback = false;
44210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmEventCbLock) {
442263f793f0f3e815c3a4895be7b02941d27d54159cWei Jia            hasCallback = !mDrmEventCallbackRecords.isEmpty();
44230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
442463f793f0f3e815c3a4895be7b02941d27d54159cWei Jia        if (hasCallback) {
44250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            result = PREPARE_DRM_STATUS_SUCCESS;
44260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
44270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // if blocking mode, wait till provisioning is done
44280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
44290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmProvisioningThread.join();
44300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (Exception e) {
44310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e);
44320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            result = mDrmProvisioningThread.status();
44340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // no longer need the thread
44350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmProvisioningThread = null;
44360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return result;
44390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
44400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean resumePrepareDrm(UUID uuid) {
44420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "resumePrepareDrm: uuid: " + uuid);
44430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // mDrmLock is guaranteed to be held
44450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        boolean success = false;
44460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        try {
44470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // resuming
44480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            prepareDrm_openSessionStep(uuid);
44490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmUUID = uuid;
44510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mActiveDrmScheme = true;
44520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            success = true;
44540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } catch (Exception e) {
44550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.w(TAG, "HandleProvisioninig: Thread run _prepareDrm resume failed with " + e);
44560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // mDrmObj clean up is done by the caller
44570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return success;
44600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
44610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void resetDrmState() {
44630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        synchronized (mDrmLock) {
44640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Log.v(TAG, "resetDrmState: " +
44650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mDrmInfoImpl=" + mDrmInfoImpl +
44660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mDrmProvisioningThread=" + mDrmProvisioningThread +
44670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mPrepareDrmInProgress=" + mPrepareDrmInProgress +
44680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    " mActiveDrmScheme=" + mActiveDrmScheme);
44690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmInfoResolved = false;
44710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmInfoImpl = null;
44720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mDrmProvisioningThread != null) {
44740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // timeout; relying on HttpUrlConnection
44750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
44760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mDrmProvisioningThread.join();
44770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                catch (InterruptedException e) {
44790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    Log.w(TAG, "resetDrmState: ProvThread.join Exception " + e);
44800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
44810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mDrmProvisioningThread = null;
44820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
44830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPrepareDrmInProgress = false;
44850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mActiveDrmScheme = false;
44860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            cleanDrmObj();
44880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }   // synchronized
44890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
44900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private void cleanDrmObj() {
44920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // the caller holds mDrmLock
44930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj + " mDrmSessionId=" + mDrmSessionId);
44940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
44950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmSessionId != null)    {
44960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj.closeSession(mDrmSessionId);
44970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmSessionId = null;
44980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
44990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (mDrmObj != null) {
45000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj.release();
45010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mDrmObj = null;
45020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
45040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
45060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long msb = uuid.getMostSignificantBits();
45070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        long lsb = uuid.getLeastSignificantBits();
45080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        byte[] uuidBytes = new byte[16];
45100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        for (int i = 0; i < 8; ++i) {
45110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
45120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
45130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return uuidBytes;
45160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
45170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // Modular DRM end
45190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /*
45210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     * Test whether a given video scaling mode is supported.
45220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia     */
45230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    private boolean isVideoScalingModeSupported(int mode) {
45240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return (mode == VIDEO_SCALING_MODE_SCALE_TO_FIT ||
45250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
45260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
45270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    /** @hide */
45290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    static class TimeProvider implements MediaTimeProvider {
45300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final String TAG = "MTP";
45310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long MAX_NS_WITHOUT_POSITION_CHECK = 5000000000L;
45320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long MAX_EARLY_CALLBACK_US = 1000;
45330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final long TIME_ADJUSTMENT_RATE = 2;  /* meaning 1/2 */
45340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mLastTimeUs = 0;
45350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaPlayer2Impl mPlayer;
45360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mPaused = true;
45370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mStopped = true;
45380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mBuffering;
45390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mLastReportedTime;
45400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // since we are expecting only a handful listeners per stream, there is
45410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // no need for log(N) search performance
45420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private MediaTimeProvider.OnMediaTimeListener mListeners[];
45430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private long mTimes[];
45440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private Handler mEventHandler;
45450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mRefresh = false;
45460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mPausing = false;
45470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private boolean mSeeking = false;
45480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY = 1;
45490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_TIME = 0;
45500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_STOP = 2;
45510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_SEEK = 3;
45520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private static final int NOTIFY_TRACK_DATA = 4;
45530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private HandlerThread mHandlerThread;
45540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
45560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public boolean DEBUG = false;
45570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public TimeProvider(MediaPlayer2Impl mp) {
45590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mPlayer = mp;
45600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
45610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                getCurrentTimeUs(true, false);
45620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
45630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we assume starting position
45640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRefresh = true;
45650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Looper looper;
45680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if ((looper = Looper.myLooper()) == null &&
45690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                (looper = Looper.getMainLooper()) == null) {
45700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // Create our own looper here in case MP was created without one
45710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread = new HandlerThread("MediaPlayer2MTPEventThread",
45720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                      Process.THREAD_PRIORITY_FOREGROUND);
45730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.start();
45740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                looper = mHandlerThread.getLooper();
45750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler = new EventHandler(looper);
45770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
45790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mTimes = new long[0];
45800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mLastTimeUs = 0;
45810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private void scheduleNotification(int type, long delayUs) {
45840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // ignore time notifications until seek is handled
45850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSeeking && type == NOTIFY_TIME) {
45860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
45870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
45880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (DEBUG) Log.v(TAG, "scheduleNotification " + type + " in " + delayUs);
45900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeMessages(NOTIFY);
45910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Message msg = mEventHandler.obtainMessage(NOTIFY, type, 0);
45920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.sendMessageDelayed(msg, (int) (delayUs / 1000));
45930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
45940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
45950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
45960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void close() {
45970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mEventHandler.removeMessages(NOTIFY);
45980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mHandlerThread != null) {
45990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.quitSafely();
46000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread = null;
46010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
46050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        protected void finalize() {
46060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mHandlerThread != null) {
46070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mHandlerThread.quitSafely();
46080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
46120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onNotifyTime() {
46130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
46140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onNotifyTime: ");
46150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
46160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
46200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onPaused(boolean paused) {
46210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
46220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onPaused: " + paused);
46230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mStopped) { // handle as seek if we were stopped
46240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mStopped = false;
46250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = true;
46260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
46270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
46280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPausing = paused;  // special handling if player disappeared
46290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = false;
46300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
46310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
46360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onBuffering(boolean buffering) {
46370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
46380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onBuffering: " + buffering);
46390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mBuffering = buffering;
46400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
46410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
46450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onStopped() {
46460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
46470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onStopped");
46480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPaused = true;
46490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mStopped = true;
46500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSeeking = false;
46510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mBuffering = false;
46520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_STOP, 0 /* delay */);
46530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
46570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onSeekComplete(MediaPlayer2Impl mp) {
46580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
46590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mStopped = false;
46600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mSeeking = true;
46610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
46620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        /** @hide */
46660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void onNewPlayer() {
46670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mRefresh) {
46680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                synchronized(this) {
46690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mStopped = false;
46700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mSeeking = true;
46710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mBuffering = false;
46720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
46730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifySeek() {
46780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mSeeking = false;
46790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
46800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long timeUs = getCurrentTimeUs(true, false);
46810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onSeekComplete at " + timeUs);
46820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
46840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (listener == null) {
46850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
46860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
46870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    listener.onSeek(timeUs);
46880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
46890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
46900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we should not be there, but at least signal pause
46910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "onSeekComplete but no player");
46920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPausing = true;  // special handling if player disappeared
46930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                notifyTimedEvent(false /* refreshTime */);
46940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
46950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
46960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
46970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyTrackData(Pair<SubtitleTrack, byte[]> trackData) {
46980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            SubtitleTrack track = trackData.first;
46990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            byte[] data = trackData.second;
47000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            track.onData(data, true /* eos */, ~0 /* runID: keep forever */);
47010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyStop() {
47040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
47050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (listener == null) {
47060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
47070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
47080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                listener.onStop();
47090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private int registerListener(MediaTimeProvider.OnMediaTimeListener listener) {
47130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            int i = 0;
47140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (; i < mListeners.length; i++) {
47150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mListeners[i] == listener || mListeners[i] == null) {
47160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
47170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
47180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // new listener
47210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (i >= mListeners.length) {
47220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaTimeProvider.OnMediaTimeListener[] newListeners =
47230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    new MediaTimeProvider.OnMediaTimeListener[i + 1];
47240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long[] newTimes = new long[i + 1];
47250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                System.arraycopy(mListeners, 0, newListeners, 0, mListeners.length);
47260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                System.arraycopy(mTimes, 0, newTimes, 0, mTimes.length);
47270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mListeners = newListeners;
47280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes = newTimes;
47290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mListeners[i] == null) {
47320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mListeners[i] = listener;
47330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes[i] = MediaTimeProvider.NO_TIME;
47340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return i;
47360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void notifyAt(
47390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                long timeUs, MediaTimeProvider.OnMediaTimeListener listener) {
47400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
47410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "notifyAt " + timeUs);
47420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mTimes[registerListener(listener)] = timeUs;
47430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
47440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void scheduleUpdate(MediaTimeProvider.OnMediaTimeListener listener) {
47480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
47490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "scheduleUpdate");
47500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int i = registerListener(listener);
47510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (!mStopped) {
47530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mTimes[i] = 0;
47540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
47550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
47560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public void cancelNotifications(
47600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                MediaTimeProvider.OnMediaTimeListener listener) {
47610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized(this) {
47620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                int i = 0;
47630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (; i < mListeners.length; i++) {
47640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mListeners[i] == listener) {
47650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        System.arraycopy(mListeners, i + 1,
47660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mListeners, i, mListeners.length - i - 1);
47670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        System.arraycopy(mTimes, i + 1,
47680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                                mTimes, i, mTimes.length - i - 1);
47690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mListeners[mListeners.length - 1] = null;
47700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mTimes[mTimes.length - 1] = NO_TIME;
47710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
47720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    } else if (mListeners[i] == null) {
47730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
47740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
47750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
47760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
47780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
47800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private synchronized void notifyTimedEvent(boolean refreshTime) {
47820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // figure out next callback
47830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long nowUs;
47840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            try {
47850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                nowUs = getCurrentTimeUs(refreshTime, true);
47860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } catch (IllegalStateException e) {
47870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // assume we paused until new player arrives
47880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mRefresh = true;
47890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPausing = true; // this ensures that call succeeds
47900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                nowUs = getCurrentTimeUs(refreshTime, true);
47910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            long nextTimeUs = nowUs;
47930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (mSeeking) {
47950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // skip timed-event notifications until seek is complete
47960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return;
47970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
47980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
47990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (DEBUG) {
48000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                StringBuilder sb = new StringBuilder();
48010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                sb.append("notifyTimedEvent(").append(mLastTimeUs).append(" -> ")
48020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        .append(nowUs).append(") from {");
48030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                boolean first = true;
48040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                for (long time: mTimes) {
48050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (time == NO_TIME) {
48060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        continue;
48070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
48080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (!first) sb.append(", ");
48090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    sb.append(time);
48100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    first = false;
48110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
48120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                sb.append("}");
48130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                Log.d(TAG, sb.toString());
48140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
48150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            Vector<MediaTimeProvider.OnMediaTimeListener> activatedListeners =
48170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                new Vector<MediaTimeProvider.OnMediaTimeListener>();
48180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (int ix = 0; ix < mTimes.length; ix++) {
48190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mListeners[ix] == null) {
48200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    break;
48210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
48220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mTimes[ix] <= NO_TIME) {
48230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // ignore, unless we were stopped
48240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (mTimes[ix] <= nowUs + MAX_EARLY_CALLBACK_US) {
48250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    activatedListeners.add(mListeners[ix]);
48260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (DEBUG) Log.d(TAG, "removed");
48270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mTimes[ix] = NO_TIME;
48280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else if (nextTimeUs == nowUs || mTimes[ix] < nextTimeUs) {
48290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    nextTimeUs = mTimes[ix];
48300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
48310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
48320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            if (nextTimeUs > nowUs && !mPaused) {
48340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // schedule callback at nextTimeUs
48350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (DEBUG) Log.d(TAG, "scheduling for " + nextTimeUs + " and " + nowUs);
48360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mPlayer.notifyAt(nextTimeUs);
48370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            } else {
48380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                mEventHandler.removeMessages(NOTIFY);
48390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // no more callbacks
48400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
48410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            for (MediaTimeProvider.OnMediaTimeListener listener: activatedListeners) {
48430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                listener.onTimedEvent(nowUs);
48440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
48450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
48460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        public long getCurrentTimeUs(boolean refreshTime, boolean monotonic)
48480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                throws IllegalStateException {
48490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            synchronized (this) {
48500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we always refresh the time when the paused-state changes, because
48510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                // we expect to have received the pause-change event delayed.
48520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (mPaused && !refreshTime) {
48530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    return mLastReportedTime;
48540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
48550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                try {
48570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mLastTimeUs = mPlayer.getCurrentPosition() * 1000L;
48580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mPaused = !mPlayer.isPlaying() || mBuffering;
48590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (DEBUG) Log.v(TAG, (mPaused ? "paused" : "playing") + " at " + mLastTimeUs);
48600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } catch (IllegalStateException e) {
48610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mPausing) {
48620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // if we were pausing, get last estimated timestamp
48630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mPausing = false;
48640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (!monotonic || mLastReportedTime < mLastTimeUs) {
48650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                            mLastReportedTime = mLastTimeUs;
48660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        }
48670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mPaused = true;
48680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        if (DEBUG) Log.d(TAG, "illegal state, but pausing: estimating at " + mLastReportedTime);
48690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        return mLastReportedTime;
48700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
48710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    // TODO get time when prepared
48720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    throw e;
48730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
48740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (monotonic && mLastTimeUs < mLastReportedTime) {
48750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    /* have to adjust time */
48760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    if (mLastReportedTime - mLastTimeUs > 1000000) {
48770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // schedule seeked event if time jumped significantly
48780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        // TODO: do this properly by introducing an exception
48790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mStopped = false;
48800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        mSeeking = true;
48810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
48820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
48830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                } else {
48840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    mLastReportedTime = mLastTimeUs;
48850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
48860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                return mLastReportedTime;
48880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
48890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
48900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        private class EventHandler extends Handler {
48920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public EventHandler(Looper looper) {
48930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                super(looper);
48940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
48950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
48960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            @Override
48970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            public void handleMessage(Message msg) {
48980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                if (msg.what == NOTIFY) {
48990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    switch (msg.arg1) {
49000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_TIME:
49010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyTimedEvent(true /* refreshTime */);
49020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
49030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_STOP:
49040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyStop();
49050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
49060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_SEEK:
49070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifySeek();
49080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
49090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    case NOTIFY_TRACK_DATA:
49100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        notifyTrackData((Pair<SubtitleTrack, byte[]>)msg.obj);
49110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                        break;
49120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                    }
49130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia                }
49140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            }
49150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
49160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
49170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
4918