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 <uses-permission>} 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