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