Merge pull request #9462 from google/dev-v2-r2.15.1

r2.15.1
This commit is contained in:
christosts 2021-09-22 17:58:21 +01:00 committed by GitHub
commit 2a88f0fb29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 2097 additions and 621 deletions

View File

@ -115,9 +115,8 @@ Next, add the following to your project's `settings.gradle` file, replacing
`path/to/exoplayer` with the path to your local copy:
```gradle
gradle.ext.exoplayerRoot = 'path/to/exoplayer'
gradle.ext.exoplayerModulePrefix = 'exoplayer-'
apply from: file("$gradle.ext.exoplayerRoot/core_settings.gradle")
apply from: file("path/to/exoplayer/core_settings.gradle")
```
You should now see the ExoPlayer modules appear as part of your project. You can

View File

@ -1,5 +1,72 @@
# Release notes
### 2.15.1 (2021-09-20)
* Core Library:
* Fix track selection in `StyledPlayerControlView` when using
`ForwardingPlayer`.
* Fix `FlagSet#equals` on API levels below 24.
* Fix `NullPointerException` being thrown from `CacheDataSource` when
reading a fully cached resource with `DataSpec.position` equal to the
resource length.
* Fix a bug when [depending on ExoPlayer locally](README.md#locally) with
a relative path
([#9403](https://github.com/google/ExoPlayer/issues/9403)).
* Better handle invalid seek requests. Seeks to positions that are before
the start or after the end of the media are now handled as seeks to the
start and end respectively
([8906](https://github.com/google/ExoPlayer/issues/8906)).
* Rename `MimeTypes.AUDIO_DTS_UHD` to `MimeTypes.AUDIO_DTS_X` and add
required profile to its value
([#9429](https://github.com/google/ExoPlayer/issues/9429)).
* Extractors:
* Support TS packets without PTS flag
([#9294](https://github.com/google/ExoPlayer/issues/9294)).
* Fix issue decoding ID3 tags containing UTF-16 encoded strings
([#9087](https://github.com/google/ExoPlayer/issues/9087)).
* Video:
* Request smaller decoder input buffers for Dolby Vision. This fixes an
issue that could cause UHD Dolby Vision playbacks to fail on some
devices, including Amazon Fire TV 4K.
* DRM:
* Fix `DefaultDrmSessionManager` to correctly eagerly release preacquired
DRM sessions when there's a shortage of DRM resources on the device.
* Downloads and caching:
* Workaround platform issue that can cause a `SecurityException` to be
thrown from `Requirements.isInternetConnectivityValidated` on devices
running Android 11
([#9002](https://github.com/google/ExoPlayer/issues/9002)).
* DASH:
* Use identical cache keys for downloading and playing DASH segments
([#9370](https://github.com/google/ExoPlayer/issues/9370)).
* Fix base URL selection and load error handling when base URLs are shared
across adaptation sets.
* HLS:
* Fix bug where the player would get stuck if all download attempts fail
and would not raise an error to the application
([#9390](https://github.com/google/ExoPlayer/issues/9390)).
* RTSP:
* Handle when additional spaces are in SDP's RTPMAP atrribute
([#9379](https://github.com/google/ExoPlayer/issues/9379)).
* Handle partial URIs in RTP-Info headers
([#9346](https://github.com/google/ExoPlayer/issues/9346)).
* Fix RTSP Session header handling
([#9416](https://github.com/google/ExoPlayer/issues/9416)).
* Fix RTSP WWW-Authenticate header parsing
([#9428](https://github.com/google/ExoPlayer/issues/9428)).
* UI:
* Use `defStyleAttr` when obtaining styled attributes in
`StyledPlayerView`, `PlayerView` and `PlayerControlView`
([#9024](https://github.com/google/ExoPlayer/issues/9024)).
* Fix accessibility focus in `PlayerControlView`
([#9111](https://github.com/google/ExoPlayer/issues/9111)).
* Fix issue that `StyledPlayerView` and `PlayerView` don't update UI when
available player commands change.
* Cast extension:
* Implement `CastPlayer.setPlaybackParameters(PlaybackParameters)` to
support setting the playback speed
([#6784](https://github.com/google/ExoPlayer/issues/6784)).
### 2.15.0 (2021-08-10)
* Core Library:

View File

@ -13,8 +13,8 @@
// limitations under the License.
project.ext {
// ExoPlayer version and version code.
releaseVersion = '2.15.0'
releaseVersionCode = 2015000
releaseVersion = '2.15.1'
releaseVersionCode = 2015001
minSdkVersion = 16
appTargetSdkVersion = 29
targetSdkVersion = 30

View File

@ -11,7 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
def rootDir = file(gradle.ext.exoplayerRoot)
def rootDir = file(".")
if (!gradle.ext.has('exoplayerSettingsDir')) {
gradle.ext.exoplayerSettingsDir = rootDir.getCanonicalPath()
}

View File

@ -212,6 +212,19 @@
}
]
},
{
"name": "DASH - Multiple base URLs",
"samples": [
{
"name": "DASH - Multiple base URLs",
"uri": "https://storage.googleapis.com/exoplayer-test-media-0/dash-multiple-base-urls/manifest.mpd"
},
{
"name": "DASH - Multiple base URLs (fail over)",
"uri": "https://storage.googleapis.com/exoplayer-test-media-0/dash-multiple-base-urls/manifest-failover.mpd"
}
]
},
{
"name": "HLS",
"samples": [

View File

@ -174,7 +174,7 @@ file at `https://yourdomain.com/samples.exolist.json`, you can open it in the
demo app using:
~~~
adb shell am start -a com.android.action.VIEW \
adb shell am start -a android.intent.action.VIEW \
-d https://yourdomain.com/samples.exolist.json
~~~
{: .language-shell}

View File

@ -879,7 +879,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<tr id="i126" class="altColor">
<td class="colFirst"><a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html" title="class in com.google.android.exoplayer2.source.dash">BaseUrlExclusionList</a></td>
<th class="colLast" scope="row">
<div class="block">Holds the state of <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#selectBaseUrl(java.util.List)"><code>to select</code></a> a base URL based on these exclusions.</div>
<div class="block">Holds the state of <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used to <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#selectBaseUrl(java.util.List)"><code>select</code></a> a base URL based on these exclusions.</div>
</th>
</tr>
<tr id="i127" class="rowColor">
@ -6270,7 +6270,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<tr id="i1011" class="rowColor">
<td class="colFirst"><a href="com/google/android/exoplayer2/offline/StreamKey.html" title="class in com.google.android.exoplayer2.offline">StreamKey</a></td>
<th class="colLast" scope="row">
<div class="block">A key for a subset of media which can be separately loaded (a "stream").</div>
<div class="block">A key for a subset of media that can be separately loaded (a "stream").</div>
</th>
</tr>
<tr id="i1012" class="altColor">

View File

@ -25,7 +25,7 @@
catch(err) {
}
//-->
var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":42,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":10,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":10,"i50":10,"i51":10,"i52":10,"i53":10,"i54":10,"i55":10,"i56":42,"i57":10,"i58":42,"i59":10,"i60":10,"i61":10,"i62":10,"i63":10,"i64":10,"i65":10,"i66":10,"i67":10,"i68":10,"i69":10,"i70":10,"i71":42,"i72":10,"i73":10,"i74":10,"i75":42,"i76":10,"i77":10,"i78":10,"i79":10,"i80":10,"i81":10,"i82":10,"i83":10,"i84":10,"i85":10,"i86":10,"i87":10,"i88":10,"i89":10,"i90":10,"i91":10,"i92":10,"i93":10,"i94":10,"i95":10,"i96":10,"i97":10,"i98":10,"i99":10,"i100":10,"i101":10,"i102":10,"i103":10,"i104":10,"i105":10,"i106":10,"i107":10,"i108":10,"i109":10,"i110":10,"i111":10};
var data = {"i0":42,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":10,"i22":10,"i23":10,"i24":10,"i25":10,"i26":10,"i27":10,"i28":10,"i29":42,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10,"i36":10,"i37":10,"i38":10,"i39":10,"i40":10,"i41":10,"i42":10,"i43":10,"i44":10,"i45":10,"i46":10,"i47":10,"i48":10,"i49":10,"i50":10,"i51":10,"i52":10,"i53":10,"i54":10,"i55":10,"i56":10,"i57":42,"i58":10,"i59":42,"i60":10,"i61":10,"i62":10,"i63":10,"i64":10,"i65":10,"i66":10,"i67":10,"i68":10,"i69":10,"i70":10,"i71":10,"i72":42,"i73":10,"i74":10,"i75":10,"i76":42,"i77":10,"i78":42,"i79":10,"i80":10,"i81":10,"i82":10,"i83":10,"i84":10,"i85":10,"i86":10,"i87":10,"i88":10,"i89":10,"i90":10,"i91":10,"i92":10,"i93":10,"i94":10,"i95":10,"i96":10,"i97":10,"i98":10,"i99":10,"i100":10,"i101":10,"i102":10,"i103":10,"i104":10,"i105":10,"i106":10,"i107":10,"i108":10,"i109":10,"i110":10,"i111":10,"i112":42};
var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]};
var altColor = "altColor";
var rowColor = "rowColor";
@ -219,7 +219,7 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#addListener(com.google.android.exoplayer2.Player.EventListener)">addListener</a></span>&#8203;(<a href="Player.EventListener.html" title="interface in com.google.android.exoplayer2">Player.EventListener</a>&nbsp;listener)</code></th>
<td class="colLast">
<div class="block">Registers a listener to receive events from the player.</div>
<div class="block"><span class="deprecatedLabel">Deprecated.</span></div>
</td>
</tr>
<tr id="i1" class="rowColor">
@ -628,13 +628,20 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
</td>
</tr>
<tr id="i56" class="altColor">
<td class="colFirst"><code><a href="Player.html" title="interface in com.google.android.exoplayer2">Player</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getWrappedPlayer()">getWrappedPlayer</a></span>()</code></th>
<td class="colLast">
<div class="block">Returns the <a href="Player.html" title="interface in com.google.android.exoplayer2"><code>Player</code></a> to which operations are forwarded.</div>
</td>
</tr>
<tr id="i57" class="rowColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#hasNext()">hasNext</a></span>()</code></th>
<td class="colLast">
<div class="block"><span class="deprecatedLabel">Deprecated.</span></div>
</td>
</tr>
<tr id="i57" class="rowColor">
<tr id="i58" class="altColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#hasNextWindow()">hasNextWindow</a></span>()</code></th>
<td class="colLast">
@ -642,14 +649,14 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
shuffle mode is enabled.</div>
</td>
</tr>
<tr id="i58" class="altColor">
<tr id="i59" class="rowColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#hasPrevious()">hasPrevious</a></span>()</code></th>
<td class="colLast">
<div class="block"><span class="deprecatedLabel">Deprecated.</span></div>
</td>
</tr>
<tr id="i59" class="rowColor">
<tr id="i60" class="altColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#hasPreviousWindow()">hasPreviousWindow</a></span>()</code></th>
<td class="colLast">
@ -657,21 +664,21 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
whether shuffle mode is enabled.</div>
</td>
</tr>
<tr id="i60" class="altColor">
<tr id="i61" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#increaseDeviceVolume()">increaseDeviceVolume</a></span>()</code></th>
<td class="colLast">
<div class="block">Increases the volume of the device.</div>
</td>
</tr>
<tr id="i61" class="rowColor">
<tr id="i62" class="altColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isCommandAvailable(int)">isCommandAvailable</a></span>&#8203;(int&nbsp;command)</code></th>
<td class="colLast">
<div class="block">Returns whether the provided <a href="Player.Command.html" title="annotation in com.google.android.exoplayer2"><code>Player.Command</code></a> is available.</div>
</td>
</tr>
<tr id="i62" class="altColor">
<tr id="i63" class="rowColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isCurrentWindowDynamic()">isCurrentWindowDynamic</a></span>()</code></th>
<td class="colLast">
@ -679,14 +686,14 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
empty.</div>
</td>
</tr>
<tr id="i63" class="rowColor">
<tr id="i64" class="altColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isCurrentWindowLive()">isCurrentWindowLive</a></span>()</code></th>
<td class="colLast">
<div class="block">Returns whether the current window is live, or <code>false</code> if the <a href="Timeline.html" title="class in com.google.android.exoplayer2"><code>Timeline</code></a> is empty.</div>
</td>
</tr>
<tr id="i64" class="altColor">
<tr id="i65" class="rowColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isCurrentWindowSeekable()">isCurrentWindowSeekable</a></span>()</code></th>
<td class="colLast">
@ -694,35 +701,35 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
empty.</div>
</td>
</tr>
<tr id="i65" class="rowColor">
<tr id="i66" class="altColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isDeviceMuted()">isDeviceMuted</a></span>()</code></th>
<td class="colLast">
<div class="block">Gets whether the device is muted or not.</div>
</td>
</tr>
<tr id="i66" class="altColor">
<tr id="i67" class="rowColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isLoading()">isLoading</a></span>()</code></th>
<td class="colLast">
<div class="block">Whether the player is currently loading the source.</div>
</td>
</tr>
<tr id="i67" class="rowColor">
<tr id="i68" class="altColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isPlaying()">isPlaying</a></span>()</code></th>
<td class="colLast">
<div class="block">Returns whether the player is playing, i.e.</div>
</td>
</tr>
<tr id="i68" class="altColor">
<tr id="i69" class="rowColor">
<td class="colFirst"><code>boolean</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isPlayingAd()">isPlayingAd</a></span>()</code></th>
<td class="colLast">
<div class="block">Returns whether the player is currently playing an ad.</div>
</td>
</tr>
<tr id="i69" class="rowColor">
<tr id="i70" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#moveMediaItem(int,int)">moveMediaItem</a></span>&#8203;(int&nbsp;currentIndex,
int&nbsp;newIndex)</code></th>
@ -730,7 +737,7 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Moves the media item at the current index to the new index.</div>
</td>
</tr>
<tr id="i70" class="altColor">
<tr id="i71" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#moveMediaItems(int,int,int)">moveMediaItems</a></span>&#8203;(int&nbsp;fromIndex,
int&nbsp;toIndex,
@ -739,70 +746,70 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Moves the media item range to the new index.</div>
</td>
</tr>
<tr id="i71" class="rowColor">
<tr id="i72" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#next()">next</a></span>()</code></th>
<td class="colLast">
<div class="block"><span class="deprecatedLabel">Deprecated.</span></div>
</td>
</tr>
<tr id="i72" class="altColor">
<tr id="i73" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#pause()">pause</a></span>()</code></th>
<td class="colLast">
<div class="block">Pauses playback.</div>
</td>
</tr>
<tr id="i73" class="rowColor">
<tr id="i74" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#play()">play</a></span>()</code></th>
<td class="colLast">
<div class="block">Resumes playback as soon as <a href="Player.html#getPlaybackState()"><code>Player.getPlaybackState()</code></a> == <a href="Player.html#STATE_READY"><code>Player.STATE_READY</code></a>.</div>
</td>
</tr>
<tr id="i74" class="altColor">
<tr id="i75" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#prepare()">prepare</a></span>()</code></th>
<td class="colLast">
<div class="block">Prepares the player.</div>
</td>
</tr>
<tr id="i75" class="rowColor">
<tr id="i76" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#previous()">previous</a></span>()</code></th>
<td class="colLast">
<div class="block"><span class="deprecatedLabel">Deprecated.</span></div>
</td>
</tr>
<tr id="i76" class="altColor">
<tr id="i77" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#release()">release</a></span>()</code></th>
<td class="colLast">
<div class="block">Releases the player.</div>
</td>
</tr>
<tr id="i77" class="rowColor">
<tr id="i78" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#removeListener(com.google.android.exoplayer2.Player.EventListener)">removeListener</a></span>&#8203;(<a href="Player.EventListener.html" title="interface in com.google.android.exoplayer2">Player.EventListener</a>&nbsp;listener)</code></th>
<td class="colLast">
<div class="block">Unregister a listener registered through <a href="Player.html#addListener(com.google.android.exoplayer2.Player.EventListener)"><code>Player.addListener(EventListener)</code></a>.</div>
<div class="block"><span class="deprecatedLabel">Deprecated.</span></div>
</td>
</tr>
<tr id="i78" class="altColor">
<tr id="i79" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#removeListener(com.google.android.exoplayer2.Player.Listener)">removeListener</a></span>&#8203;(<a href="Player.Listener.html" title="interface in com.google.android.exoplayer2">Player.Listener</a>&nbsp;listener)</code></th>
<td class="colLast">
<div class="block">Unregister a listener registered through <a href="Player.html#addListener(com.google.android.exoplayer2.Player.Listener)"><code>Player.addListener(Listener)</code></a>.</div>
</td>
</tr>
<tr id="i79" class="rowColor">
<tr id="i80" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#removeMediaItem(int)">removeMediaItem</a></span>&#8203;(int&nbsp;index)</code></th>
<td class="colLast">
<div class="block">Removes the media item at the given index of the playlist.</div>
</td>
</tr>
<tr id="i80" class="altColor">
<tr id="i81" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#removeMediaItems(int,int)">removeMediaItems</a></span>&#8203;(int&nbsp;fromIndex,
int&nbsp;toIndex)</code></th>
@ -810,21 +817,21 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Removes a range of media items from the playlist.</div>
</td>
</tr>
<tr id="i81" class="rowColor">
<tr id="i82" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekBack()">seekBack</a></span>()</code></th>
<td class="colLast">
<div class="block">Seeks back in the current window by <a href="Player.html#getSeekBackIncrement()"><code>Player.getSeekBackIncrement()</code></a> milliseconds.</div>
</td>
</tr>
<tr id="i82" class="altColor">
<tr id="i83" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekForward()">seekForward</a></span>()</code></th>
<td class="colLast">
<div class="block">Seeks forward in the current window by <a href="Player.html#getSeekForwardIncrement()"><code>Player.getSeekForwardIncrement()</code></a> milliseconds.</div>
</td>
</tr>
<tr id="i83" class="rowColor">
<tr id="i84" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekTo(int,long)">seekTo</a></span>&#8203;(int&nbsp;windowIndex,
long&nbsp;positionMs)</code></th>
@ -832,35 +839,35 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Seeks to a position specified in milliseconds in the specified window.</div>
</td>
</tr>
<tr id="i84" class="altColor">
<tr id="i85" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekTo(long)">seekTo</a></span>&#8203;(long&nbsp;positionMs)</code></th>
<td class="colLast">
<div class="block">Seeks to a position specified in milliseconds in the current window.</div>
</td>
</tr>
<tr id="i85" class="rowColor">
<tr id="i86" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekToDefaultPosition()">seekToDefaultPosition</a></span>()</code></th>
<td class="colLast">
<div class="block">Seeks to the default position associated with the current window.</div>
</td>
</tr>
<tr id="i86" class="altColor">
<tr id="i87" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekToDefaultPosition(int)">seekToDefaultPosition</a></span>&#8203;(int&nbsp;windowIndex)</code></th>
<td class="colLast">
<div class="block">Seeks to the default position associated with the specified window.</div>
</td>
</tr>
<tr id="i87" class="rowColor">
<tr id="i88" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekToNext()">seekToNext</a></span>()</code></th>
<td class="colLast">
<div class="block">Seeks to a later position in the current or next window (if available).</div>
</td>
</tr>
<tr id="i88" class="altColor">
<tr id="i89" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekToNextWindow()">seekToNextWindow</a></span>()</code></th>
<td class="colLast">
@ -868,14 +875,14 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
and whether shuffle mode is enabled.</div>
</td>
</tr>
<tr id="i89" class="rowColor">
<tr id="i90" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekToPrevious()">seekToPrevious</a></span>()</code></th>
<td class="colLast">
<div class="block">Seeks to an earlier position in the current or previous window (if available).</div>
</td>
</tr>
<tr id="i90" class="altColor">
<tr id="i91" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#seekToPreviousWindow()">seekToPreviousWindow</a></span>()</code></th>
<td class="colLast">
@ -883,21 +890,21 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
mode and whether shuffle mode is enabled.</div>
</td>
</tr>
<tr id="i91" class="rowColor">
<tr id="i92" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setDeviceMuted(boolean)">setDeviceMuted</a></span>&#8203;(boolean&nbsp;muted)</code></th>
<td class="colLast">
<div class="block">Sets the mute state of the device.</div>
</td>
</tr>
<tr id="i92" class="altColor">
<tr id="i93" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setDeviceVolume(int)">setDeviceVolume</a></span>&#8203;(int&nbsp;volume)</code></th>
<td class="colLast">
<div class="block">Sets the volume of the device.</div>
</td>
</tr>
<tr id="i93" class="rowColor">
<tr id="i94" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setMediaItem(com.google.android.exoplayer2.MediaItem)">setMediaItem</a></span>&#8203;(<a href="MediaItem.html" title="class in com.google.android.exoplayer2">MediaItem</a>&nbsp;mediaItem)</code></th>
<td class="colLast">
@ -905,7 +912,7 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
default position.</div>
</td>
</tr>
<tr id="i94" class="altColor">
<tr id="i95" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setMediaItem(com.google.android.exoplayer2.MediaItem,boolean)">setMediaItem</a></span>&#8203;(<a href="MediaItem.html" title="class in com.google.android.exoplayer2">MediaItem</a>&nbsp;mediaItem,
boolean&nbsp;resetPosition)</code></th>
@ -913,7 +920,7 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Clears the playlist and adds the specified <a href="MediaItem.html" title="class in com.google.android.exoplayer2"><code>MediaItem</code></a>.</div>
</td>
</tr>
<tr id="i95" class="rowColor">
<tr id="i96" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setMediaItem(com.google.android.exoplayer2.MediaItem,long)">setMediaItem</a></span>&#8203;(<a href="MediaItem.html" title="class in com.google.android.exoplayer2">MediaItem</a>&nbsp;mediaItem,
long&nbsp;startPositionMs)</code></th>
@ -921,7 +928,7 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Clears the playlist and adds the specified <a href="MediaItem.html" title="class in com.google.android.exoplayer2"><code>MediaItem</code></a>.</div>
</td>
</tr>
<tr id="i96" class="altColor">
<tr id="i97" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setMediaItems(java.util.List)">setMediaItems</a></span>&#8203;(<a href="https://developer.android.com/reference/java/util/List.html" title="class or interface in java.util" class="externalLink">List</a>&lt;<a href="MediaItem.html" title="class in com.google.android.exoplayer2" target="_top">MediaItem</a>&gt;&nbsp;mediaItems)</code></th>
<td class="colLast">
@ -929,7 +936,7 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
the default position.</div>
</td>
</tr>
<tr id="i97" class="rowColor">
<tr id="i98" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setMediaItems(java.util.List,boolean)">setMediaItems</a></span>&#8203;(<a href="https://developer.android.com/reference/java/util/List.html" title="class or interface in java.util" class="externalLink">List</a>&lt;<a href="MediaItem.html" title="class in com.google.android.exoplayer2" target="_top">MediaItem</a>&gt;&nbsp;mediaItems,
boolean&nbsp;resetPosition)</code></th>
@ -937,7 +944,7 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Clears the playlist and adds the specified <a href="MediaItem.html" title="class in com.google.android.exoplayer2"><code>MediaItems</code></a>.</div>
</td>
</tr>
<tr id="i98" class="altColor">
<tr id="i99" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setMediaItems(java.util.List,int,long)">setMediaItems</a></span>&#8203;(<a href="https://developer.android.com/reference/java/util/List.html" title="class or interface in java.util" class="externalLink">List</a>&lt;<a href="MediaItem.html" title="class in com.google.android.exoplayer2" target="_top">MediaItem</a>&gt;&nbsp;mediaItems,
int&nbsp;startWindowIndex,
@ -946,56 +953,56 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<div class="block">Clears the playlist and adds the specified <a href="MediaItem.html" title="class in com.google.android.exoplayer2"><code>MediaItems</code></a>.</div>
</td>
</tr>
<tr id="i99" class="rowColor">
<tr id="i100" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setPlaybackParameters(com.google.android.exoplayer2.PlaybackParameters)">setPlaybackParameters</a></span>&#8203;(<a href="PlaybackParameters.html" title="class in com.google.android.exoplayer2">PlaybackParameters</a>&nbsp;playbackParameters)</code></th>
<td class="colLast">
<div class="block">Attempts to set the playback parameters.</div>
</td>
</tr>
<tr id="i100" class="altColor">
<tr id="i101" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setPlaybackSpeed(float)">setPlaybackSpeed</a></span>&#8203;(float&nbsp;speed)</code></th>
<td class="colLast">
<div class="block">Changes the rate at which playback occurs.</div>
</td>
</tr>
<tr id="i101" class="rowColor">
<tr id="i102" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setPlaylistMetadata(com.google.android.exoplayer2.MediaMetadata)">setPlaylistMetadata</a></span>&#8203;(<a href="MediaMetadata.html" title="class in com.google.android.exoplayer2">MediaMetadata</a>&nbsp;mediaMetadata)</code></th>
<td class="colLast">
<div class="block">Sets the playlist <a href="MediaMetadata.html" title="class in com.google.android.exoplayer2"><code>MediaMetadata</code></a>.</div>
</td>
</tr>
<tr id="i102" class="altColor">
<tr id="i103" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setPlayWhenReady(boolean)">setPlayWhenReady</a></span>&#8203;(boolean&nbsp;playWhenReady)</code></th>
<td class="colLast">
<div class="block">Sets whether playback should proceed when <a href="Player.html#getPlaybackState()"><code>Player.getPlaybackState()</code></a> == <a href="Player.html#STATE_READY"><code>Player.STATE_READY</code></a>.</div>
</td>
</tr>
<tr id="i103" class="rowColor">
<tr id="i104" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setRepeatMode(int)">setRepeatMode</a></span>&#8203;(int&nbsp;repeatMode)</code></th>
<td class="colLast">
<div class="block">Sets the <a href="Player.RepeatMode.html" title="annotation in com.google.android.exoplayer2"><code>Player.RepeatMode</code></a> to be used for playback.</div>
</td>
</tr>
<tr id="i104" class="altColor">
<tr id="i105" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setShuffleModeEnabled(boolean)">setShuffleModeEnabled</a></span>&#8203;(boolean&nbsp;shuffleModeEnabled)</code></th>
<td class="colLast">
<div class="block">Sets whether shuffling of windows is enabled.</div>
</td>
</tr>
<tr id="i105" class="rowColor">
<tr id="i106" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setVideoSurface(android.view.Surface)">setVideoSurface</a></span>&#8203;(<a href="https://developer.android.com/reference/android/view/Surface.html" title="class or interface in android.view" class="externalLink" target="_top">Surface</a>&nbsp;surface)</code></th>
<td class="colLast">
<div class="block">Sets the <a href="https://developer.android.com/reference/android/view/Surface.html" title="class or interface in android.view" class="externalLink" target="_top"><code>Surface</code></a> onto which video will be rendered.</div>
</td>
</tr>
<tr id="i106" class="altColor">
<tr id="i107" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setVideoSurfaceHolder(android.view.SurfaceHolder)">setVideoSurfaceHolder</a></span>&#8203;(<a href="https://developer.android.com/reference/android/view/SurfaceHolder.html" title="class or interface in android.view" class="externalLink" target="_top">SurfaceHolder</a>&nbsp;surfaceHolder)</code></th>
<td class="colLast">
@ -1003,38 +1010,40 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
rendered.</div>
</td>
</tr>
<tr id="i107" class="rowColor">
<tr id="i108" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setVideoSurfaceView(android.view.SurfaceView)">setVideoSurfaceView</a></span>&#8203;(<a href="https://developer.android.com/reference/android/view/SurfaceView.html" title="class or interface in android.view" class="externalLink" target="_top">SurfaceView</a>&nbsp;surfaceView)</code></th>
<td class="colLast">
<div class="block">Sets the <a href="https://developer.android.com/reference/android/view/SurfaceView.html" title="class or interface in android.view" class="externalLink" target="_top"><code>SurfaceView</code></a> onto which video will be rendered.</div>
</td>
</tr>
<tr id="i108" class="altColor">
<tr id="i109" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setVideoTextureView(android.view.TextureView)">setVideoTextureView</a></span>&#8203;(<a href="https://developer.android.com/reference/android/view/TextureView.html" title="class or interface in android.view" class="externalLink" target="_top">TextureView</a>&nbsp;textureView)</code></th>
<td class="colLast">
<div class="block">Sets the <a href="https://developer.android.com/reference/android/view/TextureView.html" title="class or interface in android.view" class="externalLink" target="_top"><code>TextureView</code></a> onto which video will be rendered.</div>
</td>
</tr>
<tr id="i109" class="rowColor">
<tr id="i110" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setVolume(float)">setVolume</a></span>&#8203;(float&nbsp;audioVolume)</code></th>
<td class="colLast">
<div class="block">Sets the audio volume, with 0 being silence and 1 being unity gain (signal unchanged).</div>
</td>
</tr>
<tr id="i110" class="altColor">
<tr id="i111" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#stop()">stop</a></span>()</code></th>
<td class="colLast">
<div class="block">Stops playback without resetting the player.</div>
</td>
</tr>
<tr id="i111" class="rowColor">
<tr id="i112" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#stop(boolean)">stop</a></span>&#8203;(boolean&nbsp;reset)</code></th>
<td class="colLast">&nbsp;</td>
<td class="colLast">
<div class="block"><span class="deprecatedLabel">Deprecated.</span></div>
</td>
</tr>
</table>
<ul class="blockList">
@ -1102,7 +1111,9 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<ul class="blockList">
<li class="blockList">
<h4>addListener</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;addListener&#8203;(<a href="Player.EventListener.html" title="interface in com.google.android.exoplayer2">Player.EventListener</a>&nbsp;listener)</pre>
<pre class="methodSignature"><a href="https://developer.android.com/reference/java/lang/Deprecated.html" title="class or interface in java.lang" class="externalLink" target="_top">@Deprecated</a>
public&nbsp;void&nbsp;addListener&#8203;(<a href="Player.EventListener.html" title="interface in com.google.android.exoplayer2">Player.EventListener</a>&nbsp;listener)</pre>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span></div>
<div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="Player.html#addListener(com.google.android.exoplayer2.Player.EventListener)">Player</a></code></span></div>
<div class="block">Registers a listener to receive events from the player.
@ -1144,7 +1155,9 @@ implements <a href="Player.html" title="interface in com.google.android.exoplaye
<ul class="blockList">
<li class="blockList">
<h4>removeListener</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;removeListener&#8203;(<a href="Player.EventListener.html" title="interface in com.google.android.exoplayer2">Player.EventListener</a>&nbsp;listener)</pre>
<pre class="methodSignature"><a href="https://developer.android.com/reference/java/lang/Deprecated.html" title="class or interface in java.lang" class="externalLink" target="_top">@Deprecated</a>
public&nbsp;void&nbsp;removeListener&#8203;(<a href="Player.EventListener.html" title="interface in com.google.android.exoplayer2">Player.EventListener</a>&nbsp;listener)</pre>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span></div>
<div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="Player.html#removeListener(com.google.android.exoplayer2.Player.EventListener)">Player</a></code></span></div>
<div class="block">Unregister a listener registered through <a href="Player.html#addListener(com.google.android.exoplayer2.Player.EventListener)"><code>Player.addListener(EventListener)</code></a>. The listener will
no longer receive events from the player.</div>
@ -2232,7 +2245,9 @@ public&nbsp;void&nbsp;next()</pre>
<ul class="blockList">
<li class="blockList">
<h4>stop</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;stop&#8203;(boolean&nbsp;reset)</pre>
<pre class="methodSignature"><a href="https://developer.android.com/reference/java/lang/Deprecated.html" title="class or interface in java.lang" class="externalLink" target="_top">@Deprecated</a>
public&nbsp;void&nbsp;stop&#8203;(boolean&nbsp;reset)</pre>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span></div>
<dl>
<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
<dd><code><a href="Player.html#stop(boolean)">stop</a></code>&nbsp;in interface&nbsp;<code><a href="Player.html" title="interface in com.google.android.exoplayer2">Player</a></code></dd>
@ -3134,7 +3149,7 @@ public&nbsp;<a href="MediaItem.html" title="class in com.google.android.exoplaye
<a id="setDeviceMuted(boolean)">
<!-- -->
</a>
<ul class="blockListLast">
<ul class="blockList">
<li class="blockList">
<h4>setDeviceMuted</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setDeviceMuted&#8203;(boolean&nbsp;muted)</pre>
@ -3146,6 +3161,16 @@ public&nbsp;<a href="MediaItem.html" title="class in com.google.android.exoplaye
</dl>
</li>
</ul>
<a id="getWrappedPlayer()">
<!-- -->
</a>
<ul class="blockListLast">
<li class="blockList">
<h4>getWrappedPlayer</h4>
<pre class="methodSignature">public&nbsp;<a href="Player.html" title="interface in com.google.android.exoplayer2">Player</a>&nbsp;getWrappedPlayer()</pre>
<div class="block">Returns the <a href="Player.html" title="interface in com.google.android.exoplayer2"><code>Player</code></a> to which operations are forwarded.</div>
</li>
</ul>
</li>
</ul>
</section>

View File

@ -769,7 +769,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<td class="colFirst"><code>static int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#STATE_BUFFERING">STATE_BUFFERING</a></span></code></th>
<td class="colLast">
<div class="block">The player is not able to immediately play from its current position.</div>
<div class="block">The player is not able to immediately play the media, but is doing work toward being able to do
so.</div>
</td>
</tr>
<tr class="rowColor">
@ -783,7 +784,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<td class="colFirst"><code>static int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#STATE_IDLE">STATE_IDLE</a></span></code></th>
<td class="colLast">
<div class="block">The player does not have any media to play.</div>
<div class="block">The player is idle, and must be <a href="#prepare()"><code>prepared</code></a> before it will play the media.</div>
</td>
</tr>
<tr class="rowColor">
@ -1691,7 +1692,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<li class="blockList">
<h4>STATE_IDLE</h4>
<pre>static final&nbsp;int STATE_IDLE</pre>
<div class="block">The player does not have any media to play.</div>
<div class="block">The player is idle, and must be <a href="#prepare()"><code>prepared</code></a> before it will play the media.</div>
<dl>
<dt><span class="seeLabel">See Also:</span></dt>
<dd><a href="../../../../constant-values.html#com.google.android.exoplayer2.Player.STATE_IDLE">Constant Field Values</a></dd>
@ -1705,8 +1706,9 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<li class="blockList">
<h4>STATE_BUFFERING</h4>
<pre>static final&nbsp;int STATE_BUFFERING</pre>
<div class="block">The player is not able to immediately play from its current position. This state typically
occurs when more data needs to be loaded.</div>
<div class="block">The player is not able to immediately play the media, but is doing work toward being able to do
so. This state typically occurs when the player needs to buffer more data before playback can
start.</div>
<dl>
<dt><span class="seeLabel">See Also:</span></dt>
<dd><a href="../../../../constant-values.html#com.google.android.exoplayer2.Player.STATE_BUFFERING">Constant Field Values</a></dd>

View File

@ -451,7 +451,8 @@ implements <a href="Bundleable.html" title="interface in com.google.android.exop
long&nbsp;windowPositionUs,
long&nbsp;defaultPositionProjectionUs)</code></th>
<td class="colLast">
<div class="block">Converts (windowIndex, windowPositionUs) to the corresponding (periodUid, periodPositionUs).</div>
<div class="block">Converts <code>(windowIndex, windowPositionUs)</code> to the corresponding <code>(periodUid,
periodPositionUs)</code>.</div>
</td>
</tr>
<tr id="i12" class="altColor">
@ -833,7 +834,9 @@ public final&nbsp;<a href="https://developer.android.com/reference/android/util/
int&nbsp;windowIndex,
long&nbsp;windowPositionUs,
long&nbsp;defaultPositionProjectionUs)</pre>
<div class="block">Converts (windowIndex, windowPositionUs) to the corresponding (periodUid, periodPositionUs).</div>
<div class="block">Converts <code>(windowIndex, windowPositionUs)</code> to the corresponding <code>(periodUid,
periodPositionUs)</code>. The returned <code>periodPositionUs</code> is constrained to be non-negative,
and to be less than the containing period's duration if it is known.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
<dd><code>window</code> - A <a href="Timeline.Window.html" title="class in com.google.android.exoplayer2"><code>Timeline.Window</code></a> that may be overwritten.</dd>

View File

@ -393,7 +393,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#reset()">reset</a></span>()</code></th>
<td class="colLast">
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
</td>
</tr>
<tr id="i17" class="rowColor">
@ -886,7 +886,7 @@ int&nbsp;getFormatSupport&#8203;(<a href="../Format.html" title="class in com.go
<li class="blockList">
<h4>reset</h4>
<pre class="methodSignature">void&nbsp;reset()</pre>
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
</li>
</ul>
</li>

View File

@ -480,7 +480,7 @@ implements <a href="AudioSink.html" title="interface in com.google.android.exopl
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#reset()">reset</a></span>()</code></th>
<td class="colLast">
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
</td>
</tr>
<tr id="i17" class="rowColor">
@ -1259,7 +1259,7 @@ public&nbsp;int&nbsp;getFormatSupport&#8203;(<a href="../Format.html" title="cla
<h4>reset</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;reset()</pre>
<div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="AudioSink.html#reset()">AudioSink</a></code></span></div>
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
<dl>
<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
<dd><code><a href="AudioSink.html#reset()">reset</a></code>&nbsp;in interface&nbsp;<code><a href="AudioSink.html" title="interface in com.google.android.exoplayer2.audio">AudioSink</a></code></dd>

View File

@ -337,7 +337,7 @@ implements <a href="AudioSink.html" title="interface in com.google.android.exopl
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#reset()">reset</a></span>()</code></th>
<td class="colLast">
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
</td>
</tr>
<tr id="i17" class="rowColor">
@ -886,7 +886,7 @@ public&nbsp;int&nbsp;getFormatSupport&#8203;(<a href="../Format.html" title="cla
<h4>reset</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;reset()</pre>
<div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="AudioSink.html#reset()">AudioSink</a></code></span></div>
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
<dl>
<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
<dd><code><a href="AudioSink.html#reset()">reset</a></code>&nbsp;in interface&nbsp;<code><a href="AudioSink.html" title="interface in com.google.android.exoplayer2.audio">AudioSink</a></code></dd>

View File

@ -1426,7 +1426,9 @@ protected&nbsp;void&nbsp;onPositionDiscontinuity()</pre>
<dd><code>bufferPresentationTimeUs</code> - The presentation time of the output buffer in microseconds.</dd>
<dd><code>isDecodeOnlyBuffer</code> - Whether the buffer was marked with <a href="../C.html#BUFFER_FLAG_DECODE_ONLY"><code>C.BUFFER_FLAG_DECODE_ONLY</code></a>
by the source.</dd>
<dd><code>isLastBuffer</code> - Whether the buffer is the last sample of the current stream.</dd>
<dd><code>isLastBuffer</code> - Whether the buffer is known to contain the last sample of the current
stream. This flag is set on a best effort basis, and any logic relying on it should degrade
gracefully to handle cases where it's not set.</dd>
<dd><code>format</code> - The <a href="../Format.html" title="class in com.google.android.exoplayer2"><code>Format</code></a> associated with the buffer.</dd>
<dt><span class="returnLabel">Returns:</span></dt>
<dd>Whether the output buffer was fully processed (for example, rendered or skipped).</dd>

View File

@ -93,7 +93,7 @@ loadScripts(document, 'script');</script>
</ul>
<ul class="subNavList">
<li>Detail:&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.detail">Method</a></li>
</ul>
@ -181,6 +181,24 @@ extends <a href="../../BasePlayer.html" title="class in com.google.android.exopl
<!-- -->
</a>
<h3>Field Summary</h3>
<table class="memberSummary">
<caption><span>Fields</span><span class="tabEnd">&nbsp;</span></caption>
<tr>
<th class="colFirst" scope="col">Modifier and Type</th>
<th class="colSecond" scope="col">Field</th>
<th class="colLast" scope="col">Description</th>
</tr>
<tr class="altColor">
<td class="colFirst"><code>static float</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#MAX_SPEED_SUPPORTED">MAX_SPEED_SUPPORTED</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>static float</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#MIN_SPEED_SUPPORTED">MIN_SPEED_SUPPORTED</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
</table>
<ul class="blockList">
<li class="blockList"><a id="fields.inherited.from.class.com.google.android.exoplayer2.BasePlayer">
<!-- -->
@ -796,6 +814,42 @@ extends <a href="../../BasePlayer.html" title="class in com.google.android.exopl
<div class="details">
<ul class="blockList">
<li class="blockList">
<!-- ============ FIELD DETAIL =========== -->
<section role="region">
<ul class="blockList">
<li class="blockList"><a id="field.detail">
<!-- -->
</a>
<h3>Field Detail</h3>
<a id="MIN_SPEED_SUPPORTED">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>MIN_SPEED_SUPPORTED</h4>
<pre>public static final&nbsp;float MIN_SPEED_SUPPORTED</pre>
<dl>
<dt><span class="seeLabel">See Also:</span></dt>
<dd><a href="../../../../../../constant-values.html#com.google.android.exoplayer2.ext.cast.CastPlayer.MIN_SPEED_SUPPORTED">Constant Field Values</a></dd>
</dl>
</li>
</ul>
<a id="MAX_SPEED_SUPPORTED">
<!-- -->
</a>
<ul class="blockListLast">
<li class="blockList">
<h4>MAX_SPEED_SUPPORTED</h4>
<pre>public static final&nbsp;float MAX_SPEED_SUPPORTED</pre>
<dl>
<dt><span class="seeLabel">See Also:</span></dt>
<dd><a href="../../../../../../constant-values.html#com.google.android.exoplayer2.ext.cast.CastPlayer.MAX_SPEED_SUPPORTED">Constant Field Values</a></dd>
</dl>
</li>
</ul>
</li>
</ul>
</section>
<!-- ========= CONSTRUCTOR DETAIL ======== -->
<section role="region">
<ul class="blockList">
@ -1302,25 +1356,6 @@ public&nbsp;<a href="../../PlaybackException.html" title="class in com.google.an
</dl>
</li>
</ul>
<a id="setPlaybackParameters(com.google.android.exoplayer2.PlaybackParameters)">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>setPlaybackParameters</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setPlaybackParameters&#8203;(<a href="../../PlaybackParameters.html" title="class in com.google.android.exoplayer2">PlaybackParameters</a>&nbsp;playbackParameters)</pre>
<div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../Player.html#setPlaybackParameters(com.google.android.exoplayer2.PlaybackParameters)">Player</a></code></span></div>
<div class="block">Attempts to set the playback parameters. Passing <a href="../../PlaybackParameters.html#DEFAULT"><code>PlaybackParameters.DEFAULT</code></a> resets the
player to the default, which means there is no speed or pitch adjustment.
<p>Playback parameters changes may cause the player to buffer. <a href="../../Player.Listener.html#onPlaybackParametersChanged(com.google.android.exoplayer2.PlaybackParameters)"><code>Player.Listener.onPlaybackParametersChanged(PlaybackParameters)</code></a> will be called whenever the currently
active playback parameters change.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
<dd><code>playbackParameters</code> - The playback parameters.</dd>
</dl>
</li>
</ul>
<a id="getPlaybackParameters()">
<!-- -->
</a>
@ -1357,6 +1392,25 @@ public&nbsp;<a href="../../PlaybackException.html" title="class in com.google.an
player must not be used after calling this method.</div>
</li>
</ul>
<a id="setPlaybackParameters(com.google.android.exoplayer2.PlaybackParameters)">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>setPlaybackParameters</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setPlaybackParameters&#8203;(<a href="../../PlaybackParameters.html" title="class in com.google.android.exoplayer2">PlaybackParameters</a>&nbsp;playbackParameters)</pre>
<div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../../Player.html#setPlaybackParameters(com.google.android.exoplayer2.PlaybackParameters)">Player</a></code></span></div>
<div class="block">Attempts to set the playback parameters. Passing <a href="../../PlaybackParameters.html#DEFAULT"><code>PlaybackParameters.DEFAULT</code></a> resets the
player to the default, which means there is no speed or pitch adjustment.
<p>Playback parameters changes may cause the player to buffer. <a href="../../Player.Listener.html#onPlaybackParametersChanged(com.google.android.exoplayer2.PlaybackParameters)"><code>Player.Listener.onPlaybackParametersChanged(PlaybackParameters)</code></a> will be called whenever the currently
active playback parameters change.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
<dd><code>playbackParameters</code> - The playback parameters.</dd>
</dl>
</li>
</ul>
<a id="setRepeatMode(int)">
<!-- -->
</a>
@ -1990,7 +2044,7 @@ public&nbsp;<a href="https://guava.dev/releases/27.1-android/api/docs/com/google
</ul>
<ul class="subNavList">
<li>Detail:&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.detail">Method</a></li>
</ul>

View File

@ -1717,7 +1717,9 @@ protected&nbsp;void&nbsp;onProcessedOutputBuffer&#8203;(long&nbsp;presentationTi
<dd><code>bufferPresentationTimeUs</code> - The presentation time of the output buffer in microseconds.</dd>
<dd><code>isDecodeOnlyBuffer</code> - Whether the buffer was marked with <a href="../C.html#BUFFER_FLAG_DECODE_ONLY"><code>C.BUFFER_FLAG_DECODE_ONLY</code></a>
by the source.</dd>
<dd><code>isLastBuffer</code> - Whether the buffer is the last sample of the current stream.</dd>
<dd><code>isLastBuffer</code> - Whether the buffer is known to contain the last sample of the current
stream. This flag is set on a best effort basis, and any logic relying on it should degrade
gracefully to handle cases where it's not set.</dd>
<dd><code>format</code> - The <a href="../Format.html" title="class in com.google.android.exoplayer2"><code>Format</code></a> associated with the buffer.</dd>
<dt><span class="returnLabel">Returns:</span></dt>
<dd>Whether the output buffer was fully processed (for example, rendered or skipped).</dd>

View File

@ -136,11 +136,18 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<pre>public final class <span class="typeNameLabel">StreamKey</span>
extends <a href="https://developer.android.com/reference/java/lang/Object.html" title="class or interface in java.lang" class="externalLink" target="_top">Object</a>
implements <a href="https://developer.android.com/reference/java/lang/Comparable.html" title="class or interface in java.lang" class="externalLink">Comparable</a>&lt;<a href="StreamKey.html" title="class in com.google.android.exoplayer2.offline">StreamKey</a>&gt;, <a href="https://developer.android.com/reference/android/os/Parcelable.html?is-external=true" title="class or interface in android.os" class="externalLink" target="_top">Parcelable</a></pre>
<div class="block">A key for a subset of media which can be separately loaded (a "stream").
<div class="block">A key for a subset of media that can be separately loaded (a "stream").
<p>The stream key consists of a period index, a group index within the period and a track index
<p>The stream key consists of a period index, a group index within the period and a stream index
within the group. The interpretation of these indices depends on the type of media for which the
stream key is used.</div>
stream key is used. Note that they are <em>not</em> the same as track group and track indices,
because multiple tracks can be multiplexed into a single stream.
<p>Application code should not generally attempt to build StreamKey instances directly. Instead,
<code>DownloadHelper.getDownloadRequest</code> can be used to generate download requests with the
correct StreamKeys for the track selections that have been configured on the helper. <code>
MediaPeriod.getStreamKeys</code> provides a lower level way of generating StreamKeys corresponding to a
particular track selection.</div>
</li>
</ul>
</div>
@ -199,9 +206,18 @@ implements <a href="https://developer.android.com/reference/java/lang/Comparable
</tr>
<tr class="rowColor">
<td class="colFirst"><code>int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#streamIndex">streamIndex</a></span></code></th>
<td class="colLast">
<div class="block">The stream index.</div>
</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#trackIndex">trackIndex</a></span></code></th>
<td class="colLast">
<div class="block">The track index.</div>
<div class="block"><span class="deprecatedLabel">Deprecated.</span>
<div class="deprecationComment">Use <a href="#streamIndex"><code>streamIndex</code></a>.</div>
</div>
</td>
</tr>
</table>
@ -230,14 +246,18 @@ implements <a href="https://developer.android.com/reference/java/lang/Comparable
</tr>
<tr class="altColor">
<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(int,int)">StreamKey</a></span>&#8203;(int&nbsp;groupIndex,
int&nbsp;trackIndex)</code></th>
<td class="colLast">&nbsp;</td>
int&nbsp;streamIndex)</code></th>
<td class="colLast">
<div class="block">Creates an instance with <a href="#periodIndex"><code>periodIndex</code></a> set to 0.</div>
</td>
</tr>
<tr class="rowColor">
<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(int,int,int)">StreamKey</a></span>&#8203;(int&nbsp;periodIndex,
int&nbsp;groupIndex,
int&nbsp;trackIndex)</code></th>
<td class="colLast">&nbsp;</td>
int&nbsp;streamIndex)</code></th>
<td class="colLast">
<div class="block">Creates an instance.</div>
</td>
</tr>
</table>
</li>
@ -332,14 +352,27 @@ implements <a href="https://developer.android.com/reference/java/lang/Comparable
<div class="block">The group index.</div>
</li>
</ul>
<a id="streamIndex">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>streamIndex</h4>
<pre>public final&nbsp;int streamIndex</pre>
<div class="block">The stream index.</div>
</li>
</ul>
<a id="trackIndex">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>trackIndex</h4>
<pre>public final&nbsp;int trackIndex</pre>
<div class="block">The track index.</div>
<pre><a href="https://developer.android.com/reference/java/lang/Deprecated.html" title="class or interface in java.lang" class="externalLink" target="_top">@Deprecated</a>
public final&nbsp;int trackIndex</pre>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
<div class="deprecationComment">Use <a href="#streamIndex"><code>streamIndex</code></a>.</div>
</div>
</li>
</ul>
<a id="CREATOR">
@ -368,11 +401,12 @@ implements <a href="https://developer.android.com/reference/java/lang/Comparable
<li class="blockList">
<h4>StreamKey</h4>
<pre>public&nbsp;StreamKey&#8203;(int&nbsp;groupIndex,
int&nbsp;trackIndex)</pre>
int&nbsp;streamIndex)</pre>
<div class="block">Creates an instance with <a href="#periodIndex"><code>periodIndex</code></a> set to 0.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
<dd><code>groupIndex</code> - The group index.</dd>
<dd><code>trackIndex</code> - The track index.</dd>
<dd><code>streamIndex</code> - The stream index.</dd>
</dl>
</li>
</ul>
@ -384,12 +418,13 @@ implements <a href="https://developer.android.com/reference/java/lang/Comparable
<h4>StreamKey</h4>
<pre>public&nbsp;StreamKey&#8203;(int&nbsp;periodIndex,
int&nbsp;groupIndex,
int&nbsp;trackIndex)</pre>
int&nbsp;streamIndex)</pre>
<div class="block">Creates an instance.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
<dd><code>periodIndex</code> - The period index.</dd>
<dd><code>groupIndex</code> - The group index.</dd>
<dd><code>trackIndex</code> - The track index.</dd>
<dd><code>streamIndex</code> - The stream index.</dd>
</dl>
</li>
</ul>

View File

@ -263,7 +263,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<tr class="altColor">
<th class="colFirst" scope="row"><a href="StreamKey.html" title="class in com.google.android.exoplayer2.offline">StreamKey</a></th>
<td class="colLast">
<div class="block">A key for a subset of media which can be separately loaded (a "stream").</div>
<div class="block">A key for a subset of media that can be separately loaded (a "stream").</div>
</td>
</tr>
</tbody>

View File

@ -131,7 +131,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<hr>
<pre>public final class <span class="typeNameLabel">BaseUrlExclusionList</span>
extends <a href="https://developer.android.com/reference/java/lang/Object.html" title="class or interface in java.lang" class="externalLink" target="_top">Object</a></pre>
<div class="block">Holds the state of <a href="#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used <a href="#selectBaseUrl(java.util.List)"><code>to select</code></a> a base URL based on these exclusions.</div>
<div class="block">Holds the state of <a href="#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used to <a href="#selectBaseUrl(java.util.List)"><code>select</code></a> a base URL based on these exclusions.</div>
</li>
</ul>
</div>

View File

@ -25,7 +25,7 @@
catch(err) {
}
//-->
var data = {"i0":9,"i1":9,"i2":9,"i3":9,"i4":9,"i5":9,"i6":9,"i7":9,"i8":9};
var data = {"i0":9,"i1":9,"i2":9,"i3":9,"i4":9,"i5":9,"i6":9,"i7":9,"i8":9,"i9":9};
var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],8:["t4","Concrete Methods"]};
var altColor = "altColor";
var rowColor = "rowColor";
@ -163,9 +163,9 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
</tr>
<tr id="i1" class="rowColor">
<td class="colFirst"><code>static <a href="../../upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream">DataSpec</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#buildDataSpec(java.lang.String,com.google.android.exoplayer2.source.dash.manifest.RangedUri,java.lang.String,int)">buildDataSpec</a></span>&#8203;(<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;baseUrl,
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#buildDataSpec(com.google.android.exoplayer2.source.dash.manifest.Representation,java.lang.String,com.google.android.exoplayer2.source.dash.manifest.RangedUri,int)">buildDataSpec</a></span>&#8203;(<a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest">Representation</a>&nbsp;representation,
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;baseUrl,
<a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest">RangedUri</a>&nbsp;requestUri,
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;cacheKey,
int&nbsp;flags)</code></th>
<td class="colLast">
<div class="block">Builds a <a href="../../upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream"><code>DataSpec</code></a> for a given <a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>RangedUri</code></a> belonging to <a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a>.</div>
@ -236,6 +236,14 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
<div class="block">Loads initialization data for the <code>representation</code> and returns the sample <a href="../../Format.html" title="class in com.google.android.exoplayer2"><code>Format</code></a>.</div>
</td>
</tr>
<tr id="i9" class="rowColor">
<td class="colFirst"><code>static <a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#resolveCacheKey(com.google.android.exoplayer2.source.dash.manifest.Representation,com.google.android.exoplayer2.source.dash.manifest.RangedUri)">resolveCacheKey</a></span>&#8203;(<a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest">Representation</a>&nbsp;representation,
<a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest">RangedUri</a>&nbsp;rangedUri)</code></th>
<td class="colLast">
<div class="block">Resolves the cache key to be used when requesting the given ranged URI for the given <a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a>.</div>
</td>
</tr>
</table>
<ul class="blockList">
<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
@ -260,23 +268,22 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
<!-- -->
</a>
<h3>Method Detail</h3>
<a id="buildDataSpec(java.lang.String,com.google.android.exoplayer2.source.dash.manifest.RangedUri,java.lang.String,int)">
<a id="buildDataSpec(com.google.android.exoplayer2.source.dash.manifest.Representation,java.lang.String,com.google.android.exoplayer2.source.dash.manifest.RangedUri,int)">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>buildDataSpec</h4>
<pre class="methodSignature">public static&nbsp;<a href="../../upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream">DataSpec</a>&nbsp;buildDataSpec&#8203;(<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;baseUrl,
<pre class="methodSignature">public static&nbsp;<a href="../../upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream">DataSpec</a>&nbsp;buildDataSpec&#8203;(<a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest">Representation</a>&nbsp;representation,
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;baseUrl,
<a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest">RangedUri</a>&nbsp;requestUri,
@Nullable
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;cacheKey,
int&nbsp;flags)</pre>
<div class="block">Builds a <a href="../../upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream"><code>DataSpec</code></a> for a given <a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>RangedUri</code></a> belonging to <a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a>.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
<dd><code>representation</code> - The <a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a> to which the request belongs.</dd>
<dd><code>baseUrl</code> - The base url with which to resolve the request URI.</dd>
<dd><code>requestUri</code> - The <a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>RangedUri</code></a> of the data to request.</dd>
<dd><code>cacheKey</code> - An optional cache key.</dd>
<dd><code>flags</code> - Flags to be set on the returned <a href="../../upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream"><code>DataSpec</code></a>. See <a href="../../upstream/DataSpec.Builder.html#setFlags(int)"><code>DataSpec.Builder.setFlags(int)</code></a>.</dd>
<dt><span class="returnLabel">Returns:</span></dt>
<dd>The <a href="../../upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream"><code>DataSpec</code></a>.</dd>
@ -457,7 +464,7 @@ public static&nbsp;<a href="../../extractor/ChunkIndex.html" title="class in com
<a id="loadInitializationData(com.google.android.exoplayer2.source.chunk.ChunkExtractor,com.google.android.exoplayer2.upstream.DataSource,com.google.android.exoplayer2.source.dash.manifest.Representation,boolean)">
<!-- -->
</a>
<ul class="blockListLast">
<ul class="blockList">
<li class="blockList">
<h4>loadInitializationData</h4>
<pre class="methodSignature">public static&nbsp;void&nbsp;loadInitializationData&#8203;(<a href="../chunk/ChunkExtractor.html" title="interface in com.google.android.exoplayer2.source.chunk">ChunkExtractor</a>&nbsp;chunkExtractor,
@ -480,6 +487,24 @@ public static&nbsp;<a href="../../extractor/ChunkIndex.html" title="class in com
</dl>
</li>
</ul>
<a id="resolveCacheKey(com.google.android.exoplayer2.source.dash.manifest.Representation,com.google.android.exoplayer2.source.dash.manifest.RangedUri)">
<!-- -->
</a>
<ul class="blockListLast">
<li class="blockList">
<h4>resolveCacheKey</h4>
<pre class="methodSignature">public static&nbsp;<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink">String</a>&nbsp;resolveCacheKey&#8203;(<a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest" target="_top">Representation</a>&nbsp;representation,
<a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest">RangedUri</a>&nbsp;rangedUri)</pre>
<div class="block">Resolves the cache key to be used when requesting the given ranged URI for the given <a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a>.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
<dd><code>representation</code> - The <a href="manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a> to which the URI belongs to.</dd>
<dd><code>rangedUri</code> - The URI for which to resolve the cache key.</dd>
<dt><span class="returnLabel">Returns:</span></dt>
<dd>The cache key.</dd>
</dl>
</li>
</ul>
</li>
</ul>
</section>

View File

@ -692,6 +692,7 @@ implements <a href="DashChunkSource.html" title="interface in com.google.android
<a href="https://developer.android.com/reference/java/lang/Object.html" title="class or interface in java.lang" class="externalLink" target="_top">Object</a>&nbsp;trackSelectionData,
@Nullable
<a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest">RangedUri</a>&nbsp;initializationUri,
@Nullable
<a href="manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest">RangedUri</a>&nbsp;indexUri)</pre>
</li>
</ul>

View File

@ -141,7 +141,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<tr class="altColor">
<th class="colFirst" scope="row"><a href="BaseUrlExclusionList.html" title="class in com.google.android.exoplayer2.source.dash">BaseUrlExclusionList</a></th>
<td class="colLast">
<div class="block">Holds the state of <a href="BaseUrlExclusionList.html#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used <a href="BaseUrlExclusionList.html#selectBaseUrl(java.util.List)"><code>to select</code></a> a base URL based on these exclusions.</div>
<div class="block">Holds the state of <a href="BaseUrlExclusionList.html#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used to <a href="BaseUrlExclusionList.html#selectBaseUrl(java.util.List)"><code>select</code></a> a base URL based on these exclusions.</div>
</td>
</tr>
<tr class="rowColor">

View File

@ -261,7 +261,7 @@ implements <a href="Dumper.Dumpable.html" title="interface in com.google.android
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#reset()">reset</a></span>()</code></th>
<td class="colLast">
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
</td>
</tr>
</table>
@ -430,7 +430,7 @@ implements <a href="Dumper.Dumpable.html" title="interface in com.google.android
<h4>reset</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;reset()</pre>
<div class="block"><span class="descfrmTypeLabel">Description copied from interface:&nbsp;<code><a href="../audio/AudioSink.html#reset()">AudioSink</a></code></span></div>
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
<dl>
<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
<dd><code><a href="../audio/AudioSink.html#reset()">reset</a></code>&nbsp;in interface&nbsp;<code><a href="../audio/AudioSink.html" title="interface in com.google.android.exoplayer2.audio">AudioSink</a></code></dd>

View File

@ -267,12 +267,12 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
</tr>
<tr id="i5" class="rowColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException()">dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException</a></span>()</code></th>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#dataSpecWithPositionAtEnd_readsZeroBytes()">dataSpecWithPositionAtEnd_readsZeroBytes</a></span>()</code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr id="i6" class="altColor">
<td class="colFirst"><code>void</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException()">dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException</a></span>()</code></th>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#dataSpecWithPositionAtEndAndLength_readsZeroBytes()">dataSpecWithPositionAtEndAndLength_readsZeroBytes</a></span>()</code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr id="i7" class="rowColor">
@ -545,13 +545,13 @@ protected&nbsp;<a href="../upstream/DataSource.html" title="interface in com.goo
</dl>
</li>
</ul>
<a id="dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException()">
<a id="dataSpecWithPositionAtEnd_readsZeroBytes()">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException()
<h4>dataSpecWithPositionAtEnd_readsZeroBytes</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;dataSpecWithPositionAtEnd_readsZeroBytes()
throws <a href="https://developer.android.com/reference/java/lang/Exception.html" title="class or interface in java.lang" class="externalLink" target="_top">Exception</a></pre>
<dl>
<dt><span class="throwsLabel">Throws:</span></dt>
@ -559,13 +559,13 @@ protected&nbsp;<a href="../upstream/DataSource.html" title="interface in com.goo
</dl>
</li>
</ul>
<a id="dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException()">
<a id="dataSpecWithPositionAtEndAndLength_readsZeroBytes()">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException()
<h4>dataSpecWithPositionAtEndAndLength_readsZeroBytes</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;dataSpecWithPositionAtEndAndLength_readsZeroBytes()
throws <a href="https://developer.android.com/reference/java/lang/Exception.html" title="class or interface in java.lang" class="externalLink" target="_top">Exception</a></pre>
<dl>
<dt><span class="throwsLabel">Throws:</span></dt>

View File

@ -246,7 +246,7 @@ extends <a href="MappingTrackSelector.html" title="class in com.google.android.e
<h2>Tunneling</h2>
Tunneled playback can be enabled in cases where the combination of renderers and selected tracks
support it. Tunneled playback is enabled by passing an audio session ID to <a href="DefaultTrackSelector.ParametersBuilder.html#setTunnelingEnabled(boolean)"><code>DefaultTrackSelector.ParametersBuilder.setTunnelingEnabled(boolean)</code></a>.</div>
supports it. This can be done by using <a href="DefaultTrackSelector.ParametersBuilder.html#setTunnelingEnabled(boolean)"><code>DefaultTrackSelector.ParametersBuilder.setTunnelingEnabled(boolean)</code></a>.</div>
</li>
</ul>
</div>

View File

@ -87,13 +87,13 @@ loadScripts(document, 'script');</script>
<ul class="subNavList">
<li>Summary:&nbsp;</li>
<li>Nested&nbsp;|&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.summary">Method</a></li>
</ul>
<ul class="subNavList">
<li>Detail:&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.detail">Method</a></li>
</ul>
@ -142,6 +142,114 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
<div class="summary">
<ul class="blockList">
<li class="blockList">
<!-- =========== FIELD SUMMARY =========== -->
<section role="region">
<ul class="blockList">
<li class="blockList"><a id="field.summary">
<!-- -->
</a>
<h3>Field Summary</h3>
<table class="memberSummary">
<caption><span>Fields</span><span class="tabEnd">&nbsp;</span></caption>
<tr>
<th class="colFirst" scope="col">Modifier and Type</th>
<th class="colSecond" scope="col">Field</th>
<th class="colLast" scope="col">Description</th>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#channelDescriptionResourceId">channelDescriptionResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected <a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#channelId">channelId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#channelImportance">channelImportance</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#channelNameResourceId">channelNameResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected <a href="https://developer.android.com/reference/android/content/Context.html" title="class or interface in android.content" class="externalLink" target="_top">Context</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#context">context</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected <a href="PlayerNotificationManager.CustomActionReceiver.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.CustomActionReceiver</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#customActionReceiver">customActionReceiver</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#fastForwardActionIconResourceId">fastForwardActionIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected <a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#groupKey">groupKey</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected <a href="PlayerNotificationManager.MediaDescriptionAdapter.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.MediaDescriptionAdapter</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#mediaDescriptionAdapter">mediaDescriptionAdapter</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#nextActionIconResourceId">nextActionIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#notificationId">notificationId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected <a href="PlayerNotificationManager.NotificationListener.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.NotificationListener</a></code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#notificationListener">notificationListener</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#pauseActionIconResourceId">pauseActionIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#playActionIconResourceId">playActionIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#previousActionIconResourceId">previousActionIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#rewindActionIconResourceId">rewindActionIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#smallIconResourceId">smallIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
<tr class="rowColor">
<td class="colFirst"><code>protected int</code></td>
<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#stopActionIconResourceId">stopActionIconResourceId</a></span></code></th>
<td class="colLast">&nbsp;</td>
</tr>
</table>
</li>
</ul>
</section>
<!-- ======== CONSTRUCTOR SUMMARY ======== -->
<section role="region">
<ul class="blockList">
@ -321,6 +429,181 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
<div class="details">
<ul class="blockList">
<li class="blockList">
<!-- ============ FIELD DETAIL =========== -->
<section role="region">
<ul class="blockList">
<li class="blockList"><a id="field.detail">
<!-- -->
</a>
<h3>Field Detail</h3>
<a id="context">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>context</h4>
<pre>protected final&nbsp;<a href="https://developer.android.com/reference/android/content/Context.html" title="class or interface in android.content" class="externalLink" target="_top">Context</a> context</pre>
</li>
</ul>
<a id="notificationId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>notificationId</h4>
<pre>protected final&nbsp;int notificationId</pre>
</li>
</ul>
<a id="channelId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>channelId</h4>
<pre>protected final&nbsp;<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a> channelId</pre>
</li>
</ul>
<a id="notificationListener">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>notificationListener</h4>
<pre>@Nullable
protected&nbsp;<a href="PlayerNotificationManager.NotificationListener.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.NotificationListener</a> notificationListener</pre>
</li>
</ul>
<a id="customActionReceiver">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>customActionReceiver</h4>
<pre>@Nullable
protected&nbsp;<a href="PlayerNotificationManager.CustomActionReceiver.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.CustomActionReceiver</a> customActionReceiver</pre>
</li>
</ul>
<a id="mediaDescriptionAdapter">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>mediaDescriptionAdapter</h4>
<pre>protected&nbsp;<a href="PlayerNotificationManager.MediaDescriptionAdapter.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.MediaDescriptionAdapter</a> mediaDescriptionAdapter</pre>
</li>
</ul>
<a id="channelNameResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>channelNameResourceId</h4>
<pre>protected&nbsp;int channelNameResourceId</pre>
</li>
</ul>
<a id="channelDescriptionResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>channelDescriptionResourceId</h4>
<pre>protected&nbsp;int channelDescriptionResourceId</pre>
</li>
</ul>
<a id="channelImportance">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>channelImportance</h4>
<pre>protected&nbsp;int channelImportance</pre>
</li>
</ul>
<a id="smallIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>smallIconResourceId</h4>
<pre>protected&nbsp;int smallIconResourceId</pre>
</li>
</ul>
<a id="rewindActionIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>rewindActionIconResourceId</h4>
<pre>protected&nbsp;int rewindActionIconResourceId</pre>
</li>
</ul>
<a id="playActionIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>playActionIconResourceId</h4>
<pre>protected&nbsp;int playActionIconResourceId</pre>
</li>
</ul>
<a id="pauseActionIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>pauseActionIconResourceId</h4>
<pre>protected&nbsp;int pauseActionIconResourceId</pre>
</li>
</ul>
<a id="stopActionIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>stopActionIconResourceId</h4>
<pre>protected&nbsp;int stopActionIconResourceId</pre>
</li>
</ul>
<a id="fastForwardActionIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>fastForwardActionIconResourceId</h4>
<pre>protected&nbsp;int fastForwardActionIconResourceId</pre>
</li>
</ul>
<a id="previousActionIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>previousActionIconResourceId</h4>
<pre>protected&nbsp;int previousActionIconResourceId</pre>
</li>
</ul>
<a id="nextActionIconResourceId">
<!-- -->
</a>
<ul class="blockList">
<li class="blockList">
<h4>nextActionIconResourceId</h4>
<pre>protected&nbsp;int nextActionIconResourceId</pre>
</li>
</ul>
<a id="groupKey">
<!-- -->
</a>
<ul class="blockListLast">
<li class="blockList">
<h4>groupKey</h4>
<pre>@Nullable
protected&nbsp;<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a> groupKey</pre>
</li>
</ul>
</li>
</ul>
</section>
<!-- ========= CONSTRUCTOR DETAIL ======== -->
<section role="region">
<ul class="blockList">
@ -681,13 +964,13 @@ public&nbsp;Builder&#8203;(<a href="https://developer.android.com/reference/andr
<ul class="subNavList">
<li>Summary:&nbsp;</li>
<li>Nested&nbsp;|&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.summary">Method</a></li>
</ul>
<ul class="subNavList">
<li>Detail:&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.detail">Method</a></li>
</ul>

View File

@ -88,13 +88,13 @@ loadScripts(document, 'script');</script>
<li>Summary:&nbsp;</li>
<li><a href="#nested.class.summary">Nested</a>&nbsp;|&nbsp;</li>
<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
<li>Constr&nbsp;|&nbsp;</li>
<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.summary">Method</a></li>
</ul>
<ul class="subNavList">
<li>Detail:&nbsp;</li>
<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
<li>Constr&nbsp;|&nbsp;</li>
<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.detail">Method</a></li>
</ul>
</div>
@ -373,6 +373,43 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
</li>
</ul>
</section>
<!-- ======== CONSTRUCTOR SUMMARY ======== -->
<section role="region">
<ul class="blockList">
<li class="blockList"><a id="constructor.summary">
<!-- -->
</a>
<h3>Constructor Summary</h3>
<table class="memberSummary">
<caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
<tr>
<th class="colFirst" scope="col">Modifier</th>
<th class="colSecond" scope="col">Constructor</th>
<th class="colLast" scope="col">Description</th>
</tr>
<tr class="altColor">
<td class="colFirst"><code>protected </code></td>
<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(android.content.Context,java.lang.String,int,com.google.android.exoplayer2.ui.PlayerNotificationManager.MediaDescriptionAdapter,com.google.android.exoplayer2.ui.PlayerNotificationManager.NotificationListener,com.google.android.exoplayer2.ui.PlayerNotificationManager.CustomActionReceiver,int,int,int,int,int,int,int,int,java.lang.String)">PlayerNotificationManager</a></span>&#8203;(<a href="https://developer.android.com/reference/android/content/Context.html" title="class or interface in android.content" class="externalLink" target="_top">Context</a>&nbsp;context,
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;channelId,
int&nbsp;notificationId,
<a href="PlayerNotificationManager.MediaDescriptionAdapter.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.MediaDescriptionAdapter</a>&nbsp;mediaDescriptionAdapter,
<a href="PlayerNotificationManager.NotificationListener.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.NotificationListener</a>&nbsp;notificationListener,
<a href="PlayerNotificationManager.CustomActionReceiver.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.CustomActionReceiver</a>&nbsp;customActionReceiver,
int&nbsp;smallIconResourceId,
int&nbsp;playActionIconResourceId,
int&nbsp;pauseActionIconResourceId,
int&nbsp;stopActionIconResourceId,
int&nbsp;rewindActionIconResourceId,
int&nbsp;fastForwardActionIconResourceId,
int&nbsp;previousActionIconResourceId,
int&nbsp;nextActionIconResourceId,
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;groupKey)</code></th>
<td class="colLast">&nbsp;</td>
</tr>
</table>
</li>
</ul>
</section>
<!-- ========== METHOD SUMMARY =========== -->
<section role="region">
<ul class="blockList">
@ -718,6 +755,42 @@ extends <a href="https://developer.android.com/reference/java/lang/Object.html"
</li>
</ul>
</section>
<!-- ========= CONSTRUCTOR DETAIL ======== -->
<section role="region">
<ul class="blockList">
<li class="blockList"><a id="constructor.detail">
<!-- -->
</a>
<h3>Constructor Detail</h3>
<a id="&lt;init&gt;(android.content.Context,java.lang.String,int,com.google.android.exoplayer2.ui.PlayerNotificationManager.MediaDescriptionAdapter,com.google.android.exoplayer2.ui.PlayerNotificationManager.NotificationListener,com.google.android.exoplayer2.ui.PlayerNotificationManager.CustomActionReceiver,int,int,int,int,int,int,int,int,java.lang.String)">
<!-- -->
</a>
<ul class="blockListLast">
<li class="blockList">
<h4>PlayerNotificationManager</h4>
<pre>protected&nbsp;PlayerNotificationManager&#8203;(<a href="https://developer.android.com/reference/android/content/Context.html" title="class or interface in android.content" class="externalLink" target="_top">Context</a>&nbsp;context,
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;channelId,
int&nbsp;notificationId,
<a href="PlayerNotificationManager.MediaDescriptionAdapter.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.MediaDescriptionAdapter</a>&nbsp;mediaDescriptionAdapter,
@Nullable
<a href="PlayerNotificationManager.NotificationListener.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.NotificationListener</a>&nbsp;notificationListener,
@Nullable
<a href="PlayerNotificationManager.CustomActionReceiver.html" title="interface in com.google.android.exoplayer2.ui">PlayerNotificationManager.CustomActionReceiver</a>&nbsp;customActionReceiver,
int&nbsp;smallIconResourceId,
int&nbsp;playActionIconResourceId,
int&nbsp;pauseActionIconResourceId,
int&nbsp;stopActionIconResourceId,
int&nbsp;rewindActionIconResourceId,
int&nbsp;fastForwardActionIconResourceId,
int&nbsp;previousActionIconResourceId,
int&nbsp;nextActionIconResourceId,
@Nullable
<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a>&nbsp;groupKey)</pre>
</li>
</ul>
</li>
</ul>
</section>
<!-- ============ METHOD DETAIL ========== -->
<section role="region">
<ul class="blockList">
@ -771,7 +844,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUseNextAction</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUseNextAction&#8203;(boolean&nbsp;useNextAction)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUseNextAction&#8203;(boolean&nbsp;useNextAction)</pre>
<div class="block">Sets whether the next action should be used.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
@ -785,7 +858,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUsePreviousAction</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUsePreviousAction&#8203;(boolean&nbsp;usePreviousAction)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUsePreviousAction&#8203;(boolean&nbsp;usePreviousAction)</pre>
<div class="block">Sets whether the previous action should be used.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
@ -799,7 +872,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUseNextActionInCompactView</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUseNextActionInCompactView&#8203;(boolean&nbsp;useNextActionInCompactView)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUseNextActionInCompactView&#8203;(boolean&nbsp;useNextActionInCompactView)</pre>
<div class="block">If <a href="#setUseNextAction(boolean)"><code>useNextAction</code></a> is <code>true</code>, sets whether the next action should
also be used in compact view. Has no effect if <a href="#setUseNextAction(boolean)"><code>useNextAction</code></a> is
<code>false</code>.
@ -817,7 +890,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUsePreviousActionInCompactView</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUsePreviousActionInCompactView&#8203;(boolean&nbsp;usePreviousActionInCompactView)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUsePreviousActionInCompactView&#8203;(boolean&nbsp;usePreviousActionInCompactView)</pre>
<div class="block">If <a href="#setUsePreviousAction(boolean)"><code>usePreviousAction</code></a> is <code>true</code>, sets whether the previous
action should also be used in compact view. Has no effect if <a href="#setUsePreviousAction(boolean)"><code>usePreviousAction</code></a> is <code>false</code>.
@ -834,7 +907,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUseFastForwardAction</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUseFastForwardAction&#8203;(boolean&nbsp;useFastForwardAction)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUseFastForwardAction&#8203;(boolean&nbsp;useFastForwardAction)</pre>
<div class="block">Sets whether the fast forward action should be used.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
@ -848,7 +921,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUseRewindAction</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUseRewindAction&#8203;(boolean&nbsp;useRewindAction)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUseRewindAction&#8203;(boolean&nbsp;useRewindAction)</pre>
<div class="block">Sets whether the rewind action should be used.</div>
<dl>
<dt><span class="paramLabel">Parameters:</span></dt>
@ -862,7 +935,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUseFastForwardActionInCompactView</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUseFastForwardActionInCompactView&#8203;(boolean&nbsp;useFastForwardActionInCompactView)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUseFastForwardActionInCompactView&#8203;(boolean&nbsp;useFastForwardActionInCompactView)</pre>
<div class="block">Sets whether the fast forward action should also be used in compact view. Has no effect if
<a href="#ACTION_FAST_FORWARD"><code>ACTION_FAST_FORWARD</code></a> is not enabled, for instance if the media is not seekable.
@ -880,7 +953,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>setUseRewindActionInCompactView</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;setUseRewindActionInCompactView&#8203;(boolean&nbsp;useRewindActionInCompactView)</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;setUseRewindActionInCompactView&#8203;(boolean&nbsp;useRewindActionInCompactView)</pre>
<div class="block">Sets whether the rewind action should also be used in compact view. Has no effect if <a href="#ACTION_REWIND"><code>ACTION_REWIND</code></a> is not enabled, for instance if the media is not seekable.
<p>If set to <code>true</code>, <a href="#setUsePreviousActionInCompactView(boolean)"><code>setUsePreviousActionInCompactView</code></a> is set to false.</div>
@ -1086,7 +1159,7 @@ public final&nbsp;void&nbsp;setControlDispatcher&#8203;(<a href="../ControlDispa
<ul class="blockList">
<li class="blockList">
<h4>invalidate</h4>
<pre class="methodSignature">public&nbsp;void&nbsp;invalidate()</pre>
<pre class="methodSignature">public final&nbsp;void&nbsp;invalidate()</pre>
<div class="block">Forces an update of the notification if already started.</div>
</li>
</ul>
@ -1224,13 +1297,13 @@ protected&nbsp;androidx.core.app.NotificationCompat.Builder&nbsp;createNotificat
<li>Summary:&nbsp;</li>
<li><a href="#nested.class.summary">Nested</a>&nbsp;|&nbsp;</li>
<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
<li>Constr&nbsp;|&nbsp;</li>
<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.summary">Method</a></li>
</ul>
<ul class="subNavList">
<li>Detail:&nbsp;</li>
<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
<li>Constr&nbsp;|&nbsp;</li>
<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
<li><a href="#method.detail">Method</a></li>
</ul>
</div>

View File

@ -1473,7 +1473,9 @@ protected&nbsp;void&nbsp;onQueueInputBuffer&#8203;(<a href="../decoder/DecoderIn
<dd><code>bufferPresentationTimeUs</code> - The presentation time of the output buffer in microseconds.</dd>
<dd><code>isDecodeOnlyBuffer</code> - Whether the buffer was marked with <a href="../C.html#BUFFER_FLAG_DECODE_ONLY"><code>C.BUFFER_FLAG_DECODE_ONLY</code></a>
by the source.</dd>
<dd><code>isLastBuffer</code> - Whether the buffer is the last sample of the current stream.</dd>
<dd><code>isLastBuffer</code> - Whether the buffer is known to contain the last sample of the current
stream. This flag is set on a best effort basis, and any logic relying on it should degrade
gracefully to handle cases where it's not set.</dd>
<dd><code>format</code> - The <a href="../Format.html" title="class in com.google.android.exoplayer2"><code>Format</code></a> associated with the buffer.</dd>
<dt><span class="returnLabel">Returns:</span></dt>
<dd>Whether the output buffer was fully processed (for example, rendered or skipped).</dd>

View File

@ -1850,21 +1850,21 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<!-- -->
</a><code>public&nbsp;static&nbsp;final&nbsp;<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a></code></td>
<th class="colSecond" scope="row"><code><a href="com/google/android/exoplayer2/ExoPlayerLibraryInfo.html#VERSION">VERSION</a></code></th>
<td class="colLast"><code>"2.14.2"</code></td>
<td class="colLast"><code>"2.15.1"</code></td>
</tr>
<tr class="rowColor">
<td class="colFirst"><a id="com.google.android.exoplayer2.ExoPlayerLibraryInfo.VERSION_INT">
<!-- -->
</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
<th class="colSecond" scope="row"><code><a href="com/google/android/exoplayer2/ExoPlayerLibraryInfo.html#VERSION_INT">VERSION_INT</a></code></th>
<td class="colLast"><code>2014002</code></td>
<td class="colLast"><code>2015001</code></td>
</tr>
<tr class="altColor">
<td class="colFirst"><a id="com.google.android.exoplayer2.ExoPlayerLibraryInfo.VERSION_SLASHY">
<!-- -->
</a><code>public&nbsp;static&nbsp;final&nbsp;<a href="https://developer.android.com/reference/java/lang/String.html" title="class or interface in java.lang" class="externalLink" target="_top">String</a></code></td>
<th class="colSecond" scope="row"><code><a href="com/google/android/exoplayer2/ExoPlayerLibraryInfo.html#VERSION_SLASHY">VERSION_SLASHY</a></code></th>
<td class="colLast"><code>"ExoPlayerLib/2.14.2"</code></td>
<td class="colLast"><code>"ExoPlayerLib/2.15.1"</code></td>
</tr>
</tbody>
</table>
@ -5001,6 +5001,32 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<ul class="blockList">
<li class="blockList">
<table class="constantsSummary">
<caption><span>com.google.android.exoplayer2.ext.cast.<a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html" title="class in com.google.android.exoplayer2.ext.cast">CastPlayer</a></span><span class="tabEnd">&nbsp;</span></caption>
<tr>
<th class="colFirst" scope="col">Modifier and Type</th>
<th class="colSecond" scope="col">Constant Field</th>
<th class="colLast" scope="col">Value</th>
</tr>
<tbody>
<tr class="altColor">
<td class="colFirst"><a id="com.google.android.exoplayer2.ext.cast.CastPlayer.MAX_SPEED_SUPPORTED">
<!-- -->
</a><code>public&nbsp;static&nbsp;final&nbsp;float</code></td>
<th class="colSecond" scope="row"><code><a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html#MAX_SPEED_SUPPORTED">MAX_SPEED_SUPPORTED</a></code></th>
<td class="colLast"><code>2.0f</code></td>
</tr>
<tr class="rowColor">
<td class="colFirst"><a id="com.google.android.exoplayer2.ext.cast.CastPlayer.MIN_SPEED_SUPPORTED">
<!-- -->
</a><code>public&nbsp;static&nbsp;final&nbsp;float</code></td>
<th class="colSecond" scope="row"><code><a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html#MIN_SPEED_SUPPORTED">MIN_SPEED_SUPPORTED</a></code></th>
<td class="colLast"><code>0.5f</code></td>
</tr>
</tbody>
</table>
</li>
<li class="blockList">
<table class="constantsSummary">
<caption><span>com.google.android.exoplayer2.ext.cast.<a href="com/google/android/exoplayer2/ext/cast/DefaultCastOptionsProvider.html" title="class in com.google.android.exoplayer2.ext.cast">DefaultCastOptionsProvider</a></span><span class="tabEnd">&nbsp;</span></caption>
<tr>
<th class="colFirst" scope="col">Modifier and Type</th>

View File

@ -400,96 +400,102 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</td>
</tr>
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/offline/StreamKey.html#trackIndex">com.google.android.exoplayer2.offline.StreamKey.trackIndex</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/offline/StreamKey.html#streamIndex"><code>StreamKey.streamIndex</code></a>.</div>
</td>
</tr>
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#EVENT_STATIC_METADATA_CHANGED">com.google.android.exoplayer2.Player.EVENT_STATIC_METADATA_CHANGED</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#EVENT_MEDIA_METADATA_CHANGED"><code>Player.EVENT_MEDIA_METADATA_CHANGED</code></a> for structured metadata changes.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Renderer.html#VIDEO_SCALING_MODE_DEFAULT">com.google.android.exoplayer2.Renderer.VIDEO_SCALING_MODE_DEFAULT</a></th>
<td class="colLast">
<div class="deprecationComment">Use <code>C.VIDEO_SCALING_MODE_DEFAULT</code>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Renderer.html#VIDEO_SCALING_MODE_SCALE_TO_FIT">com.google.android.exoplayer2.Renderer.VIDEO_SCALING_MODE_SCALE_TO_FIT</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/C.html#VIDEO_SCALING_MODE_SCALE_TO_FIT"><code>C.VIDEO_SCALING_MODE_SCALE_TO_FIT</code></a>.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Renderer.html#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING">com.google.android.exoplayer2.Renderer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/C.html#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING"><code>C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING</code></a>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/RendererCapabilities.html#FORMAT_EXCEEDS_CAPABILITIES">com.google.android.exoplayer2.RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/C.html#FORMAT_EXCEEDS_CAPABILITIES"><code>C.FORMAT_EXCEEDS_CAPABILITIES</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/RendererCapabilities.html#FORMAT_HANDLED">com.google.android.exoplayer2.RendererCapabilities.FORMAT_HANDLED</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/C.html#FORMAT_HANDLED"><code>C.FORMAT_HANDLED</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/RendererCapabilities.html#FORMAT_UNSUPPORTED_DRM">com.google.android.exoplayer2.RendererCapabilities.FORMAT_UNSUPPORTED_DRM</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/C.html#FORMAT_UNSUPPORTED_DRM"><code>C.FORMAT_UNSUPPORTED_DRM</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/RendererCapabilities.html#FORMAT_UNSUPPORTED_SUBTYPE">com.google.android.exoplayer2.RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/C.html#FORMAT_UNSUPPORTED_SUBTYPE"><code>C.FORMAT_UNSUPPORTED_SUBTYPE</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/RendererCapabilities.html#FORMAT_UNSUPPORTED_TYPE">com.google.android.exoplayer2.RendererCapabilities.FORMAT_UNSUPPORTED_TYPE</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/C.html#FORMAT_UNSUPPORTED_TYPE"><code>C.FORMAT_UNSUPPORTED_TYPE</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/dash/DashMediaSource.html#DEFAULT_LIVE_PRESENTATION_DELAY_MS">com.google.android.exoplayer2.source.dash.DashMediaSource.DEFAULT_LIVE_PRESENTATION_DELAY_MS</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/dash/DashMediaSource.html#DEFAULT_FALLBACK_TARGET_LIVE_OFFSET_MS"><code>DashMediaSource.DEFAULT_FALLBACK_TARGET_LIVE_OFFSET_MS</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Timeline.Window.html#isLive">com.google.android.exoplayer2.Timeline.Window.isLive</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Timeline.Window.html#isLive()"><code>Timeline.Window.isLive()</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Timeline.Window.html#tag">com.google.android.exoplayer2.Timeline.Window.tag</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Timeline.Window.html#mediaItem"><code>Timeline.Window.mediaItem</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/trackselection/DefaultTrackSelector.Parameters.html#DEFAULT">com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters.DEFAULT</a></th>
<td class="colLast">
<div class="deprecationComment">This instance is not configured using <a href="https://developer.android.com/reference/android/content/Context.html" title="class or interface in android.content" class="externalLink"><code>Context</code></a> constraints. Use <a href="com/google/android/exoplayer2/trackselection/DefaultTrackSelector.Parameters.html#getDefaults(android.content.Context)" target="_top"><code>DefaultTrackSelector.Parameters.getDefaults(Context)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/trackselection/TrackSelectionParameters.html#DEFAULT">com.google.android.exoplayer2.trackselection.TrackSelectionParameters.DEFAULT</a></th>
<td class="colLast">
<div class="deprecationComment">This instance is not configured using <a href="https://developer.android.com/reference/android/content/Context.html" title="class or interface in android.content" class="externalLink"><code>Context</code></a> constraints. Use <a href="com/google/android/exoplayer2/trackselection/TrackSelectionParameters.html#getDefaults(android.content.Context)" target="_top"><code>TrackSelectionParameters.getDefaults(Context)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/upstream/DataSourceException.html#POSITION_OUT_OF_RANGE">com.google.android.exoplayer2.upstream.DataSourceException.POSITION_OUT_OF_RANGE</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/PlaybackException.html#ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE"><code>PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE</code></a>.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/upstream/DataSpec.html#absoluteStreamPosition">com.google.android.exoplayer2.upstream.DataSpec.absoluteStreamPosition</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/upstream/DataSpec.html#position"><code>DataSpec.position</code></a> except for specific use cases where the absolute position
@ -497,7 +503,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
position is required, use <code>uriPositionOffset + position</code>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.html#DEFAULT_TRACK_BLACKLIST_MS">com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_BLACKLIST_MS</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.html#DEFAULT_TRACK_EXCLUSION_MS"><code>DefaultLoadErrorHandlingPolicy.DEFAULT_TRACK_EXCLUSION_MS</code></a> instead.</div>
@ -886,78 +892,90 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</td>
</tr>
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#addListener(com.google.android.exoplayer2.Player.EventListener)">com.google.android.exoplayer2.ForwardingPlayer.addListener&#8203;(Player.EventListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#getCurrentStaticMetadata()">com.google.android.exoplayer2.ForwardingPlayer.getCurrentStaticMetadata()</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#hasNext()">com.google.android.exoplayer2.ForwardingPlayer.hasNext()</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#hasPrevious()">com.google.android.exoplayer2.ForwardingPlayer.hasPrevious()</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#next()">com.google.android.exoplayer2.ForwardingPlayer.next()</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#previous()">com.google.android.exoplayer2.ForwardingPlayer.previous()</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#removeListener(com.google.android.exoplayer2.Player.EventListener)">com.google.android.exoplayer2.ForwardingPlayer.removeListener&#8203;(Player.EventListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#stop(boolean)">com.google.android.exoplayer2.ForwardingPlayer.stop&#8203;(boolean)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/mediacodec/MediaCodecInfo.html#isSeamlessAdaptationSupported(com.google.android.exoplayer2.Format,com.google.android.exoplayer2.Format,boolean)">com.google.android.exoplayer2.mediacodec.MediaCodecInfo.isSeamlessAdaptationSupported&#8203;(Format, Format, boolean)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/mediacodec/MediaCodecInfo.html#canReuseCodec(com.google.android.exoplayer2.Format,com.google.android.exoplayer2.Format)"><code>MediaCodecInfo.canReuseCodec(com.google.android.exoplayer2.Format, com.google.android.exoplayer2.Format)</code></a>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/MediaMetadata.Builder.html#setArtworkData(byte%5B%5D)">com.google.android.exoplayer2.MediaMetadata.Builder.setArtworkData&#8203;(byte[])</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaMetadata.Builder.html#setArtworkData(byte%5B%5D,java.lang.Integer)"><code>MediaMetadata.Builder.setArtworkData(byte[] data, Integer pictureType)</code></a> or <a href="com/google/android/exoplayer2/MediaMetadata.Builder.html#maybeSetArtworkData(byte%5B%5D,int)"><code>MediaMetadata.Builder.maybeSetArtworkData(byte[] data, int pictureType)</code></a>, providing a <a href="com/google/android/exoplayer2/MediaMetadata.PictureType.html" title="annotation in com.google.android.exoplayer2"><code>MediaMetadata.PictureType</code></a>.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/MediaMetadata.Builder.html#setYear(java.lang.Integer)">com.google.android.exoplayer2.MediaMetadata.Builder.setYear&#8203;(Integer)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaMetadata.Builder.html#setRecordingYear(java.lang.Integer)"><code>MediaMetadata.Builder.setRecordingYear(Integer)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forDash(android.content.Context,android.net.Uri,com.google.android.exoplayer2.upstream.DataSource.Factory,com.google.android.exoplayer2.RenderersFactory)">com.google.android.exoplayer2.offline.DownloadHelper.forDash&#8203;(Context, Uri, DataSource.Factory, RenderersFactory)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forMediaItem(com.google.android.exoplayer2.MediaItem,com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters,com.google.android.exoplayer2.RenderersFactory,com.google.android.exoplayer2.upstream.DataSource.Factory)"><code>DownloadHelper.forMediaItem(MediaItem, Parameters, RenderersFactory,
DataSource.Factory)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forHls(android.content.Context,android.net.Uri,com.google.android.exoplayer2.upstream.DataSource.Factory,com.google.android.exoplayer2.RenderersFactory)">com.google.android.exoplayer2.offline.DownloadHelper.forHls&#8203;(Context, Uri, DataSource.Factory, RenderersFactory)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forMediaItem(com.google.android.exoplayer2.MediaItem,com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters,com.google.android.exoplayer2.RenderersFactory,com.google.android.exoplayer2.upstream.DataSource.Factory)"><code>DownloadHelper.forMediaItem(MediaItem, Parameters, RenderersFactory,
DataSource.Factory)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forProgressive(android.content.Context,android.net.Uri)">com.google.android.exoplayer2.offline.DownloadHelper.forProgressive&#8203;(Context, Uri)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forMediaItem(android.content.Context,com.google.android.exoplayer2.MediaItem)"><code>DownloadHelper.forMediaItem(Context, MediaItem)</code></a></div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forSmoothStreaming(android.net.Uri,com.google.android.exoplayer2.upstream.DataSource.Factory,com.google.android.exoplayer2.RenderersFactory)">com.google.android.exoplayer2.offline.DownloadHelper.forSmoothStreaming&#8203;(Uri, DataSource.Factory, RenderersFactory)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/offline/DownloadHelper.html#forMediaItem(com.google.android.exoplayer2.MediaItem,com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters,com.google.android.exoplayer2.RenderersFactory,com.google.android.exoplayer2.upstream.DataSource.Factory)"><code>DownloadHelper.forMediaItem(MediaItem, Parameters, RenderersFactory,
DataSource.Factory)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/offline/DownloadService.html#onDownloadChanged(com.google.android.exoplayer2.offline.Download)">com.google.android.exoplayer2.offline.DownloadService.onDownloadChanged&#8203;(Download)</a></th>
<td class="colLast">
<div class="deprecationComment">Some state change events may not be delivered to this method. Instead, use <a href="com/google/android/exoplayer2/offline/DownloadManager.html#addListener(com.google.android.exoplayer2.offline.DownloadManager.Listener)"><code>DownloadManager.addListener(DownloadManager.Listener)</code></a> to register a listener directly to
the <a href="com/google/android/exoplayer2/offline/DownloadManager.html" title="class in com.google.android.exoplayer2.offline"><code>DownloadManager</code></a> that you return through <a href="com/google/android/exoplayer2/offline/DownloadService.html#getDownloadManager()"><code>DownloadService.getDownloadManager()</code></a>.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/offline/DownloadService.html#onDownloadRemoved(com.google.android.exoplayer2.offline.Download)">com.google.android.exoplayer2.offline.DownloadService.onDownloadRemoved&#8203;(Download)</a></th>
<td class="colLast">
<div class="deprecationComment">Some download removal events may not be delivered to this method. Instead, use
@ -965,37 +983,37 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
directly to the <a href="com/google/android/exoplayer2/offline/DownloadManager.html" title="class in com.google.android.exoplayer2.offline"><code>DownloadManager</code></a> that you return through <a href="com/google/android/exoplayer2/offline/DownloadService.html#getDownloadManager()"><code>DownloadService.getDownloadManager()</code></a>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#addListener(com.google.android.exoplayer2.Player.EventListener)">com.google.android.exoplayer2.Player.addListener&#8203;(Player.EventListener)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#addListener(com.google.android.exoplayer2.Player.Listener)"><code>Player.addListener(Listener)</code></a> and <a href="com/google/android/exoplayer2/Player.html#removeListener(com.google.android.exoplayer2.Player.Listener)"><code>Player.removeListener(Listener)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.EventListener.html#onLoadingChanged(boolean)">com.google.android.exoplayer2.Player.EventListener.onLoadingChanged&#8203;(boolean)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.EventListener.html#onIsLoadingChanged(boolean)"><code>Player.EventListener.onIsLoadingChanged(boolean)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.EventListener.html#onPlayerStateChanged(boolean,int)">com.google.android.exoplayer2.Player.EventListener.onPlayerStateChanged&#8203;(boolean, int)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.EventListener.html#onPlaybackStateChanged(int)"><code>Player.EventListener.onPlaybackStateChanged(int)</code></a> and <a href="com/google/android/exoplayer2/Player.EventListener.html#onPlayWhenReadyChanged(boolean,int)"><code>Player.EventListener.onPlayWhenReadyChanged(boolean, int)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.EventListener.html#onPositionDiscontinuity(int)">com.google.android.exoplayer2.Player.EventListener.onPositionDiscontinuity&#8203;(int)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.EventListener.html#onPositionDiscontinuity(com.google.android.exoplayer2.Player.PositionInfo,com.google.android.exoplayer2.Player.PositionInfo,int)"><code>Player.EventListener.onPositionDiscontinuity(PositionInfo, PositionInfo, int)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.EventListener.html#onSeekProcessed()">com.google.android.exoplayer2.Player.EventListener.onSeekProcessed()</a></th>
<td class="colLast">
<div class="deprecationComment">Seeks are processed without delay. Listen to <a href="com/google/android/exoplayer2/Player.EventListener.html#onPositionDiscontinuity(com.google.android.exoplayer2.Player.PositionInfo,com.google.android.exoplayer2.Player.PositionInfo,int)"><code>Player.EventListener.onPositionDiscontinuity(PositionInfo, PositionInfo, int)</code></a> with reason <a href="com/google/android/exoplayer2/Player.html#DISCONTINUITY_REASON_SEEK"><code>Player.DISCONTINUITY_REASON_SEEK</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.EventListener.html#onStaticMetadataChanged(java.util.List)">com.google.android.exoplayer2.Player.EventListener.onStaticMetadataChanged&#8203;(List&lt;Metadata&gt;)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#getMediaMetadata()"><code>Player.getMediaMetadata()</code></a> and <a href="com/google/android/exoplayer2/Player.EventListener.html#onMediaMetadataChanged(com.google.android.exoplayer2.MediaMetadata)"><code>Player.EventListener.onMediaMetadataChanged(MediaMetadata)</code></a> for access to structured metadata, or access the
@ -1003,7 +1021,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
selections' formats</code></a>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#getCurrentStaticMetadata()">com.google.android.exoplayer2.Player.getCurrentStaticMetadata()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#getMediaMetadata()"><code>Player.getMediaMetadata()</code></a> and <a href="com/google/android/exoplayer2/Player.Listener.html#onMediaMetadataChanged(com.google.android.exoplayer2.MediaMetadata)"><code>Player.Listener.onMediaMetadataChanged(MediaMetadata)</code></a> for access to structured metadata, or
@ -1011,37 +1029,37 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
selections' formats</code></a>.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#hasNext()">com.google.android.exoplayer2.Player.hasNext()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#hasNextWindow()"><code>Player.hasNextWindow()</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#hasPrevious()">com.google.android.exoplayer2.Player.hasPrevious()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#hasPreviousWindow()"><code>Player.hasPreviousWindow()</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#next()">com.google.android.exoplayer2.Player.next()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#seekToNextWindow()"><code>Player.seekToNextWindow()</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#previous()">com.google.android.exoplayer2.Player.previous()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#seekToPreviousWindow()"><code>Player.seekToPreviousWindow()</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#removeListener(com.google.android.exoplayer2.Player.EventListener)">com.google.android.exoplayer2.Player.removeListener&#8203;(Player.EventListener)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#addListener(com.google.android.exoplayer2.Player.Listener)"><code>Player.addListener(Listener)</code></a> and <a href="com/google/android/exoplayer2/Player.html#removeListener(com.google.android.exoplayer2.Player.Listener)"><code>Player.removeListener(Listener)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/Player.html#stop(boolean)">com.google.android.exoplayer2.Player.stop&#8203;(boolean)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/Player.html#stop()"><code>Player.stop()</code></a> and <a href="com/google/android/exoplayer2/Player.html#clearMediaItems()"><code>Player.clearMediaItems()</code></a> (if <code>reset</code> is true) or
@ -1049,149 +1067,149 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<a href="com/google/android/exoplayer2/Player.html#prepare()"><code>re-preparing</code></a> the player.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/PlayerMessage.html#setHandler(android.os.Handler)">com.google.android.exoplayer2.PlayerMessage.setHandler&#8203;(Handler)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/PlayerMessage.html#setLooper(android.os.Looper)"><code>PlayerMessage.setLooper(Looper)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#addAudioListener(com.google.android.exoplayer2.audio.AudioListener)">com.google.android.exoplayer2.SimpleExoPlayer.addAudioListener&#8203;(AudioListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#addDeviceListener(com.google.android.exoplayer2.device.DeviceListener)">com.google.android.exoplayer2.SimpleExoPlayer.addDeviceListener&#8203;(DeviceListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#addListener(com.google.android.exoplayer2.Player.EventListener)">com.google.android.exoplayer2.SimpleExoPlayer.addListener&#8203;(Player.EventListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#addMetadataOutput(com.google.android.exoplayer2.metadata.MetadataOutput)">com.google.android.exoplayer2.SimpleExoPlayer.addMetadataOutput&#8203;(MetadataOutput)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#addTextOutput(com.google.android.exoplayer2.text.TextOutput)">com.google.android.exoplayer2.SimpleExoPlayer.addTextOutput&#8203;(TextOutput)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#addVideoListener(com.google.android.exoplayer2.video.VideoListener)">com.google.android.exoplayer2.SimpleExoPlayer.addVideoListener&#8203;(VideoListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#getCurrentStaticMetadata()">com.google.android.exoplayer2.SimpleExoPlayer.getCurrentStaticMetadata()</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#prepare(com.google.android.exoplayer2.source.MediaSource)">com.google.android.exoplayer2.SimpleExoPlayer.prepare&#8203;(MediaSource)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/SimpleExoPlayer.html#setMediaSource(com.google.android.exoplayer2.source.MediaSource)"><code>SimpleExoPlayer.setMediaSource(MediaSource)</code></a> and <a href="com/google/android/exoplayer2/Player.html#prepare()"><code>Player.prepare()</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#removeAudioListener(com.google.android.exoplayer2.audio.AudioListener)">com.google.android.exoplayer2.SimpleExoPlayer.removeAudioListener&#8203;(AudioListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#removeDeviceListener(com.google.android.exoplayer2.device.DeviceListener)">com.google.android.exoplayer2.SimpleExoPlayer.removeDeviceListener&#8203;(DeviceListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#removeListener(com.google.android.exoplayer2.Player.EventListener)">com.google.android.exoplayer2.SimpleExoPlayer.removeListener&#8203;(Player.EventListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#removeMetadataOutput(com.google.android.exoplayer2.metadata.MetadataOutput)">com.google.android.exoplayer2.SimpleExoPlayer.removeMetadataOutput&#8203;(MetadataOutput)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#removeTextOutput(com.google.android.exoplayer2.text.TextOutput)">com.google.android.exoplayer2.SimpleExoPlayer.removeTextOutput&#8203;(TextOutput)</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#removeVideoListener(com.google.android.exoplayer2.video.VideoListener)">com.google.android.exoplayer2.SimpleExoPlayer.removeVideoListener&#8203;(VideoListener)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#retry()">com.google.android.exoplayer2.SimpleExoPlayer.retry()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/SimpleExoPlayer.html#prepare()"><code>SimpleExoPlayer.prepare()</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#setHandleWakeLock(boolean)">com.google.android.exoplayer2.SimpleExoPlayer.setHandleWakeLock&#8203;(boolean)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/SimpleExoPlayer.html#setWakeMode(int)"><code>SimpleExoPlayer.setWakeMode(int)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#setThrowsWhenUsingWrongThread(boolean)">com.google.android.exoplayer2.SimpleExoPlayer.setThrowsWhenUsingWrongThread&#8203;(boolean)</a></th>
<td class="colLast">
<div class="deprecationComment">Disabling the enforcement can result in hard-to-detect bugs. Do not use this method
except to ease the transition while wrong thread access problems are fixed.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/SimpleExoPlayer.html#stop(boolean)">com.google.android.exoplayer2.SimpleExoPlayer.stop&#8203;(boolean)</a></th>
<td class="colLast"></td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#createMediaSource(android.net.Uri)">com.google.android.exoplayer2.source.dash.DashMediaSource.Factory.createMediaSource&#8203;(Uri)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>DashMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#setLivePresentationDelayMs(long,boolean)">com.google.android.exoplayer2.source.dash.DashMediaSource.Factory.setLivePresentationDelayMs&#8203;(long, boolean)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setLiveTargetOffsetMs(long)"><code>MediaItem.Builder.setLiveTargetOffsetMs(long)</code></a> to override the
manifest, or <a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#setFallbackTargetLiveOffsetMs(long)"><code>DashMediaSource.Factory.setFallbackTargetLiveOffsetMs(long)</code></a> to provide a fallback value.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#setStreamKeys(java.util.List)">com.google.android.exoplayer2.source.dash.DashMediaSource.Factory.setStreamKeys&#8203;(List&lt;StreamKey&gt;)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setStreamKeys(java.util.List)"><code>MediaItem.Builder.setStreamKeys(List)</code></a> and <a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>DashMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#setTag(java.lang.Object)">com.google.android.exoplayer2.source.dash.DashMediaSource.Factory.setTag&#8203;(Object)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setTag(java.lang.Object)"><code>MediaItem.Builder.setTag(Object)</code></a> and <a href="com/google/android/exoplayer2/source/dash/DashMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>DashMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/DefaultMediaSourceFactory.html#setStreamKeys(java.util.List)">com.google.android.exoplayer2.source.DefaultMediaSourceFactory.setStreamKeys&#8203;(List&lt;StreamKey&gt;)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setStreamKeys(java.util.List)"><code>MediaItem.Builder.setStreamKeys(List)</code></a> and <a href="com/google/android/exoplayer2/source/DefaultMediaSourceFactory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>DefaultMediaSourceFactory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/hls/HlsMediaSource.Factory.html#createMediaSource(android.net.Uri)">com.google.android.exoplayer2.source.hls.HlsMediaSource.Factory.createMediaSource&#8203;(Uri)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/hls/HlsMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>HlsMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/hls/HlsMediaSource.Factory.html#setStreamKeys(java.util.List)">com.google.android.exoplayer2.source.hls.HlsMediaSource.Factory.setStreamKeys&#8203;(List&lt;StreamKey&gt;)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setStreamKeys(java.util.List)"><code>MediaItem.Builder.setStreamKeys(List)</code></a> and <a href="com/google/android/exoplayer2/source/hls/HlsMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>HlsMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/hls/HlsMediaSource.Factory.html#setTag(java.lang.Object)">com.google.android.exoplayer2.source.hls.HlsMediaSource.Factory.setTag&#8203;(Object)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setTag(java.lang.Object)"><code>MediaItem.Builder.setTag(Object)</code></a> and <a href="com/google/android/exoplayer2/source/hls/HlsMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>HlsMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#createMediaSource(android.net.Uri)">com.google.android.exoplayer2.source.MediaSourceFactory.createMediaSource&#8203;(Uri)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>MediaSourceFactory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#setDrmHttpDataSourceFactory(com.google.android.exoplayer2.upstream.HttpDataSource.Factory)">com.google.android.exoplayer2.source.MediaSourceFactory.setDrmHttpDataSourceFactory&#8203;(HttpDataSource.Factory)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#setDrmSessionManagerProvider(com.google.android.exoplayer2.drm.DrmSessionManagerProvider)"><code>MediaSourceFactory.setDrmSessionManagerProvider(DrmSessionManagerProvider)</code></a> and pass an
@ -1199,14 +1217,14 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<a href="com/google/android/exoplayer2/upstream/HttpDataSource.Factory.html" title="interface in com.google.android.exoplayer2.upstream"><code>HttpDataSource.Factory</code></a>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#setDrmSessionManager(com.google.android.exoplayer2.drm.DrmSessionManager)">com.google.android.exoplayer2.source.MediaSourceFactory.setDrmSessionManager&#8203;(DrmSessionManager)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#setDrmSessionManagerProvider(com.google.android.exoplayer2.drm.DrmSessionManagerProvider)"><code>MediaSourceFactory.setDrmSessionManagerProvider(DrmSessionManagerProvider)</code></a> and pass an
implementation that always returns the same instance.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#setDrmUserAgent(java.lang.String)">com.google.android.exoplayer2.source.MediaSourceFactory.setDrmUserAgent&#8203;(String)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#setDrmSessionManagerProvider(com.google.android.exoplayer2.drm.DrmSessionManagerProvider)"><code>MediaSourceFactory.setDrmSessionManagerProvider(DrmSessionManagerProvider)</code></a> and pass an
@ -1214,25 +1232,25 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<code>userAgent</code>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/MediaSourceFactory.html#setStreamKeys(java.util.List)">com.google.android.exoplayer2.source.MediaSourceFactory.setStreamKeys&#8203;(List&lt;StreamKey&gt;)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.PlaybackProperties.html#streamKeys"><code>MediaItem.PlaybackProperties.streamKeys</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#createMediaSource(android.net.Uri)">com.google.android.exoplayer2.source.ProgressiveMediaSource.Factory.createMediaSource&#8203;(Uri)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>ProgressiveMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#setCustomCacheKey(java.lang.String)">com.google.android.exoplayer2.source.ProgressiveMediaSource.Factory.setCustomCacheKey&#8203;(String)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setCustomCacheKey(java.lang.String)"><code>MediaItem.Builder.setCustomCacheKey(String)</code></a> and <a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>ProgressiveMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#setExtractorsFactory(com.google.android.exoplayer2.extractor.ExtractorsFactory)">com.google.android.exoplayer2.source.ProgressiveMediaSource.Factory.setExtractorsFactory&#8203;(ExtractorsFactory)</a></th>
<td class="colLast">
<div class="deprecationComment">Pass the <a href="com/google/android/exoplayer2/extractor/ExtractorsFactory.html" title="interface in com.google.android.exoplayer2.extractor"><code>ExtractorsFactory</code></a> via <a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#%3Cinit%3E(com.google.android.exoplayer2.upstream.DataSource.Factory,com.google.android.exoplayer2.extractor.ExtractorsFactory)"><code>Factory(DataSource.Factory,
@ -1240,71 +1258,71 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
factory as unused.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#setTag(java.lang.Object)">com.google.android.exoplayer2.source.ProgressiveMediaSource.Factory.setTag&#8203;(Object)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setTag(java.lang.Object)"><code>MediaItem.Builder.setTag(Object)</code></a> and <a href="com/google/android/exoplayer2/source/ProgressiveMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>ProgressiveMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/rtsp/RtspMediaSource.Factory.html#setDrmHttpDataSourceFactory(com.google.android.exoplayer2.upstream.HttpDataSource.Factory)">com.google.android.exoplayer2.source.rtsp.RtspMediaSource.Factory.setDrmHttpDataSourceFactory&#8203;(HttpDataSource.Factory)</a></th>
<td class="colLast">
<div class="deprecationComment"><a href="com/google/android/exoplayer2/source/rtsp/RtspMediaSource.html" title="class in com.google.android.exoplayer2.source.rtsp"><code>RtspMediaSource</code></a> does not support DRM.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/rtsp/RtspMediaSource.Factory.html#setDrmSessionManager(com.google.android.exoplayer2.drm.DrmSessionManager)">com.google.android.exoplayer2.source.rtsp.RtspMediaSource.Factory.setDrmSessionManager&#8203;(DrmSessionManager)</a></th>
<td class="colLast">
<div class="deprecationComment"><a href="com/google/android/exoplayer2/source/rtsp/RtspMediaSource.html" title="class in com.google.android.exoplayer2.source.rtsp"><code>RtspMediaSource</code></a> does not support DRM.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/rtsp/RtspMediaSource.Factory.html#setDrmUserAgent(java.lang.String)">com.google.android.exoplayer2.source.rtsp.RtspMediaSource.Factory.setDrmUserAgent&#8203;(String)</a></th>
<td class="colLast">
<div class="deprecationComment"><a href="com/google/android/exoplayer2/source/rtsp/RtspMediaSource.html" title="class in com.google.android.exoplayer2.source.rtsp"><code>RtspMediaSource</code></a> does not support DRM.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/SingleSampleMediaSource.Factory.html#createMediaSource(android.net.Uri,com.google.android.exoplayer2.Format,long)">com.google.android.exoplayer2.source.SingleSampleMediaSource.Factory.createMediaSource&#8203;(Uri, Format, long)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/SingleSampleMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem.Subtitle,long)"><code>SingleSampleMediaSource.Factory.createMediaSource(MediaItem.Subtitle, long)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html#createMediaSource(android.net.Uri)">com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource.Factory.createMediaSource&#8203;(Uri)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>SsMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html#setStreamKeys(java.util.List)">com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource.Factory.setStreamKeys&#8203;(List&lt;StreamKey&gt;)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setStreamKeys(java.util.List)"><code>MediaItem.Builder.setStreamKeys(List)</code></a> and <a href="com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>SsMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html#setTag(java.lang.Object)">com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource.Factory.setTag&#8203;(Object)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/MediaItem.Builder.html#setTag(java.lang.Object)"><code>MediaItem.Builder.setTag(Object)</code></a> and <a href="com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.Factory.html#createMediaSource(com.google.android.exoplayer2.MediaItem)"><code>SsMediaSource.Factory.createMediaSource(MediaItem)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/testutil/StubExoPlayer.html#getCurrentStaticMetadata()">com.google.android.exoplayer2.testutil.StubExoPlayer.getCurrentStaticMetadata()</a></th>
<td class="colLast"></td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/testutil/StubExoPlayer.html#prepare()">com.google.android.exoplayer2.testutil.StubExoPlayer.prepare()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/testutil/StubExoPlayer.html#setMediaSource(com.google.android.exoplayer2.source.MediaSource)"><code>StubExoPlayer.setMediaSource(MediaSource)</code></a> and <a href="com/google/android/exoplayer2/Player.html#prepare()"><code>Player.prepare()</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/testutil/StubExoPlayer.html#retry()">com.google.android.exoplayer2.testutil.StubExoPlayer.retry()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/testutil/StubExoPlayer.html#prepare()"><code>StubExoPlayer.prepare()</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ui/PlayerControlView.html#setControlDispatcher(com.google.android.exoplayer2.ControlDispatcher)">com.google.android.exoplayer2.ui.PlayerControlView.setControlDispatcher&#8203;(ControlDispatcher)</a></th>
<td class="colLast">
<div class="deprecationComment">Use a <a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2"><code>ForwardingPlayer</code></a> and pass it to <a href="com/google/android/exoplayer2/ui/PlayerControlView.html#setPlayer(com.google.android.exoplayer2.Player)"><code>PlayerControlView.setPlayer(Player)</code></a> instead.
@ -1312,7 +1330,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<a href="com/google/android/exoplayer2/SimpleExoPlayer.Builder.html#setSeekBackIncrementMs(long)"><code>SimpleExoPlayer.Builder.setSeekBackIncrementMs(long)</code></a>).</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.html#setControlDispatcher(com.google.android.exoplayer2.ControlDispatcher)">com.google.android.exoplayer2.ui.PlayerNotificationManager.setControlDispatcher&#8203;(ControlDispatcher)</a></th>
<td class="colLast">
<div class="deprecationComment">Use a <a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2"><code>ForwardingPlayer</code></a> and pass it to <a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.html#setPlayer(com.google.android.exoplayer2.Player)"><code>PlayerNotificationManager.setPlayer(Player)</code></a> instead.
@ -1322,7 +1340,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
and <a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.html#setUseFastForwardAction(boolean)"><code>PlayerNotificationManager.setUseFastForwardAction(boolean)</code></a>.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ui/PlayerView.html#setControlDispatcher(com.google.android.exoplayer2.ControlDispatcher)">com.google.android.exoplayer2.ui.PlayerView.setControlDispatcher&#8203;(ControlDispatcher)</a></th>
<td class="colLast">
<div class="deprecationComment">Use a <a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2"><code>ForwardingPlayer</code></a> and pass it to <a href="com/google/android/exoplayer2/ui/PlayerView.html#setPlayer(com.google.android.exoplayer2.Player)"><code>PlayerView.setPlayer(Player)</code></a> instead.
@ -1330,7 +1348,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<a href="com/google/android/exoplayer2/SimpleExoPlayer.Builder.html#setSeekBackIncrementMs(long)"><code>SimpleExoPlayer.Builder.setSeekBackIncrementMs(long)</code></a>).</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ui/StyledPlayerControlView.html#setControlDispatcher(com.google.android.exoplayer2.ControlDispatcher)">com.google.android.exoplayer2.ui.StyledPlayerControlView.setControlDispatcher&#8203;(ControlDispatcher)</a></th>
<td class="colLast">
<div class="deprecationComment">Use a <a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2"><code>ForwardingPlayer</code></a> and pass it to <a href="com/google/android/exoplayer2/ui/StyledPlayerControlView.html#setPlayer(com.google.android.exoplayer2.Player)"><code>StyledPlayerControlView.setPlayer(Player)</code></a> instead.
@ -1338,7 +1356,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<a href="com/google/android/exoplayer2/SimpleExoPlayer.Builder.html#setSeekBackIncrementMs(long)"><code>SimpleExoPlayer.Builder.setSeekBackIncrementMs(long)</code></a>).</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/ui/StyledPlayerView.html#setControlDispatcher(com.google.android.exoplayer2.ControlDispatcher)">com.google.android.exoplayer2.ui.StyledPlayerView.setControlDispatcher&#8203;(ControlDispatcher)</a></th>
<td class="colLast">
<div class="deprecationComment">Use a <a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2"><code>ForwardingPlayer</code></a> and pass it to <a href="com/google/android/exoplayer2/ui/StyledPlayerView.html#setPlayer(com.google.android.exoplayer2.Player)"><code>StyledPlayerView.setPlayer(Player)</code></a> instead.
@ -1346,44 +1364,44 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<a href="com/google/android/exoplayer2/SimpleExoPlayer.Builder.html#setSeekBackIncrementMs(long)"><code>SimpleExoPlayer.Builder.setSeekBackIncrementMs(long)</code></a>).</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/upstream/DefaultHttpDataSource.Factory.html#getDefaultRequestProperties()">com.google.android.exoplayer2.upstream.DefaultHttpDataSource.Factory.getDefaultRequestProperties()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/upstream/DefaultHttpDataSource.Factory.html#setDefaultRequestProperties(java.util.Map)"><code>DefaultHttpDataSource.Factory.setDefaultRequestProperties(Map)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/upstream/DefaultHttpDataSource.html#setContentTypePredicate(com.google.common.base.Predicate)">com.google.android.exoplayer2.upstream.DefaultHttpDataSource.setContentTypePredicate&#8203;(Predicate&lt;String&gt;)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/upstream/DefaultHttpDataSource.Factory.html#setContentTypePredicate(com.google.common.base.Predicate)"><code>DefaultHttpDataSource.Factory.setContentTypePredicate(Predicate)</code></a>
instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/upstream/HttpDataSource.BaseFactory.html#getDefaultRequestProperties()">com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory.getDefaultRequestProperties()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/upstream/HttpDataSource.BaseFactory.html#setDefaultRequestProperties(java.util.Map)"><code>HttpDataSource.BaseFactory.setDefaultRequestProperties(Map)</code></a> instead.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/upstream/HttpDataSource.Factory.html#getDefaultRequestProperties()">com.google.android.exoplayer2.upstream.HttpDataSource.Factory.getDefaultRequestProperties()</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/upstream/HttpDataSource.Factory.html#setDefaultRequestProperties(java.util.Map)"><code>HttpDataSource.Factory.setDefaultRequestProperties(Map)</code></a> instead.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/video/VideoDecoderGLSurfaceView.html#getVideoDecoderOutputBufferRenderer()">com.google.android.exoplayer2.video.VideoDecoderGLSurfaceView.getVideoDecoderOutputBufferRenderer()</a></th>
<td class="colLast">
<div class="deprecationComment">This class implements <a href="com/google/android/exoplayer2/video/VideoDecoderOutputBufferRenderer.html" title="interface in com.google.android.exoplayer2.video"><code>VideoDecoderOutputBufferRenderer</code></a> directly.</div>
</td>
</tr>
<tr class="altColor">
<tr class="rowColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/video/VideoListener.html#onVideoSizeChanged(int,int,int,float)">com.google.android.exoplayer2.video.VideoListener.onVideoSizeChanged&#8203;(int, int, int, float)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/video/VideoListener.html#onVideoSizeChanged(com.google.android.exoplayer2.video.VideoSize)"><code>VideoListener.onVideoSizeChanged(VideoSize videoSize)</code></a>.</div>
</td>
</tr>
<tr class="rowColor">
<tr class="altColor">
<th class="colDeprecatedItemName" scope="row"><a href="com/google/android/exoplayer2/video/VideoRendererEventListener.html#onVideoInputFormatChanged(com.google.android.exoplayer2.Format)">com.google.android.exoplayer2.video.VideoRendererEventListener.onVideoInputFormatChanged&#8203;(Format)</a></th>
<td class="colLast">
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/video/VideoRendererEventListener.html#onVideoInputFormatChanged(com.google.android.exoplayer2.Format,com.google.android.exoplayer2.decoder.DecoderReuseEvaluation)"><code>VideoRendererEventListener.onVideoInputFormatChanged(Format, DecoderReuseEvaluation)</code></a>.</div>

View File

@ -761,7 +761,9 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html#addListener(com.google.android.exoplayer2.Player.EventListener)">addListener(Player.EventListener)</a></span> - Method in class com.google.android.exoplayer2.ext.cast.<a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html" title="class in com.google.android.exoplayer2.ext.cast">CastPlayer</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#addListener(com.google.android.exoplayer2.Player.EventListener)">addListener(Player.EventListener)</a></span> - Method in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2">ForwardingPlayer</a></dt>
<dd>&nbsp;</dd>
<dd>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span></div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/Player.html#addListener(com.google.android.exoplayer2.Player.EventListener)">addListener(Player.EventListener)</a></span> - Method in interface com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/Player.html" title="interface in com.google.android.exoplayer2">Player</a></dt>
<dd>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
@ -2240,7 +2242,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html" title="class in com.google.android.exoplayer2.source.dash"><span class="typeNameLink">BaseUrlExclusionList</span></a> - Class in <a href="com/google/android/exoplayer2/source/dash/package-summary.html">com.google.android.exoplayer2.source.dash</a></dt>
<dd>
<div class="block">Holds the state of <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#selectBaseUrl(java.util.List)"><code>to select</code></a> a base URL based on these exclusions.</div>
<div class="block">Holds the state of <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#exclude(com.google.android.exoplayer2.source.dash.manifest.BaseUrl,long)"><code>excluded</code></a> base URLs to be used to <a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#selectBaseUrl(java.util.List)"><code>select</code></a> a base URL based on these exclusions.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html#%3Cinit%3E()">BaseUrlExclusionList()</a></span> - Constructor for class com.google.android.exoplayer2.source.dash.<a href="com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.html" title="class in com.google.android.exoplayer2.source.dash">BaseUrlExclusionList</a></dt>
<dd>
@ -2728,7 +2730,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Builds a <a href="com/google/android/exoplayer2/upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream"><code>DataSpec</code></a> for a given <a href="com/google/android/exoplayer2/source/dash/manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>RangedUri</code></a> belonging to <a href="com/google/android/exoplayer2/source/dash/manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a>.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/dash/DashUtil.html#buildDataSpec(java.lang.String,com.google.android.exoplayer2.source.dash.manifest.RangedUri,java.lang.String,int)">buildDataSpec(String, RangedUri, String, int)</a></span> - Static method in class com.google.android.exoplayer2.source.dash.<a href="com/google/android/exoplayer2/source/dash/DashUtil.html" title="class in com.google.android.exoplayer2.source.dash">DashUtil</a></dt>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/dash/DashUtil.html#buildDataSpec(com.google.android.exoplayer2.source.dash.manifest.Representation,java.lang.String,com.google.android.exoplayer2.source.dash.manifest.RangedUri,int)">buildDataSpec(Representation, String, RangedUri, int)</a></span> - Static method in class com.google.android.exoplayer2.source.dash.<a href="com/google/android/exoplayer2/source/dash/DashUtil.html" title="class in com.google.android.exoplayer2.source.dash">DashUtil</a></dt>
<dd>
<div class="block">Builds a <a href="com/google/android/exoplayer2/upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream"><code>DataSpec</code></a> for a given <a href="com/google/android/exoplayer2/source/dash/manifest/RangedUri.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>RangedUri</code></a> belonging to <a href="com/google/android/exoplayer2/source/dash/manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a>.</div>
</dd>
@ -3715,6 +3717,14 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">The number of audio channels, or <a href="com/google/android/exoplayer2/Format.html#NO_VALUE"><code>Format.NO_VALUE</code></a> if unknown or not applicable.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#channelDescriptionResourceId">channelDescriptionResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#channelId">channelId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#channelImportance">channelImportance</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#channelNameResourceId">channelNameResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/audio/MpegAudioUtil.Header.html#channels">channels</a></span> - Variable in class com.google.android.exoplayer2.audio.<a href="com/google/android/exoplayer2/audio/MpegAudioUtil.Header.html" title="class in com.google.android.exoplayer2.audio">MpegAudioUtil.Header</a></dt>
<dd>
<div class="block">Number of audio channels in the frame.</div>
@ -5126,6 +5136,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/upstream/HttpDataSource.InvalidContentTypeException.html#contentType">contentType</a></span> - Variable in exception com.google.android.exoplayer2.upstream.<a href="com/google/android/exoplayer2/upstream/HttpDataSource.InvalidContentTypeException.html" title="class in com.google.android.exoplayer2.upstream">HttpDataSource.InvalidContentTypeException</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#context">context</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html#continueLoading(long)">continueLoading(long)</a></span> - Method in class com.google.android.exoplayer2.source.chunk.<a href="com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html" title="class in com.google.android.exoplayer2.source.chunk">ChunkSampleStream</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/ClippingMediaPeriod.html#continueLoading(long)">continueLoading(long)</a></span> - Method in class com.google.android.exoplayer2.source.<a href="com/google/android/exoplayer2/source/ClippingMediaPeriod.html" title="class in com.google.android.exoplayer2.source">ClippingMediaPeriod</a></dt>
@ -6640,6 +6652,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<div class="block">Player implementations that want to surface custom errors can use error codes greater than this
value, so as to avoid collision with other error codes defined in this class.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#customActionReceiver">customActionReceiver</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/MediaItem.PlaybackProperties.html#customCacheKey">customCacheKey</a></span> - Variable in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/MediaItem.PlaybackProperties.html" title="class in com.google.android.exoplayer2">MediaItem.PlaybackProperties</a></dt>
<dd>
<div class="block">Optional custom cache key (only used for progressive streams).</div>
@ -7015,9 +7029,9 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html#dataSpecWithPositionAndLength_readExpectedRange()">dataSpecWithPositionAndLength_readExpectedRange()</a></span> - Method in class com.google.android.exoplayer2.testutil.<a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html" title="class in com.google.android.exoplayer2.testutil">DataSourceContractTest</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html#dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException()">dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException()</a></span> - Method in class com.google.android.exoplayer2.testutil.<a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html" title="class in com.google.android.exoplayer2.testutil">DataSourceContractTest</a></dt>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html#dataSpecWithPositionAtEnd_readsZeroBytes()">dataSpecWithPositionAtEnd_readsZeroBytes()</a></span> - Method in class com.google.android.exoplayer2.testutil.<a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html" title="class in com.google.android.exoplayer2.testutil">DataSourceContractTest</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html#dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException()">dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException()</a></span> - Method in class com.google.android.exoplayer2.testutil.<a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html" title="class in com.google.android.exoplayer2.testutil">DataSourceContractTest</a></dt>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html#dataSpecWithPositionAtEndAndLength_readsZeroBytes()">dataSpecWithPositionAtEndAndLength_readsZeroBytes()</a></span> - Method in class com.google.android.exoplayer2.testutil.<a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html" title="class in com.google.android.exoplayer2.testutil">DataSourceContractTest</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html#dataSpecWithPositionOutOfRange_throwsPositionOutOfRangeException()">dataSpecWithPositionOutOfRange_throwsPositionOutOfRangeException()</a></span> - Method in class com.google.android.exoplayer2.testutil.<a href="com/google/android/exoplayer2/testutil/DataSourceContractTest.html" title="class in com.google.android.exoplayer2.testutil">DataSourceContractTest</a></dt>
<dd>&nbsp;</dd>
@ -11777,6 +11791,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Creates an instance.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#fastForwardActionIconResourceId">fastForwardActionIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/analytics/PlaybackStats.html#fatalErrorCount">fatalErrorCount</a></span> - Variable in class com.google.android.exoplayer2.analytics.<a href="com/google/android/exoplayer2/analytics/PlaybackStats.html" title="class in com.google.android.exoplayer2.analytics">PlaybackStats</a></dt>
<dd>
<div class="block">The total number of fatal errors.</div>
@ -15762,7 +15778,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/Timeline.html#getPeriodPosition(com.google.android.exoplayer2.Timeline.Window,com.google.android.exoplayer2.Timeline.Period,int,long,long)">getPeriodPosition(Timeline.Window, Timeline.Period, int, long, long)</a></span> - Method in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/Timeline.html" title="class in com.google.android.exoplayer2">Timeline</a></dt>
<dd>
<div class="block">Converts (windowIndex, windowPositionUs) to the corresponding (periodUid, periodPositionUs).</div>
<div class="block">Converts <code>(windowIndex, windowPositionUs)</code> to the corresponding <code>(periodUid,
periodPositionUs)</code>.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/Format.html#getPixelCount()">getPixelCount()</a></span> - Method in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/Format.html" title="class in com.google.android.exoplayer2">Format</a></dt>
<dd>
@ -17474,6 +17491,10 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Returns the <a href="com/google/android/exoplayer2/Format.html" title="class in com.google.android.exoplayer2"><code>Format</code></a> that can be used to decode the wrapped metadata in <a href="com/google/android/exoplayer2/metadata/Metadata.Entry.html#getWrappedMetadataBytes()"><code>Metadata.Entry.getWrappedMetadataBytes()</code></a>, or null if this Entry doesn't contain wrapped metadata.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#getWrappedPlayer()">getWrappedPlayer()</a></span> - Method in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2">ForwardingPlayer</a></dt>
<dd>
<div class="block">Returns the <a href="com/google/android/exoplayer2/Player.html" title="interface in com.google.android.exoplayer2"><code>Player</code></a> to which operations are forwarded.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/database/DatabaseProvider.html#getWritableDatabase()">getWritableDatabase()</a></span> - Method in interface com.google.android.exoplayer2.database.<a href="com/google/android/exoplayer2/database/DatabaseProvider.html" title="interface in com.google.android.exoplayer2.database">DatabaseProvider</a></dt>
<dd>
<div class="block">Creates and/or opens a database that will be used for reading and writing.</div>
@ -17532,6 +17553,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/trackselection/DefaultTrackSelector.SelectionOverride.html#groupIndex">groupIndex</a></span> - Variable in class com.google.android.exoplayer2.trackselection.<a href="com/google/android/exoplayer2/trackselection/DefaultTrackSelector.SelectionOverride.html" title="class in com.google.android.exoplayer2.trackselection">DefaultTrackSelector.SelectionOverride</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#groupKey">groupKey</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><a href="com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.html" title="class in com.google.android.exoplayer2.ext.gvr"><span class="typeNameLink">GvrAudioProcessor</span></a> - Class in <a href="com/google/android/exoplayer2/ext/gvr/package-summary.html">com.google.android.exoplayer2.ext.gvr</a></dt>
<dd>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
@ -20868,6 +20891,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/rtsp/RtpPacket.html#MAX_SIZE">MAX_SIZE</a></span> - Static variable in class com.google.android.exoplayer2.source.rtsp.<a href="com/google/android/exoplayer2/source/rtsp/RtpPacket.html" title="class in com.google.android.exoplayer2.source.rtsp">RtpPacket</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html#MAX_SPEED_SUPPORTED">MAX_SPEED_SUPPORTED</a></span> - Static variable in class com.google.android.exoplayer2.ext.cast.<a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html" title="class in com.google.android.exoplayer2.ext.cast">CastPlayer</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/mediacodec/MediaCodecInfo.html#MAX_SUPPORTED_INSTANCES_UNKNOWN">MAX_SUPPORTED_INSTANCES_UNKNOWN</a></span> - Static variable in class com.google.android.exoplayer2.mediacodec.<a href="com/google/android/exoplayer2/mediacodec/MediaCodecInfo.html" title="class in com.google.android.exoplayer2.mediacodec">MediaCodecInfo</a></dt>
<dd>
<div class="block">The value returned by <a href="com/google/android/exoplayer2/mediacodec/MediaCodecInfo.html#getMaxSupportedInstances()"><code>MediaCodecInfo.getMaxSupportedInstances()</code></a> if the upper bound on the maximum
@ -21259,6 +21284,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>&nbsp;</dd>
<dt><a href="com/google/android/exoplayer2/video/MediaCodecVideoRenderer.CodecMaxValues.html" title="class in com.google.android.exoplayer2.video"><span class="typeNameLink">MediaCodecVideoRenderer.CodecMaxValues</span></a> - Class in <a href="com/google/android/exoplayer2/video/package-summary.html">com.google.android.exoplayer2.video</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#mediaDescriptionAdapter">mediaDescriptionAdapter</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><a href="com/google/android/exoplayer2/drm/MediaDrmCallback.html" title="interface in com.google.android.exoplayer2.drm"><span class="typeNameLink">MediaDrmCallback</span></a> - Interface in <a href="com/google/android/exoplayer2/drm/package-summary.html">com.google.android.exoplayer2.drm</a></dt>
<dd>
<div class="block">Performs <a href="com/google/android/exoplayer2/drm/ExoMediaDrm.html" title="interface in com.google.android.exoplayer2.drm"><code>ExoMediaDrm</code></a> key and provisioning requests.</div>
@ -21802,6 +21829,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/rtsp/RtpPacket.html#MIN_SEQUENCE_NUMBER">MIN_SEQUENCE_NUMBER</a></span> - Static variable in class com.google.android.exoplayer2.source.rtsp.<a href="com/google/android/exoplayer2/source/rtsp/RtpPacket.html" title="class in com.google.android.exoplayer2.source.rtsp">RtpPacket</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html#MIN_SPEED_SUPPORTED">MIN_SPEED_SUPPORTED</a></span> - Static variable in class com.google.android.exoplayer2.ext.cast.<a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html" title="class in com.google.android.exoplayer2.ext.cast">CastPlayer</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/extractor/FlacStreamMetadata.html#minBlockSizeSamples">minBlockSizeSamples</a></span> - Variable in class com.google.android.exoplayer2.extractor.<a href="com/google/android/exoplayer2/extractor/FlacStreamMetadata.html" title="class in com.google.android.exoplayer2.extractor">FlacStreamMetadata</a></dt>
<dd>
<div class="block">Minimum number of samples per block.</div>
@ -22421,6 +22450,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Parameters for seeking to the sync point immediately after a requested seek position.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#nextActionIconResourceId">nextActionIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/MediaPeriodId.html#nextAdGroupIndex">nextAdGroupIndex</a></span> - Variable in class com.google.android.exoplayer2.source.<a href="com/google/android/exoplayer2/source/MediaPeriodId.html" title="class in com.google.android.exoplayer2.source">MediaPeriodId</a></dt>
<dd>
<div class="block">The index of the next ad group to which the media period's content is clipped, or <a href="com/google/android/exoplayer2/C.html#INDEX_UNSET"><code>C.INDEX_UNSET</code></a> if there is no following ad group or if this media period is an ad.</div>
@ -22490,6 +22521,10 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/audio/AudioProcessor.AudioFormat.html#NOT_SET">NOT_SET</a></span> - Static variable in class com.google.android.exoplayer2.audio.<a href="com/google/android/exoplayer2/audio/AudioProcessor.AudioFormat.html" title="class in com.google.android.exoplayer2.audio">AudioProcessor.AudioFormat</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#notificationId">notificationId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#notificationListener">notificationListener</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><a href="com/google/android/exoplayer2/util/NotificationUtil.html" title="class in com.google.android.exoplayer2.util"><span class="typeNameLink">NotificationUtil</span></a> - Class in <a href="com/google/android/exoplayer2/util/package-summary.html">com.google.android.exoplayer2.util</a></dt>
<dd>
<div class="block">Utility methods for displaying <a href="https://developer.android.com/reference/android/app/Notification.html" title="class or interface in android.app" class="externalLink" target="_top"><code>Notifications</code></a>.</div>
@ -25688,6 +25723,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Schedules a pause action.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#pauseActionIconResourceId">pauseActionIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/offline/DownloadManager.html#pauseDownloads()">pauseDownloads()</a></span> - Method in class com.google.android.exoplayer2.offline.<a href="com/google/android/exoplayer2/offline/DownloadManager.html" title="class in com.google.android.exoplayer2.offline">DownloadManager</a></dt>
<dd>
<div class="block">Pauses downloads.</div>
@ -26003,6 +26040,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Playback has been started or paused by a call to <a href="com/google/android/exoplayer2/Player.html#setPlayWhenReady(boolean)"><code>Player.setPlayWhenReady(boolean)</code></a>.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#playActionIconResourceId">playActionIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/analytics/PlaybackStats.html#PLAYBACK_STATE_ABANDONED">PLAYBACK_STATE_ABANDONED</a></span> - Static variable in class com.google.android.exoplayer2.analytics.<a href="com/google/android/exoplayer2/analytics/PlaybackStats.html" title="class in com.google.android.exoplayer2.analytics">PlaybackStats</a></dt>
<dd>
<div class="block">Playback is abandoned before reaching the end of the media.</div>
@ -26313,6 +26352,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Starts, updates and cancels a media style notification reflecting the player state.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.html#%3Cinit%3E(android.content.Context,java.lang.String,int,com.google.android.exoplayer2.ui.PlayerNotificationManager.MediaDescriptionAdapter,com.google.android.exoplayer2.ui.PlayerNotificationManager.NotificationListener,com.google.android.exoplayer2.ui.PlayerNotificationManager.CustomActionReceiver,int,int,int,int,int,int,int,int,java.lang.String)">PlayerNotificationManager(Context, String, int, PlayerNotificationManager.MediaDescriptionAdapter, PlayerNotificationManager.NotificationListener, PlayerNotificationManager.CustomActionReceiver, int, int, int, int, int, int, int, int, String)</a></span> - Constructor for class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager</a></dt>
<dd>&nbsp;</dd>
<dt><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.BitmapCallback.html" title="class in com.google.android.exoplayer2.ui"><span class="typeNameLink">PlayerNotificationManager.BitmapCallback</span></a> - Class in <a href="com/google/android/exoplayer2/ui/package-summary.html">com.google.android.exoplayer2.ui</a></dt>
<dd>
<div class="block">Receives a <a href="https://developer.android.com/reference/android/graphics/Bitmap.html" title="class or interface in android.graphics" class="externalLink" target="_top"><code>Bitmap</code></a>.</div>
@ -26785,6 +26826,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Parameters for seeking to the sync point immediately before a requested seek position.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#previousActionIconResourceId">previousActionIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html#primaryTrackType">primaryTrackType</a></span> - Variable in class com.google.android.exoplayer2.source.chunk.<a href="com/google/android/exoplayer2/source/chunk/ChunkSampleStream.html" title="class in com.google.android.exoplayer2.source.chunk">ChunkSampleStream</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/dash/manifest/BaseUrl.html#priority">priority</a></span> - Variable in class com.google.android.exoplayer2.source.dash.manifest.<a href="com/google/android/exoplayer2/source/dash/manifest/BaseUrl.html" title="class in com.google.android.exoplayer2.source.dash.manifest">BaseUrl</a></dt>
@ -28366,7 +28409,9 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html#removeListener(com.google.android.exoplayer2.Player.EventListener)">removeListener(Player.EventListener)</a></span> - Method in class com.google.android.exoplayer2.ext.cast.<a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html" title="class in com.google.android.exoplayer2.ext.cast">CastPlayer</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#removeListener(com.google.android.exoplayer2.Player.EventListener)">removeListener(Player.EventListener)</a></span> - Method in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2">ForwardingPlayer</a></dt>
<dd>&nbsp;</dd>
<dd>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span></div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/Player.html#removeListener(com.google.android.exoplayer2.Player.EventListener)">removeListener(Player.EventListener)</a></span> - Method in interface com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/Player.html" title="interface in com.google.android.exoplayer2">Player</a></dt>
<dd>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
@ -28889,7 +28934,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/audio/AudioSink.html#reset()">reset()</a></span> - Method in interface com.google.android.exoplayer2.audio.<a href="com/google/android/exoplayer2/audio/AudioSink.html" title="interface in com.google.android.exoplayer2.audio">AudioSink</a></dt>
<dd>
<div class="block">Resets the renderer, releasing any resources that it currently holds.</div>
<div class="block">Resets the sink, releasing any resources that it currently holds.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/audio/BaseAudioProcessor.html#reset()">reset()</a></span> - Method in class com.google.android.exoplayer2.audio.<a href="com/google/android/exoplayer2/audio/BaseAudioProcessor.html" title="class in com.google.android.exoplayer2.audio">BaseAudioProcessor</a></dt>
<dd>&nbsp;</dd>
@ -29068,6 +29113,10 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Performs relative resolution of a <code>referenceUri</code> with respect to a <code>baseUri</code>.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/source/dash/DashUtil.html#resolveCacheKey(com.google.android.exoplayer2.source.dash.manifest.Representation,com.google.android.exoplayer2.source.dash.manifest.RangedUri)">resolveCacheKey(Representation, RangedUri)</a></span> - Static method in class com.google.android.exoplayer2.source.dash.<a href="com/google/android/exoplayer2/source/dash/DashUtil.html" title="class in com.google.android.exoplayer2.source.dash">DashUtil</a></dt>
<dd>
<div class="block">Resolves the cache key to be used when requesting the given ranged URI for the given <a href="com/google/android/exoplayer2/source/dash/manifest/Representation.html" title="class in com.google.android.exoplayer2.source.dash.manifest"><code>Representation</code></a>.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/upstream/ResolvingDataSource.Resolver.html#resolveDataSpec(com.google.android.exoplayer2.upstream.DataSpec)">resolveDataSpec(DataSpec)</a></span> - Method in interface com.google.android.exoplayer2.upstream.<a href="com/google/android/exoplayer2/upstream/ResolvingDataSource.Resolver.html" title="interface in com.google.android.exoplayer2.upstream">ResolvingDataSource.Resolver</a></dt>
<dd>
<div class="block">Resolves a <a href="com/google/android/exoplayer2/upstream/DataSpec.html" title="class in com.google.android.exoplayer2.upstream"><code>DataSpec</code></a> before forwarding it to the wrapped <a href="com/google/android/exoplayer2/upstream/DataSource.html" title="interface in com.google.android.exoplayer2.upstream"><code>DataSource</code></a>.</div>
@ -29270,6 +29319,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Identifies the revision of the media contained within the representation.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#rewindActionIconResourceId">rewindActionIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/audio/WavUtil.html#RIFF_FOURCC">RIFF_FOURCC</a></span> - Static variable in class com.google.android.exoplayer2.audio.<a href="com/google/android/exoplayer2/audio/WavUtil.html" title="class in com.google.android.exoplayer2.audio">WavUtil</a></dt>
<dd>
<div class="block">Four character code for "RIFF".</div>
@ -35058,6 +35109,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">Holds information about a single segment of slow motion playback within a track.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#smallIconResourceId">smallIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><a href="com/google/android/exoplayer2/metadata/mp4/SmtaMetadataEntry.html" title="class in com.google.android.exoplayer2.metadata.mp4"><span class="typeNameLink">SmtaMetadataEntry</span></a> - Class in <a href="com/google/android/exoplayer2/metadata/mp4/package-summary.html">com.google.android.exoplayer2.metadata.mp4</a></dt>
<dd>
<div class="block">Stores metadata from the Samsung smta box.</div>
@ -35551,7 +35604,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/Player.html#STATE_BUFFERING">STATE_BUFFERING</a></span> - Static variable in interface com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/Player.html" title="interface in com.google.android.exoplayer2">Player</a></dt>
<dd>
<div class="block">The player is not able to immediately play from its current position.</div>
<div class="block">The player is not able to immediately play the media, but is doing work toward being able to do
so.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/offline/Download.html#STATE_COMPLETED">STATE_COMPLETED</a></span> - Static variable in class com.google.android.exoplayer2.offline.<a href="com/google/android/exoplayer2/offline/Download.html" title="class in com.google.android.exoplayer2.offline">Download</a></dt>
<dd>
@ -35583,7 +35637,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/Player.html#STATE_IDLE">STATE_IDLE</a></span> - Static variable in interface com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/Player.html" title="interface in com.google.android.exoplayer2">Player</a></dt>
<dd>
<div class="block">The player does not have any media to play.</div>
<div class="block">The player is idle, and must be <a href="com/google/android/exoplayer2/Player.html#prepare()"><code>prepared</code></a> before it will play the media.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/drm/DrmSession.html#STATE_OPENED">STATE_OPENED</a></span> - Static variable in interface com.google.android.exoplayer2.drm.<a href="com/google/android/exoplayer2/drm/DrmSession.html" title="interface in com.google.android.exoplayer2.drm">DrmSession</a></dt>
<dd>
@ -35700,7 +35754,9 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html#stop(boolean)">stop(boolean)</a></span> - Method in class com.google.android.exoplayer2.ext.cast.<a href="com/google/android/exoplayer2/ext/cast/CastPlayer.html" title="class in com.google.android.exoplayer2.ext.cast">CastPlayer</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ForwardingPlayer.html#stop(boolean)">stop(boolean)</a></span> - Method in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/ForwardingPlayer.html" title="class in com.google.android.exoplayer2">ForwardingPlayer</a></dt>
<dd>&nbsp;</dd>
<dd>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span></div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/Player.html#stop(boolean)">stop(boolean)</a></span> - Method in interface com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/Player.html" title="interface in com.google.android.exoplayer2">Player</a></dt>
<dd>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
@ -35737,6 +35793,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">The download isn't stopped.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html#stopActionIconResourceId">stopActionIconResourceId</a></span> - Variable in class com.google.android.exoplayer2.ui.<a href="com/google/android/exoplayer2/ui/PlayerNotificationManager.Builder.html" title="class in com.google.android.exoplayer2.ui">PlayerNotificationManager.Builder</a></dt>
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/offline/Download.html#stopReason">stopReason</a></span> - Variable in class com.google.android.exoplayer2.offline.<a href="com/google/android/exoplayer2/offline/Download.html" title="class in com.google.android.exoplayer2.offline">Download</a></dt>
<dd>
<div class="block">The reason the download is stopped, or <a href="com/google/android/exoplayer2/offline/Download.html#STOP_REASON_NONE"><code>Download.STOP_REASON_NONE</code></a>.</div>
@ -35789,14 +35847,22 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>
<div class="block">The contained stream elements.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/offline/StreamKey.html#streamIndex">streamIndex</a></span> - Variable in class com.google.android.exoplayer2.offline.<a href="com/google/android/exoplayer2/offline/StreamKey.html" title="class in com.google.android.exoplayer2.offline">StreamKey</a></dt>
<dd>
<div class="block">The stream index.</div>
</dd>
<dt><a href="com/google/android/exoplayer2/offline/StreamKey.html" title="class in com.google.android.exoplayer2.offline"><span class="typeNameLink">StreamKey</span></a> - Class in <a href="com/google/android/exoplayer2/offline/package-summary.html">com.google.android.exoplayer2.offline</a></dt>
<dd>
<div class="block">A key for a subset of media which can be separately loaded (a "stream").</div>
<div class="block">A key for a subset of media that can be separately loaded (a "stream").</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/offline/StreamKey.html#%3Cinit%3E(int,int)">StreamKey(int, int)</a></span> - Constructor for class com.google.android.exoplayer2.offline.<a href="com/google/android/exoplayer2/offline/StreamKey.html" title="class in com.google.android.exoplayer2.offline">StreamKey</a></dt>
<dd>&nbsp;</dd>
<dd>
<div class="block">Creates an instance with <a href="com/google/android/exoplayer2/offline/StreamKey.html#periodIndex"><code>StreamKey.periodIndex</code></a> set to 0.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/offline/StreamKey.html#%3Cinit%3E(int,int,int)">StreamKey(int, int, int)</a></span> - Constructor for class com.google.android.exoplayer2.offline.<a href="com/google/android/exoplayer2/offline/StreamKey.html" title="class in com.google.android.exoplayer2.offline">StreamKey</a></dt>
<dd>&nbsp;</dd>
<dd>
<div class="block">Creates an instance.</div>
</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/MediaItem.PlaybackProperties.html#streamKeys">streamKeys</a></span> - Variable in class com.google.android.exoplayer2.<a href="com/google/android/exoplayer2/MediaItem.PlaybackProperties.html" title="class in com.google.android.exoplayer2">MediaItem.PlaybackProperties</a></dt>
<dd>
<div class="block">Optional stream keys by which the manifest is filtered.</div>
@ -37010,7 +37076,9 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
<dd>&nbsp;</dd>
<dt><span class="memberNameLink"><a href="com/google/android/exoplayer2/offline/StreamKey.html#trackIndex">trackIndex</a></span> - Variable in class com.google.android.exoplayer2.offline.<a href="com/google/android/exoplayer2/offline/StreamKey.html" title="class in com.google.android.exoplayer2.offline">StreamKey</a></dt>
<dd>
<div class="block">The track index.</div>
<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
<div class="deprecationComment">Use <a href="com/google/android/exoplayer2/offline/StreamKey.html#streamIndex"><code>StreamKey.streamIndex</code></a>.</div>
</div>
</dd>
<dt><a href="com/google/android/exoplayer2/ui/TrackNameProvider.html" title="interface in com.google.android.exoplayer2.ui"><span class="typeNameLink">TrackNameProvider</span></a> - Interface in <a href="com/google/android/exoplayer2/ui/package-summary.html">com.google.android.exoplayer2.ui</a></dt>
<dd>

File diff suppressed because one or more lines are too long

View File

@ -95,6 +95,7 @@ public final class CastPlayer extends BasePlayer {
COMMAND_SEEK_TO_DEFAULT_POSITION,
COMMAND_SEEK_TO_WINDOW,
COMMAND_SET_REPEAT_MODE,
COMMAND_SET_SPEED_AND_PITCH,
COMMAND_GET_CURRENT_MEDIA_ITEM,
COMMAND_GET_TIMELINE,
COMMAND_GET_MEDIA_ITEMS_METADATA,
@ -102,6 +103,9 @@ public final class CastPlayer extends BasePlayer {
COMMAND_CHANGE_MEDIA_ITEMS)
.build();
public static final float MIN_SPEED_SUPPORTED = 0.5f;
public static final float MAX_SPEED_SUPPORTED = 2.0f;
private static final String TAG = "CastPlayer";
private static final int RENDERER_COUNT = 3;
@ -132,6 +136,7 @@ public final class CastPlayer extends BasePlayer {
// Internal state.
private final StateHolder<Boolean> playWhenReady;
private final StateHolder<Integer> repeatMode;
private final StateHolder<PlaybackParameters> playbackParameters;
@Nullable private RemoteMediaClient remoteMediaClient;
private CastTimeline currentTimeline;
private TrackGroupArray currentTrackGroups;
@ -208,6 +213,7 @@ public final class CastPlayer extends BasePlayer {
(listener, flags) -> listener.onEvents(/* player= */ this, new Events(flags)));
playWhenReady = new StateHolder<>(false);
repeatMode = new StateHolder<>(REPEAT_MODE_OFF);
playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT);
playbackState = STATE_IDLE;
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
currentTrackGroups = TrackGroupArray.EMPTY;
@ -463,14 +469,9 @@ public final class CastPlayer extends BasePlayer {
return C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS;
}
@Override
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
// Unsupported by the RemoteMediaClient API. Do nothing.
}
@Override
public PlaybackParameters getPlaybackParameters() {
return PlaybackParameters.DEFAULT;
return playbackParameters.value;
}
@Override
@ -489,6 +490,32 @@ public final class CastPlayer extends BasePlayer {
sessionManager.endCurrentSession(false);
}
@Override
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
if (remoteMediaClient == null) {
return;
}
PlaybackParameters actualPlaybackParameters =
new PlaybackParameters(
Util.constrainValue(
playbackParameters.speed, MIN_SPEED_SUPPORTED, MAX_SPEED_SUPPORTED));
setPlaybackParametersAndNotifyIfChanged(actualPlaybackParameters);
listeners.flushEvents();
PendingResult<MediaChannelResult> pendingResult =
remoteMediaClient.setPlaybackRate(actualPlaybackParameters.speed, /* customData= */ null);
this.playbackParameters.pendingResultCallback =
new ResultCallback<MediaChannelResult>() {
@Override
public void onResult(MediaChannelResult mediaChannelResult) {
if (remoteMediaClient != null) {
updatePlaybackRateAndNotifyIfChanged(this);
listeners.flushEvents();
}
}
};
pendingResult.setResultCallback(this.playbackParameters.pendingResultCallback);
}
@Override
public void setRepeatMode(@RepeatMode int repeatMode) {
if (remoteMediaClient == null) {
@ -761,6 +788,7 @@ public final class CastPlayer extends BasePlayer {
Player.EVENT_IS_PLAYING_CHANGED, listener -> listener.onIsPlayingChanged(isPlaying));
}
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
updatePlaybackRateAndNotifyIfChanged(/* resultCallback= */ null);
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
Timeline currentTimeline = getCurrentTimeline();
currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
@ -844,6 +872,22 @@ public final class CastPlayer extends BasePlayer {
newPlayWhenReadyValue, playWhenReadyChangeReason, fetchPlaybackState(remoteMediaClient));
}
@RequiresNonNull("remoteMediaClient")
private void updatePlaybackRateAndNotifyIfChanged(@Nullable ResultCallback<?> resultCallback) {
if (playbackParameters.acceptsUpdate(resultCallback)) {
@Nullable MediaStatus mediaStatus = remoteMediaClient.getMediaStatus();
float speed =
mediaStatus != null
? (float) mediaStatus.getPlaybackRate()
: PlaybackParameters.DEFAULT.speed;
if (speed > 0.0f) {
// Set the speed if not paused.
setPlaybackParametersAndNotifyIfChanged(new PlaybackParameters(speed));
}
playbackParameters.clearPendingResultCallback();
}
}
@RequiresNonNull("remoteMediaClient")
private void updateRepeatModeAndNotifyIfChanged(@Nullable ResultCallback<?> resultCallback) {
if (repeatMode.acceptsUpdate(resultCallback)) {
@ -1100,6 +1144,17 @@ public final class CastPlayer extends BasePlayer {
}
}
private void setPlaybackParametersAndNotifyIfChanged(PlaybackParameters playbackParameters) {
if (this.playbackParameters.value.equals(playbackParameters)) {
return;
}
this.playbackParameters.value = playbackParameters;
listeners.queueEvent(
Player.EVENT_PLAYBACK_PARAMETERS_CHANGED,
listener -> listener.onPlaybackParametersChanged(playbackParameters));
updateAvailableCommandsAndNotifyIfChanged();
}
@SuppressWarnings("deprecation")
private void setPlayerStateAndNotifyIfChanged(
boolean playWhenReady,

View File

@ -61,6 +61,7 @@ import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.util.Assertions;
@ -126,6 +127,7 @@ public class CastPlayerTest {
// Make the remote media client present the same default values as ExoPlayer:
when(mockRemoteMediaClient.isPaused()).thenReturn(true);
when(mockMediaStatus.getQueueRepeatMode()).thenReturn(MediaStatus.REPEAT_MODE_REPEAT_OFF);
when(mockMediaStatus.getPlaybackRate()).thenReturn(1.0d);
castPlayer = new CastPlayer(mockCastContext);
castPlayer.addListener(mockListener);
verify(mockRemoteMediaClient).registerCallback(callbackArgumentCaptor.capture());
@ -208,6 +210,93 @@ public class CastPlayerTest {
assertThat(castPlayer.getPlayWhenReady()).isTrue();
}
@Test
public void playbackParameters_defaultPlaybackSpeed_isUnitSpeed() {
assertThat(castPlayer.getPlaybackParameters()).isEqualTo(PlaybackParameters.DEFAULT);
}
@Test
public void playbackParameters_onStatusUpdated_setsRemotePlaybackSpeed() {
PlaybackParameters expectedPlaybackParameters = new PlaybackParameters(/* speed= */ 1.234f);
when(mockMediaStatus.getPlaybackRate()).thenReturn(1.234d);
remoteMediaClientCallback.onStatusUpdated();
assertThat(castPlayer.getPlaybackParameters()).isEqualTo(expectedPlaybackParameters);
verify(mockListener).onPlaybackParametersChanged(expectedPlaybackParameters);
}
@Test
public void playbackParameters_onStatusUpdated_ignoreInPausedState() {
when(mockMediaStatus.getPlaybackRate()).thenReturn(0.0d);
remoteMediaClientCallback.onStatusUpdated();
assertThat(castPlayer.getPlaybackParameters()).isEqualTo(PlaybackParameters.DEFAULT);
verifyNoMoreInteractions(mockListener);
}
@Test
public void setPlaybackParameters_speedOutOfRange_valueIsConstraintToMinAndMax() {
when(mockRemoteMediaClient.setPlaybackRate(eq(2d), any())).thenReturn(mockPendingResult);
when(mockRemoteMediaClient.setPlaybackRate(eq(0.5d), any())).thenReturn(mockPendingResult);
PlaybackParameters expectedMaxValuePlaybackParameters = new PlaybackParameters(/* speed= */ 2f);
PlaybackParameters expectedMinValuePlaybackParameters =
new PlaybackParameters(/* speed= */ 0.5f);
castPlayer.setPlaybackParameters(new PlaybackParameters(/* speed= */ 2.001f));
verify(mockListener).onPlaybackParametersChanged(expectedMaxValuePlaybackParameters);
castPlayer.setPlaybackParameters(new PlaybackParameters(/* speed= */ 0.499f));
verify(mockListener).onPlaybackParametersChanged(expectedMinValuePlaybackParameters);
}
@Test
public void setPlaybackParameters_masksPendingState() {
PlaybackParameters playbackParameters = new PlaybackParameters(/* speed= */ 1.234f);
when(mockRemoteMediaClient.setPlaybackRate(eq((double) 1.234f), any()))
.thenReturn(mockPendingResult);
castPlayer.setPlaybackParameters(playbackParameters);
verify(mockPendingResult).setResultCallback(setResultCallbackArgumentCaptor.capture());
assertThat(castPlayer.getPlaybackParameters().speed).isEqualTo(1.234f);
verify(mockListener).onPlaybackParametersChanged(playbackParameters);
// Simulate a status update while the update is pending that must not override the masked speed.
when(mockMediaStatus.getPlaybackRate()).thenReturn(99.0d);
remoteMediaClientCallback.onStatusUpdated();
assertThat(castPlayer.getPlaybackParameters().speed).isEqualTo(1.234f);
// Call the captured result callback when the device responds. The listener must not be called.
when(mockMediaStatus.getPlaybackRate()).thenReturn(1.234d);
setResultCallbackArgumentCaptor
.getValue()
.onResult(mock(RemoteMediaClient.MediaChannelResult.class));
assertThat(castPlayer.getPlaybackParameters().speed).isEqualTo(1.234f);
verifyNoMoreInteractions(mockListener);
}
@Test
public void setPlaybackParameters_speedChangeNotSupported_resetOnResultCallback() {
when(mockRemoteMediaClient.setPlaybackRate(eq((double) 1.234f), any()))
.thenReturn(mockPendingResult);
PlaybackParameters playbackParameters = new PlaybackParameters(/* speed= */ 1.234f);
// Change the playback speed and and capture the result callback.
castPlayer.setPlaybackParameters(playbackParameters);
verify(mockPendingResult).setResultCallback(setResultCallbackArgumentCaptor.capture());
verify(mockListener).onPlaybackParametersChanged(new PlaybackParameters(/* speed= */ 1.234f));
// The device does not support speed changes and returns unit speed to the result callback.
when(mockMediaStatus.getPlaybackRate()).thenReturn(1.0d);
setResultCallbackArgumentCaptor
.getValue()
.onResult(mock(RemoteMediaClient.MediaChannelResult.class));
assertThat(castPlayer.getPlaybackParameters()).isEqualTo(PlaybackParameters.DEFAULT);
verify(mockListener).onPlaybackParametersChanged(PlaybackParameters.DEFAULT);
verifyNoMoreInteractions(mockListener);
}
@Test
public void setRepeatMode_masksRemoteState() {
when(mockRemoteMediaClient.queueSetRepeatMode(anyInt(), any())).thenReturn(mockPendingResult);
@ -1215,7 +1304,7 @@ public class CastPlayerTest {
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_TO_WINDOW)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_BACK)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_FORWARD)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_SPEED_AND_PITCH)).isFalse();
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_SPEED_AND_PITCH)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_SHUFFLE_MODE)).isFalse();
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_REPEAT_MODE)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)).isTrue();

View File

@ -26,11 +26,11 @@ public final class ExoPlayerLibraryInfo {
/** The version of the library expressed as a string, for example "1.2.3". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public static final String VERSION = "2.15.0";
public static final String VERSION = "2.15.1";
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final String VERSION_SLASHY = "ExoPlayerLib/2.15.0";
public static final String VERSION_SLASHY = "ExoPlayerLib/2.15.1";
/**
* The version of the library expressed as an integer, for example 1002003.
@ -40,7 +40,7 @@ public final class ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final int VERSION_INT = 2015000;
public static final int VERSION_INT = 2015001;
/**
* The default user agent for requests made by the library.

View File

@ -48,8 +48,8 @@ public class ForwardingPlayer implements Player {
return player.getApplicationLooper();
}
@Deprecated
@Override
@SuppressWarnings("deprecation") // Implementing deprecated method.
public void addListener(EventListener listener) {
player.addListener(new ForwardingEventListener(this, listener));
}
@ -59,8 +59,8 @@ public class ForwardingPlayer implements Player {
player.addListener(new ForwardingListener(this, listener));
}
@Deprecated
@Override
@SuppressWarnings("deprecation") // Implementing deprecated method.
public void removeListener(EventListener listener) {
player.removeListener(new ForwardingEventListener(this, listener));
}
@ -346,8 +346,8 @@ public class ForwardingPlayer implements Player {
player.stop();
}
@Deprecated
@Override
@SuppressWarnings("deprecation") // Forwarding to deprecated method.
public void stop(boolean reset) {
player.stop(reset);
}
@ -615,6 +615,11 @@ public class ForwardingPlayer implements Player {
player.setDeviceMuted(muted);
}
/** Returns the {@link Player} to which operations are forwarded. */
public Player getWrappedPlayer() {
return player;
}
@SuppressWarnings("deprecation") // Use of deprecated type for backwards compatibility.
private static class ForwardingEventListener implements EventListener {

View File

@ -988,11 +988,12 @@ public interface Player {
@Retention(RetentionPolicy.SOURCE)
@IntDef({STATE_IDLE, STATE_BUFFERING, STATE_READY, STATE_ENDED})
@interface State {}
/** The player does not have any media to play. */
/** The player is idle, and must be {@link #prepare() prepared} before it will play the media. */
int STATE_IDLE = 1;
/**
* The player is not able to immediately play from its current position. This state typically
* occurs when more data needs to be loaded.
* The player is not able to immediately play the media, but is doing work toward being able to do
* so. This state typically occurs when the player needs to buffer more data before playback can
* start.
*/
int STATE_BUFFERING = 2;
/**

View File

@ -17,6 +17,8 @@ package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.max;
import static java.lang.Math.min;
import android.net.Uri;
import android.os.Bundle;
@ -28,6 +30,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.BundleUtil;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
@ -1156,7 +1159,9 @@ public abstract class Timeline implements Bundleable {
}
/**
* Converts (windowIndex, windowPositionUs) to the corresponding (periodUid, periodPositionUs).
* Converts {@code (windowIndex, windowPositionUs)} to the corresponding {@code (periodUid,
* periodPositionUs)}. The returned {@code periodPositionUs} is constrained to be non-negative,
* and to be less than the containing period's duration if it is known.
*
* @param window A {@link Window} that may be overwritten.
* @param period A {@link Period} that may be overwritten.
@ -1193,6 +1198,15 @@ public abstract class Timeline implements Bundleable {
}
getPeriod(periodIndex, period, /* setIds= */ true);
long periodPositionUs = windowPositionUs - period.positionInWindowUs;
// The period positions must be less than the period duration, if it is known.
if (period.durationUs != C.TIME_UNSET) {
periodPositionUs = min(periodPositionUs, period.durationUs - 1);
}
// Period positions cannot be negative.
periodPositionUs = max(0, periodPositionUs);
if (periodPositionUs == 9) {
Log.e("XXX", "YYY");
}
return Pair.create(Assertions.checkNotNull(period.uid), periodPositionUs);
}

View File

@ -806,9 +806,9 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
return terminationPos;
}
// Otherwise ensure an even index and look for a second zero byte.
// Otherwise ensure an even offset from the start, and look for a second zero byte.
while (terminationPos < data.length - 1) {
if (terminationPos % 2 == 0 && data[terminationPos + 1] == (byte) 0) {
if ((terminationPos - fromIndex) % 2 == 0 && data[terminationPos + 1] == (byte) 0) {
return terminationPos;
}
terminationPos = indexOfZeroByte(data, terminationPos + 1);

View File

@ -20,11 +20,18 @@ import android.os.Parcelable;
import androidx.annotation.Nullable;
/**
* A key for a subset of media which can be separately loaded (a "stream").
* A key for a subset of media that can be separately loaded (a "stream").
*
* <p>The stream key consists of a period index, a group index within the period and a track index
* <p>The stream key consists of a period index, a group index within the period and a stream index
* within the group. The interpretation of these indices depends on the type of media for which the
* stream key is used.
* stream key is used. Note that they are <em>not</em> the same as track group and track indices,
* because multiple tracks can be multiplexed into a single stream.
*
* <p>Application code should not generally attempt to build StreamKey instances directly. Instead,
* {@code DownloadHelper.getDownloadRequest} can be used to generate download requests with the
* correct StreamKeys for the track selections that have been configured on the helper. {@code
* MediaPeriod.getStreamKeys} provides a lower level way of generating StreamKeys corresponding to a
* particular track selection.
*/
public final class StreamKey implements Comparable<StreamKey>, Parcelable {
@ -32,37 +39,48 @@ public final class StreamKey implements Comparable<StreamKey>, Parcelable {
public final int periodIndex;
/** The group index. */
public final int groupIndex;
/** The track index. */
public final int trackIndex;
/** The stream index. */
public final int streamIndex;
/** @deprecated Use {@link #streamIndex}. */
@Deprecated public final int trackIndex;
/**
* Creates an instance with {@link #periodIndex} set to 0.
*
* @param groupIndex The group index.
* @param trackIndex The track index.
* @param streamIndex The stream index.
*/
public StreamKey(int groupIndex, int trackIndex) {
this(0, groupIndex, trackIndex);
public StreamKey(int groupIndex, int streamIndex) {
this(0, groupIndex, streamIndex);
}
/**
* Creates an instance.
*
* @param periodIndex The period index.
* @param groupIndex The group index.
* @param trackIndex The track index.
* @param streamIndex The stream index.
*/
public StreamKey(int periodIndex, int groupIndex, int trackIndex) {
@SuppressWarnings("deprecation")
public StreamKey(int periodIndex, int groupIndex, int streamIndex) {
this.periodIndex = periodIndex;
this.groupIndex = groupIndex;
this.trackIndex = trackIndex;
this.streamIndex = streamIndex;
trackIndex = streamIndex;
}
@SuppressWarnings("deprecation")
/* package */ StreamKey(Parcel in) {
periodIndex = in.readInt();
groupIndex = in.readInt();
trackIndex = in.readInt();
streamIndex = in.readInt();
trackIndex = streamIndex;
}
@Override
public String toString() {
return periodIndex + "." + groupIndex + "." + trackIndex;
return periodIndex + "." + groupIndex + "." + streamIndex;
}
@Override
@ -77,14 +95,14 @@ public final class StreamKey implements Comparable<StreamKey>, Parcelable {
StreamKey that = (StreamKey) o;
return periodIndex == that.periodIndex
&& groupIndex == that.groupIndex
&& trackIndex == that.trackIndex;
&& streamIndex == that.streamIndex;
}
@Override
public int hashCode() {
int result = periodIndex;
result = 31 * result + groupIndex;
result = 31 * result + trackIndex;
result = 31 * result + streamIndex;
return result;
}
@ -96,7 +114,7 @@ public final class StreamKey implements Comparable<StreamKey>, Parcelable {
if (result == 0) {
result = groupIndex - o.groupIndex;
if (result == 0) {
result = trackIndex - o.trackIndex;
result = streamIndex - o.streamIndex;
}
}
return result;
@ -113,7 +131,7 @@ public final class StreamKey implements Comparable<StreamKey>, Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(periodIndex);
dest.writeInt(groupIndex);
dest.writeInt(trackIndex);
dest.writeInt(streamIndex);
}
public static final Parcelable.Creator<StreamKey> CREATOR =

View File

@ -211,11 +211,33 @@ public final class FlagSet {
return false;
}
FlagSet that = (FlagSet) o;
if (Util.SDK_INT < 24) {
// SparseBooleanArray.equals() is not implemented on API levels below 24.
if (size() != that.size()) {
return false;
}
for (int i = 0; i < size(); i++) {
if (get(i) != that.get(i)) {
return false;
}
}
return true;
} else {
return flags.equals(that.flags);
}
}
@Override
public int hashCode() {
if (Util.SDK_INT < 24) {
// SparseBooleanArray.hashCode() is not implemented on API levels below 24.
int hashCode = size();
for (int i = 0; i < size(); i++) {
hashCode = 31 * hashCode + get(i);
}
return hashCode;
} else {
return flags.hashCode();
}
}
}

View File

@ -2280,21 +2280,20 @@ public final class Util {
* @return The size of the current mode, in pixels.
*/
public static Point getCurrentDisplayModeSize(Context context, Display display) {
if (Util.SDK_INT <= 29 && display.getDisplayId() == Display.DEFAULT_DISPLAY && isTv(context)) {
// On Android TVs it is common for the UI to be configured for a lower resolution than
// SurfaceViews can output. Before API 26 the Display object does not provide a way to
// identify this case, and up to and including API 28 many devices still do not correctly set
// their hardware compositor output size.
// Sony Android TVs advertise support for 4k output via a system feature.
if ("Sony".equals(Util.MANUFACTURER)
&& Util.MODEL.startsWith("BRAVIA")
&& context.getPackageManager().hasSystemFeature("com.sony.dtv.hardware.panel.qfhd")) {
return new Point(3840, 2160);
}
// Otherwise check the system property for display size. From API 28 treble may prevent the
// system from writing sys.display-size so we check vendor.display-size instead.
if (display.getDisplayId() == Display.DEFAULT_DISPLAY && isTv(context)) {
// On Android TVs it's common for the UI to be driven at a lower resolution than the physical
// resolution of the display (e.g., driving the UI at 1080p when the display is 4K).
// SurfaceView outputs are still able to use the full physical resolution on such devices.
//
// Prior to API level 26, the Display object did not provide a way to obtain the true physical
// resolution of the display. From API level 26, Display.getMode().getPhysical[Width|Height]
// is expected to return the display's true physical resolution, but we still see devices
// setting their hardware compositor output size incorrectly, which makes this unreliable.
// Hence for TV devices, we try and read the display's true physical resolution from system
// properties.
//
// From API level 28, Treble may prevent the system from writing sys.display-size, so we check
// vendor.display-size instead.
@Nullable
String displaySize =
Util.SDK_INT < 28
@ -2316,6 +2315,13 @@ public final class Util {
}
Log.e(TAG, "Invalid display size: " + displaySize);
}
// Sony Android TVs advertise support for 4k output via a system feature.
if ("Sony".equals(Util.MANUFACTURER)
&& Util.MODEL.startsWith("BRAVIA")
&& context.getPackageManager().hasSystemFeature("com.sony.dtv.hardware.panel.qfhd")) {
return new Point(3840, 2160);
}
}
Point displaySize = new Point();

View File

@ -38,6 +38,7 @@ public final class Id3DecoderTest {
@Test
public void decodeTxxxFrame() {
// Test UTF-8.
byte[] rawId3 =
buildSingleFrameTag(
"TXXX",
@ -53,6 +54,21 @@ public final class Id3DecoderTest {
assertThat(textInformationFrame.description).isEmpty();
assertThat(textInformationFrame.value).isEqualTo("mdialog_VINDICO1527664_start");
// Test UTF-16.
rawId3 =
buildSingleFrameTag(
"TXXX",
new byte[] {
1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0,
100, 0, 0
});
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.id).isEqualTo("TXXX");
assertThat(textInformationFrame.description).isEqualTo("Hello World");
assertThat(textInformationFrame.value).isEmpty();
// Test empty.
rawId3 = buildSingleFrameTag("TXXX", new byte[0]);
metadata = decoder.decode(rawId3, rawId3.length);
@ -220,6 +236,43 @@ public final class Id3DecoderTest {
assertThat(apicFrame.description).isEqualTo("Hello World");
assertThat(apicFrame.pictureData).hasLength(10);
assertThat(apicFrame.pictureData).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0});
// Test with UTF-16 description at even offset.
rawId3 =
buildSingleFrameTag(
"APIC",
new byte[] {
1, 105, 109, 97, 103, 101, 47, 106, 112, 101, 103, 0, 16, 0, 72, 0, 101, 0, 108, 0,
108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 0
});
decoder = new Id3Decoder();
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
apicFrame = (ApicFrame) metadata.get(0);
assertThat(apicFrame.mimeType).isEqualTo("image/jpeg");
assertThat(apicFrame.pictureType).isEqualTo(16);
assertThat(apicFrame.description).isEqualTo("Hello World");
assertThat(apicFrame.pictureData).hasLength(10);
assertThat(apicFrame.pictureData).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0});
// Test with UTF-16 description at odd offset.
rawId3 =
buildSingleFrameTag(
"APIC",
new byte[] {
1, 105, 109, 97, 103, 101, 47, 112, 110, 103, 0, 16, 0, 72, 0, 101, 0, 108, 0, 108, 0,
111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
});
decoder = new Id3Decoder();
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
apicFrame = (ApicFrame) metadata.get(0);
assertThat(apicFrame.mimeType).isEqualTo("image/png");
assertThat(apicFrame.pictureType).isEqualTo(16);
assertThat(apicFrame.description).isEqualTo("Hello World");
assertThat(apicFrame.pictureData).hasLength(10);
assertThat(apicFrame.pictureData).isEqualTo(new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0});
}
@Test

View File

@ -1273,18 +1273,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (!newPlayingPeriodHolder.prepared) {
newPlayingPeriodHolder.info =
newPlayingPeriodHolder.info.copyWithStartPositionUs(periodPositionUs);
} else {
if (newPlayingPeriodHolder.info.durationUs != C.TIME_UNSET
&& periodPositionUs >= newPlayingPeriodHolder.info.durationUs) {
// Make sure seek position doesn't exceed period duration.
periodPositionUs = max(0, newPlayingPeriodHolder.info.durationUs - 1);
}
if (newPlayingPeriodHolder.hasEnabledTracks) {
} else if (newPlayingPeriodHolder.hasEnabledTracks) {
periodPositionUs = newPlayingPeriodHolder.mediaPeriod.seekToUs(periodPositionUs);
newPlayingPeriodHolder.mediaPeriod.discardBuffer(
periodPositionUs - backBufferDurationUs, retainBackBufferFromKeyframe);
}
}
resetRendererPosition(periodPositionUs);
maybeContinueLoading();
} else {

View File

@ -769,10 +769,12 @@ public final class PlaybackStatsListener
}
}
}
mediaTimeHistory.add(
mediaTimeMs == C.TIME_UNSET
? guessMediaTimeBasedOnElapsedRealtime(realtimeMs)
: new long[] {realtimeMs, mediaTimeMs});
if (mediaTimeMs != C.TIME_UNSET) {
mediaTimeHistory.add(new long[] {realtimeMs, mediaTimeMs});
} else if (!mediaTimeHistory.isEmpty()) {
mediaTimeHistory.add(guessMediaTimeBasedOnElapsedRealtime(realtimeMs));
}
}
private long[] guessMediaTimeBasedOnElapsedRealtime(long realtimeMs) {

View File

@ -446,6 +446,6 @@ public interface AudioSink {
*/
void experimentalFlushWithoutAudioTrackRelease();
/** Resets the renderer, releasing any resources that it currently holds. */
/** Resets the sink, releasing any resources that it currently holds. */
void reset();
}

View File

@ -687,13 +687,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
// If we're short on DRM session resources, first try eagerly releasing all our keepalive
// sessions and then retry the acquisition.
if (acquisitionFailedIndicatingResourceShortage(session) && !keepaliveSessions.isEmpty()) {
// Make a local copy, because sessions are removed from this.keepaliveSessions during
// release (via callback).
ImmutableSet<DefaultDrmSession> keepaliveSessions =
ImmutableSet.copyOf(this.keepaliveSessions);
for (DrmSession keepaliveSession : keepaliveSessions) {
keepaliveSession.release(/* eventDispatcher= */ null);
}
releaseAllKeepaliveSessions();
undoAcquisition(session, eventDispatcher);
session = createAndAcquireSession(schemeDatas, isPlaceholderSession, eventDispatcher);
}
@ -705,6 +699,11 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
&& shouldReleasePreacquiredSessionsBeforeRetrying
&& !preacquiredSessionReferences.isEmpty()) {
releaseAllPreacquiredSessions();
if (!keepaliveSessions.isEmpty()) {
// Some preacquired sessions released above are now in their keepalive timeout phase. We
// release the keepalive references immediately.
releaseAllKeepaliveSessions();
}
undoAcquisition(session, eventDispatcher);
session = createAndAcquireSession(schemeDatas, isPlaceholderSession, eventDispatcher);
}
@ -731,6 +730,15 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
}
}
private void releaseAllKeepaliveSessions() {
// Make a local copy, because sessions are removed from this.keepaliveSessions during
// release (via callback).
ImmutableSet<DefaultDrmSession> keepaliveSessions = ImmutableSet.copyOf(this.keepaliveSessions);
for (DrmSession keepaliveSession : keepaliveSessions) {
keepaliveSession.release(/* eventDispatcher= */ null);
}
}
private void releaseAllPreacquiredSessions() {
// Make a local copy, because sessions are removed from this.preacquiredSessionReferences
// during release (via callback).

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.mediacodec;
import static java.lang.Math.max;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.audio.MpegAudioUtil;
@ -29,13 +31,11 @@ import java.nio.ByteBuffer;
*/
/* package */ final class C2Mp3TimestampTracker {
// Mirroring the actual codec, as can be found at
// https://cs.android.com/android/platform/superproject/+/main:frameworks/av/media/codec2/components/mp3/C2SoftMp3Dec.h;l=55;drc=3665390c9d32a917398b240c5a46ced07a3b65eb
private static final long DECODER_DELAY_SAMPLES = 529;
private static final long DECODER_DELAY_FRAMES = 529;
private static final String TAG = "C2Mp3TimestampTracker";
private long processedSamples;
private long anchorTimestampUs;
private long processedFrames;
private boolean seenInvalidMpegAudioHeader;
/**
@ -44,8 +44,8 @@ import java.nio.ByteBuffer;
* <p>This should be done when the codec is flushed.
*/
public void reset() {
processedSamples = 0;
anchorTimestampUs = 0;
processedFrames = 0;
seenInvalidMpegAudioHeader = false;
}
@ -57,6 +57,10 @@ import java.nio.ByteBuffer;
* @return The expected output presentation time, in microseconds.
*/
public long updateAndGetPresentationTimeUs(Format format, DecoderInputBuffer buffer) {
if (processedFrames == 0) {
anchorTimestampUs = buffer.timeUs;
}
if (seenInvalidMpegAudioHeader) {
return buffer.timeUs;
}
@ -71,23 +75,32 @@ import java.nio.ByteBuffer;
int frameCount = MpegAudioUtil.parseMpegAudioFrameSampleCount(sampleHeaderData);
if (frameCount == C.LENGTH_UNSET) {
seenInvalidMpegAudioHeader = true;
processedFrames = 0;
anchorTimestampUs = buffer.timeUs;
Log.w(TAG, "MPEG audio header is invalid.");
return buffer.timeUs;
}
long currentBufferTimestampUs = getBufferTimestampUs(format.sampleRate);
processedFrames += frameCount;
return currentBufferTimestampUs;
}
// These calculations mirror the timestamp calculations in the Codec2 Mp3 Decoder.
/**
* Returns the timestamp of the last buffer that will be produced if the stream ends at the
* current position, in microseconds.
*
* @param format The format associated with input buffers.
* @return The timestamp of the last buffer that will be produced if the stream ends at the
* current position, in microseconds.
*/
public long getLastOutputBufferPresentationTimeUs(Format format) {
return getBufferTimestampUs(format.sampleRate);
}
private long getBufferTimestampUs(long sampleRate) {
// This calculation matches the timestamp calculation in the Codec2 Mp3 Decoder.
// https://cs.android.com/android/platform/superproject/+/main:frameworks/av/media/codec2/components/mp3/C2SoftMp3Dec.cpp;l=464;drc=ed134640332fea70ca4b05694289d91a5265bb46
if (processedSamples == 0) {
anchorTimestampUs = buffer.timeUs;
processedSamples = frameCount - DECODER_DELAY_SAMPLES;
return anchorTimestampUs;
}
long processedDurationUs = getProcessedDurationUs(format);
processedSamples += frameCount;
return anchorTimestampUs + processedDurationUs;
}
private long getProcessedDurationUs(Format format) {
return processedSamples * C.MICROS_PER_SECOND / format.sampleRate;
return anchorTimestampUs
+ max(0, (processedFrames - DECODER_DELAY_FRAMES) * C.MICROS_PER_SECOND / sampleRate);
}
}

View File

@ -1338,6 +1338,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (c2Mp3TimestampTracker != null) {
presentationTimeUs =
c2Mp3TimestampTracker.updateAndGetPresentationTimeUs(inputFormat, buffer);
// When draining the C2 MP3 decoder it produces an extra non-empty buffer with a timestamp
// after all queued input buffer timestamps (unlike other decoders, which generally propagate
// the input timestamps to output buffers 1:1). To detect the end of the stream when this
// buffer is dequeued we override the largest queued timestamp accordingly.
largestQueuedPresentationTimeUs =
max(
largestQueuedPresentationTimeUs,
c2Mp3TimestampTracker.getLastOutputBufferPresentationTimeUs(inputFormat));
}
if (buffer.isDecodeOnly()) {
@ -1347,14 +1355,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
formatQueue.add(presentationTimeUs, inputFormat);
waitingForFirstSampleInFormat = false;
}
// TODO(b/158483277): Find the root cause of why a gap is introduced in MP3 playback when using
// presentationTimeUs from the c2Mp3TimestampTracker.
if (c2Mp3TimestampTracker != null) {
largestQueuedPresentationTimeUs = max(largestQueuedPresentationTimeUs, buffer.timeUs);
} else {
largestQueuedPresentationTimeUs = max(largestQueuedPresentationTimeUs, presentationTimeUs);
}
buffer.flip();
if (buffer.hasSupplementalData()) {
handleInputBufferSupplementalData(buffer);
@ -1972,7 +1973,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @param bufferPresentationTimeUs The presentation time of the output buffer in microseconds.
* @param isDecodeOnlyBuffer Whether the buffer was marked with {@link C#BUFFER_FLAG_DECODE_ONLY}
* by the source.
* @param isLastBuffer Whether the buffer is the last sample of the current stream.
* @param isLastBuffer Whether the buffer is known to contain the last sample of the current
* stream. This flag is set on a best effort basis, and any logic relying on it should degrade
* gracefully to handle cases where it's not set.
* @param format The {@link Format} associated with the buffer.
* @return Whether the output buffer was fully processed (for example, rendered or skipped).
* @throws ExoPlaybackException If an error occurs processing the output buffer.

View File

@ -580,10 +580,10 @@ public final class MediaCodecUtil {
}
}
if (Util.SDK_INT < 30 && decoderInfos.size() > 1) {
if (Util.SDK_INT < 32 && decoderInfos.size() > 1) {
String firstCodecName = decoderInfos.get(0).name;
// Prefer anything other than OMX.qti.audio.decoder.flac on older devices. See [Internal
// ref: b/147278539] and [Internal ref: b/147354613].
// ref: b/199124812].
if ("OMX.qti.audio.decoder.flac".equals(firstCodecName)) {
decoderInfos.add(decoderInfos.remove(0));
}

View File

@ -415,7 +415,7 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
.append('.')
.append(streamKey.groupIndex)
.append('.')
.append(streamKey.trackIndex)
.append(streamKey.streamIndex)
.append(',');
}
if (stringBuilder.length() > 0) {

View File

@ -210,11 +210,17 @@ public final class Requirements implements Parcelable {
if (activeNetwork == null) {
return false;
}
try {
@Nullable
NetworkCapabilities networkCapabilities =
connectivityManager.getNetworkCapabilities(activeNetwork);
return networkCapabilities != null
&& networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
} catch (SecurityException e) {
// Workaround for https://issuetracker.google.com/issues/175055271.
return true;
}
}
@Override

View File

@ -156,8 +156,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
* <h2>Tunneling</h2>
*
* Tunneled playback can be enabled in cases where the combination of renderers and selected tracks
* support it. Tunneled playback is enabled by passing an audio session ID to {@link
* ParametersBuilder#setTunnelingEnabled(boolean)}.
* supports it. This can be done by using {@link ParametersBuilder#setTunnelingEnabled(boolean)}.
*/
public class DefaultTrackSelector extends MappingTrackSelector {

View File

@ -597,14 +597,14 @@ public final class CacheDataSource implements DataSource {
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
DataSpec requestDataSpec = checkNotNull(this.requestDataSpec);
DataSpec currentDataSpec = checkNotNull(this.currentDataSpec);
if (length == 0) {
return 0;
}
if (bytesRemaining == 0) {
return C.RESULT_END_OF_INPUT;
}
DataSpec requestDataSpec = checkNotNull(this.requestDataSpec);
DataSpec currentDataSpec = checkNotNull(this.currentDataSpec);
try {
if (readPosition >= checkCachePosition) {
openNextSource(requestDataSpec, true);

View File

@ -1359,8 +1359,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// The single entry in streamFormats must correspond to the format for which the codec is
// being configured.
if (maxInputSize != Format.NO_VALUE) {
int codecMaxInputSize =
getCodecMaxInputSize(codecInfo, format.sampleMimeType, format.width, format.height);
int codecMaxInputSize = getCodecMaxInputSize(codecInfo, format);
if (codecMaxInputSize != Format.NO_VALUE) {
// Scale up the initial video decoder maximum input size so playlist item transitions with
// small increases in maximum sample size don't require reinitialization. This only makes
@ -1397,7 +1396,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
maxInputSize =
max(
maxInputSize,
getCodecMaxInputSize(codecInfo, format.sampleMimeType, maxWidth, maxHeight));
getCodecMaxInputSize(
codecInfo, format.buildUpon().setWidth(maxWidth).setHeight(maxHeight).build()));
Log.w(TAG, "Codec max resolution adjusted to: " + maxWidth + "x" + maxHeight);
}
}
@ -1476,29 +1476,46 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
return format.maxInputSize + totalInitializationDataSize;
} else {
// Calculated maximum input sizes are overestimates, so it's not necessary to add the size of
// initialization data.
return getCodecMaxInputSize(codecInfo, format.sampleMimeType, format.width, format.height);
return getCodecMaxInputSize(codecInfo, format);
}
}
/**
* Returns a maximum input size for a given codec, MIME type, width and height.
* Returns a maximum input size for a given codec and format.
*
* @param codecInfo Information about the {@link MediaCodec} being configured.
* @param sampleMimeType The format mime type.
* @param width The width in pixels.
* @param height The height in pixels.
* @param format The format.
* @return A maximum input size in bytes, or {@link Format#NO_VALUE} if a maximum could not be
* determined.
*/
private static int getCodecMaxInputSize(
MediaCodecInfo codecInfo, String sampleMimeType, int width, int height) {
private static int getCodecMaxInputSize(MediaCodecInfo codecInfo, Format format) {
int width = format.width;
int height = format.height;
if (width == Format.NO_VALUE || height == Format.NO_VALUE) {
// We can't infer a maximum input size without video dimensions.
return Format.NO_VALUE;
}
String sampleMimeType = format.sampleMimeType;
if (MimeTypes.VIDEO_DOLBY_VISION.equals(sampleMimeType)) {
// Dolby vision can be a wrapper around H264 or H265. We assume it's wrapping H265 by default
// because it's the common case, and because some devices may fail to allocate the codec when
// the larger buffer size required for H264 is requested. We size buffers for H264 only if the
// format contains sufficient information for us to determine unambiguously that it's a H264
// profile.
sampleMimeType = MimeTypes.VIDEO_H265;
@Nullable
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
if (codecProfileAndLevel != null) {
int profile = codecProfileAndLevel.first;
if (profile == CodecProfileLevel.DolbyVisionProfileDvavSe
|| profile == CodecProfileLevel.DolbyVisionProfileDvavPer
|| profile == CodecProfileLevel.DolbyVisionProfileDvavPen) {
sampleMimeType = MimeTypes.VIDEO_H264;
}
}
}
// Attempt to infer a maximum input size from the format.
int maxPixels;
int minCompressionRatio;
@ -1508,9 +1525,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
maxPixels = width * height;
minCompressionRatio = 2;
break;
case MimeTypes.VIDEO_DOLBY_VISION:
// Dolby vision can be a wrapper around H264 or H265. We assume H264 here because the
// minimum compression ratio is lower, meaning we overestimate the maximum input size.
case MimeTypes.VIDEO_H264:
if ("BRAVIA 4K 2015".equals(Util.MODEL) // Sony Bravia 4K
|| ("Amazon".equals(Util.MANUFACTURER)

View File

@ -3660,7 +3660,7 @@ public final class ExoPlayerTest {
Timeline fakeTimeline =
new FakeTimeline(
new TimelineWindowDefinition(
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000));
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000));
final ConcatenatingMediaSource underlyingSource = new ConcatenatingMediaSource();
CompositeMediaSource<Void> delegatingMediaSource =
new CompositeMediaSource<Void>() {
@ -5413,7 +5413,7 @@ public final class ExoPlayerTest {
Timeline fakeTimeline =
new FakeTimeline(
new TimelineWindowDefinition(
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000));
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000));
ConcatenatingMediaSource concatenatingMediaSource =
new ConcatenatingMediaSource(
/* isAtomic= */ false,
@ -5452,7 +5452,7 @@ public final class ExoPlayerTest {
Timeline fakeTimeline =
new FakeTimeline(
new TimelineWindowDefinition(
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000));
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000));
ConcatenatingMediaSource concatenatingMediaSource =
new ConcatenatingMediaSource(/* isAtomic= */ false);
int[] currentWindowIndices = new int[2];
@ -5523,7 +5523,7 @@ public final class ExoPlayerTest {
Timeline fakeTimeline =
new FakeTimeline(
new TimelineWindowDefinition(
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000));
/* isSeekable= */ true, /* isDynamic= */ false, /* durationUs= */ 10_000_000));
ConcatenatingMediaSource concatenatingMediaSource =
new ConcatenatingMediaSource(/* isAtomic= */ false);
int[] currentWindowIndices = new int[2];
@ -10570,7 +10570,7 @@ public final class ExoPlayerTest {
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY);
player.seekForward();
assertThat(player.getCurrentPosition()).isEqualTo(C.DEFAULT_SEEK_FORWARD_INCREMENT_MS / 2);
assertThat(player.getCurrentPosition()).isEqualTo(C.DEFAULT_SEEK_FORWARD_INCREMENT_MS / 2 - 1);
player.release();
}

View File

@ -25,6 +25,7 @@ import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.drm.DrmSessionManager.DrmSessionReference;
import com.google.android.exoplayer2.drm.ExoMediaDrm.AppManagedProvider;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.testutil.FakeExoMediaDrm;
@ -302,6 +303,64 @@ public class DefaultDrmSessionManagerTest {
assertThat(secondDrmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
}
@Test(timeout = 10_000)
public void maxConcurrentSessionsExceeded_allPreacquiredAndKeepaliveSessionsEagerlyReleased()
throws Exception {
ImmutableList<DrmInitData.SchemeData> secondSchemeDatas =
ImmutableList.of(DRM_SCHEME_DATAS.get(0).copyWithData(TestUtil.createByteArray(4, 5, 6)));
FakeExoMediaDrm.LicenseServer licenseServer =
FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS, secondSchemeDatas);
Format secondFormatWithDrmInitData =
new Format.Builder().setDrmInitData(new DrmInitData(secondSchemeDatas)).build();
DrmSessionManager drmSessionManager =
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(
DRM_SCHEME_UUID,
uuid -> new FakeExoMediaDrm.Builder().setMaxConcurrentSessions(1).build())
.setSessionKeepaliveMs(10_000)
.setMultiSession(true)
.build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare();
DrmSessionReference firstDrmSessionReference =
checkNotNull(
drmSessionManager.preacquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
DrmSession firstDrmSession =
checkNotNull(
drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(firstDrmSession);
firstDrmSession.release(/* eventDispatcher= */ null);
// The direct reference to firstDrmSession has been released, it's being kept alive by both
// firstDrmSessionReference and drmSessionManager's internal reference.
assertThat(firstDrmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
DrmSession secondDrmSession =
checkNotNull(
drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
/* eventDispatcher= */ null,
secondFormatWithDrmInitData));
// The drmSessionManager had to release both it's internal keep-alive reference and the
// reference represented by firstDrmSessionReference in order to acquire secondDrmSession.
assertThat(firstDrmSession.getState()).isEqualTo(DrmSession.STATE_RELEASED);
waitForOpenedWithKeys(secondDrmSession);
assertThat(secondDrmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
// Not needed (because the manager has already released this reference) but we call it anyway
// for completeness.
firstDrmSessionReference.release();
// Clean-up
secondDrmSession.release(/* eventDispatcher= */ null);
drmSessionManager.release();
}
@Test(timeout = 10_000)
public void sessionReacquired_keepaliveTimeOutCancelled() throws Exception {
FakeExoMediaDrm.LicenseServer licenseServer =
@ -364,7 +423,7 @@ public class DefaultDrmSessionManagerTest {
drmSessionManager.prepare();
DrmSessionManager.DrmSessionReference sessionReference =
DrmSessionReference sessionReference =
drmSessionManager.preacquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
eventDispatcher,
@ -413,7 +472,7 @@ public class DefaultDrmSessionManagerTest {
drmSessionManager.prepare();
DrmSessionManager.DrmSessionReference sessionReference =
DrmSessionReference sessionReference =
drmSessionManager.preacquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
/* eventDispatcher= */ null,
@ -453,7 +512,7 @@ public class DefaultDrmSessionManagerTest {
drmSessionManager.prepare();
DrmSessionManager.DrmSessionReference sessionReference =
DrmSessionReference sessionReference =
drmSessionManager.preacquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
/* eventDispatcher= */ null,

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.mediacodec;
import static com.google.android.exoplayer2.testutil.TestUtil.createByteArray;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -22,6 +23,8 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.util.MimeTypes;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -30,49 +33,68 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public final class C2Mp3TimestampTrackerTest {
private static final Format AUDIO_MP3 =
private static final Format FORMAT =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_MPEG)
.setChannelCount(2)
.setSampleRate(44_100)
.build();
private DecoderInputBuffer buffer;
private C2Mp3TimestampTracker timestampTracker;
private DecoderInputBuffer buffer;
private DecoderInputBuffer invalidBuffer;
@Before
public void setUp() {
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
timestampTracker = new C2Mp3TimestampTracker();
buffer.data = ByteBuffer.wrap(new byte[] {-1, -5, -24, 60});
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
buffer.data = ByteBuffer.wrap(createByteArray(0xFF, 0xFB, 0xE8, 0x3C));
buffer.timeUs = 100_000;
invalidBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
invalidBuffer.data = ByteBuffer.wrap(createByteArray(0, 0, 0, 0));
invalidBuffer.timeUs = 120_000;
}
@Test
public void whenUpdateCalledMultipleTimes_timestampsIncrease() {
long first = timestampTracker.updateAndGetPresentationTimeUs(AUDIO_MP3, buffer);
long second = timestampTracker.updateAndGetPresentationTimeUs(AUDIO_MP3, buffer);
long third = timestampTracker.updateAndGetPresentationTimeUs(AUDIO_MP3, buffer);
public void handleBuffers_outputsCorrectTimestamps() {
List<Long> presentationTimesUs = new ArrayList<>();
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
presentationTimesUs.add(timestampTracker.getLastOutputBufferPresentationTimeUs(FORMAT));
assertThat(second).isGreaterThan(first);
assertThat(third).isGreaterThan(second);
assertThat(presentationTimesUs).containsExactly(100_000L, 114_126L, 140_249L, 166_371L);
}
@Test
public void whenResetCalled_timestampsDecrease() {
long first = timestampTracker.updateAndGetPresentationTimeUs(AUDIO_MP3, buffer);
long second = timestampTracker.updateAndGetPresentationTimeUs(AUDIO_MP3, buffer);
public void handleBuffersWithReset_resetsTimestamps() {
List<Long> presentationTimesUs = new ArrayList<>();
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
timestampTracker.reset();
long third = timestampTracker.updateAndGetPresentationTimeUs(AUDIO_MP3, buffer);
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
presentationTimesUs.add(timestampTracker.getLastOutputBufferPresentationTimeUs(FORMAT));
assertThat(second).isGreaterThan(first);
assertThat(third).isLessThan(second);
assertThat(presentationTimesUs).containsExactly(100_000L, 114_126L, 100_000L, 114_126L);
}
@Test
public void whenBufferTimeIsNotZero_firstSampleIsOffset() {
long first = timestampTracker.updateAndGetPresentationTimeUs(AUDIO_MP3, buffer);
public void handleInvalidBuffer_stopsUpdatingTimestamps() {
List<Long> presentationTimesUs = new ArrayList<>();
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer));
presentationTimesUs.add(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, invalidBuffer));
presentationTimesUs.add(timestampTracker.getLastOutputBufferPresentationTimeUs(FORMAT));
assertThat(first).isEqualTo(buffer.timeUs);
assertThat(presentationTimesUs).containsExactly(100_000L, 114_126L, 120_000L, 120_000L);
}
@Test
public void firstTimestamp_matchesBuffer() {
assertThat(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, buffer))
.isEqualTo(buffer.timeUs);
timestampTracker.reset();
assertThat(timestampTracker.updateAndGetPresentationTimeUs(FORMAT, invalidBuffer))
.isEqualTo(invalidBuffer.timeUs);
}
}

View File

@ -79,9 +79,9 @@ public final class SinglePeriodTimelineTest {
timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, windowDurationUs + 1);
assertThat(position).isNull();
// Should return (0, duration) with a projection equal to window duration.
position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, windowDurationUs);
position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, windowDurationUs - 1);
assertThat(position.first).isEqualTo(timeline.getUidOfPeriod(0));
assertThat(position.second).isEqualTo(windowDurationUs);
assertThat(position.second).isEqualTo(windowDurationUs - 1);
// Should return (0, 0) without a position projection.
position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, 0);
assertThat(position.first).isEqualTo(timeline.getUidOfPeriod(0));

View File

@ -91,12 +91,12 @@ public class UdpDataSourceContractTest extends DataSourceContractTest {
@Test
@Ignore("UdpDataSource doesn't support DataSpec's position or length [internal: b/175856954]")
@Override
public void dataSpecWithPositionAtEnd_throwsPositionOutOfRangeException() {}
public void dataSpecWithPositionAtEnd_readsZeroBytes() {}
@Test
@Ignore("UdpDataSource doesn't support DataSpec's position or length [internal: b/175856954]")
@Override
public void dataSpecWithPositionAtEndAndLength_throwsPositionOutOfRangeException() {}
public void dataSpecWithPositionAtEndAndLength_readsZeroBytes() {}
@Test
@Ignore("UdpDataSource doesn't support DataSpec's position or length [internal: b/175856954]")

View File

@ -124,6 +124,28 @@ public final class CacheDataSourceTest {
assertCacheAndRead(boundedDataSpec, /* unknownLength= */ false);
}
@Test
public void cacheAndReadFromLength_readsZeroBytes() throws Exception {
// Read and cache all data from upstream.
CacheDataSource cacheDataSource =
createCacheDataSource(
/* setReadException= */ false, /* unknownLength= */ false, /* cacheKeyFactory= */ null);
assertReadDataContentLength(
cacheDataSource,
unboundedDataSpec,
/* unknownLength= */ false,
/* customCacheKey= */ false);
// Read from position == length.
cacheDataSource =
createCacheDataSource(
/* setReadException= */ true, /* unknownLength= */ false, /* cacheKeyFactory= */ null);
assertReadData(
cacheDataSource,
unboundedDataSpec.buildUpon().setPosition(TEST_DATA.length).build(),
/* unknownLength= */ false);
}
@Test
public void propagatesHttpHeadersUpstream() throws Exception {
CacheDataSource cacheDataSource =

View File

@ -34,8 +34,8 @@ import java.util.Random;
import java.util.Set;
/**
* Holds the state of {@link #exclude(BaseUrl, long) excluded} base URLs to be used {@link
* #selectBaseUrl(List) to select} a base URL based on these exclusions.
* Holds the state of {@link #exclude(BaseUrl, long) excluded} base URLs to be used to {@link
* #selectBaseUrl(List) select} a base URL based on these exclusions.
*/
public final class BaseUrlExclusionList {

View File

@ -46,20 +46,20 @@ public final class DashUtil {
/**
* Builds a {@link DataSpec} for a given {@link RangedUri} belonging to {@link Representation}.
*
* @param representation The {@link Representation} to which the request belongs.
* @param baseUrl The base url with which to resolve the request URI.
* @param requestUri The {@link RangedUri} of the data to request.
* @param cacheKey An optional cache key.
* @param flags Flags to be set on the returned {@link DataSpec}. See {@link
* DataSpec.Builder#setFlags(int)}.
* @return The {@link DataSpec}.
*/
public static DataSpec buildDataSpec(
String baseUrl, RangedUri requestUri, @Nullable String cacheKey, int flags) {
Representation representation, String baseUrl, RangedUri requestUri, int flags) {
return new DataSpec.Builder()
.setUri(requestUri.resolveUri(baseUrl))
.setPosition(requestUri.start)
.setLength(requestUri.length)
.setKey(cacheKey)
.setKey(resolveCacheKey(representation, requestUri))
.setFlags(flags)
.build();
}
@ -77,8 +77,7 @@ public final class DashUtil {
*/
public static DataSpec buildDataSpec(
Representation representation, RangedUri requestUri, int flags) {
return buildDataSpec(
representation.baseUrls.get(0).url, requestUri, representation.getCacheKey(), flags);
return buildDataSpec(representation, representation.baseUrls.get(0).url, requestUri, flags);
}
/**
@ -289,9 +288,9 @@ public final class DashUtil {
throws IOException {
DataSpec dataSpec =
DashUtil.buildDataSpec(
representation,
representation.baseUrls.get(baseUrlIndex).url,
requestUri,
representation.getCacheKey(),
/* flags= */ 0);
InitializationChunk initializationChunk =
new InitializationChunk(
@ -304,6 +303,21 @@ public final class DashUtil {
initializationChunk.load();
}
/**
* Resolves the cache key to be used when requesting the given ranged URI for the given {@link
* Representation}.
*
* @param representation The {@link Representation} to which the URI belongs to.
* @param rangedUri The URI for which to resolve the cache key.
* @return The cache key.
*/
public static String resolveCacheKey(Representation representation, RangedUri rangedUri) {
@Nullable String cacheKey = representation.getCacheKey();
return cacheKey != null
? cacheKey
: rangedUri.resolveUri(representation.baseUrls.get(0).url).toString();
}
private static ChunkExtractor newChunkExtractor(int trackType, Format format) {
String mimeType = format.containerMimeType;
boolean isWebm =

View File

@ -350,12 +350,11 @@ public class DefaultDashChunkSource implements DashChunkSource {
playbackPositionUs, bufferedDurationUs, availableLiveDurationUs, queue, chunkIterators);
RepresentationHolder representationHolder =
representationHolders[trackSelection.getSelectedIndex()];
updateSelectedBaseUrl(trackSelection.getSelectedIndex());
if (representationHolder.chunkExtractor != null) {
Representation selectedRepresentation = representationHolder.representation;
RangedUri pendingInitializationUri = null;
RangedUri pendingIndexUri = null;
@Nullable RangedUri pendingInitializationUri = null;
@Nullable RangedUri pendingIndexUri = null;
if (representationHolder.chunkExtractor.getSampleFormats() == null) {
pendingInitializationUri = selectedRepresentation.getInitializationUri();
}
@ -495,6 +494,15 @@ public class DefaultDashChunkSource implements DashChunkSource {
int trackIndex = trackSelection.indexOf(chunk.trackFormat);
RepresentationHolder representationHolder = representationHolders[trackIndex];
@Nullable
BaseUrl newBaseUrl =
baseUrlExclusionList.selectBaseUrl(representationHolder.representation.baseUrls);
if (newBaseUrl != null && !representationHolder.selectedBaseUrl.equals(newBaseUrl)) {
// The base URL has changed since the failing chunk was created. Request a replacement chunk,
// which will use the new base URL.
return true;
}
LoadErrorHandlingPolicy.FallbackOptions fallbackOptions =
createFallbackOptions(trackSelection, representationHolder.representation.baseUrls);
if (!fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK)
@ -505,8 +513,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
@Nullable
LoadErrorHandlingPolicy.FallbackSelection fallbackSelection =
loadErrorHandlingPolicy.getFallbackSelectionFor(fallbackOptions, loadErrorInfo);
if (fallbackSelection == null) {
// Policy indicated to not use any fallback.
if (fallbackSelection == null || !fallbackOptions.isFallbackAvailable(fallbackSelection.type)) {
// Policy indicated to not use any fallback or a fallback type that is not available.
return false;
}
@ -518,18 +526,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
} else if (fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION) {
baseUrlExclusionList.exclude(
representationHolder.selectedBaseUrl, fallbackSelection.exclusionDurationMs);
for (int i = 0; i < representationHolders.length; i++) {
@Nullable
BaseUrl baseUrl =
baseUrlExclusionList.selectBaseUrl(representationHolders[i].representation.baseUrls);
if (baseUrl != null) {
if (i == trackIndex) {
cancelLoad = true;
}
representationHolders[i] = representationHolders[i].copyWithNewSelectedBaseUrl(baseUrl);
}
}
}
return cancelLoad;
}
@ -612,7 +610,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
int trackSelectionReason,
Object trackSelectionData,
@Nullable RangedUri initializationUri,
RangedUri indexUri) {
@Nullable RangedUri indexUri) {
Representation representation = representationHolder.representation;
@Nullable RangedUri requestUri;
if (initializationUri != null) {
@ -628,10 +626,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
}
DataSpec dataSpec =
DashUtil.buildDataSpec(
representationHolder.selectedBaseUrl.url,
requestUri,
representation.getCacheKey(),
/* flags= */ 0);
representation, representationHolder.selectedBaseUrl.url, requestUri, /* flags= */ 0);
return new InitializationChunk(
dataSource,
dataSpec,
@ -664,10 +659,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
DataSpec dataSpec =
DashUtil.buildDataSpec(
representationHolder.selectedBaseUrl.url,
segmentUri,
representation.getCacheKey(),
flags);
representation, representationHolder.selectedBaseUrl.url, segmentUri, flags);
return new SingleSampleMediaChunk(
dataSource,
dataSpec,
@ -706,10 +698,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
DataSpec dataSpec =
DashUtil.buildDataSpec(
representationHolder.selectedBaseUrl.url,
segmentUri,
representation.getCacheKey(),
flags);
representation, representationHolder.selectedBaseUrl.url, segmentUri, flags);
long sampleOffsetUs = -representation.presentationTimeOffsetUs;
return new ContainerMediaChunk(
dataSource,
@ -728,6 +717,18 @@ public class DefaultDashChunkSource implements DashChunkSource {
}
}
private RepresentationHolder updateSelectedBaseUrl(int trackIndex) {
RepresentationHolder representationHolder = representationHolders[trackIndex];
@Nullable
BaseUrl selectedBaseUrl =
baseUrlExclusionList.selectBaseUrl(representationHolder.representation.baseUrls);
if (selectedBaseUrl != null && !selectedBaseUrl.equals(representationHolder.selectedBaseUrl)) {
representationHolder = representationHolder.copyWithNewSelectedBaseUrl(selectedBaseUrl);
representationHolders[trackIndex] = representationHolder;
}
return representationHolder;
}
// Protected classes.
/** {@link MediaChunkIterator} wrapping a {@link RepresentationHolder}. */
@ -765,9 +766,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
? 0
: DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED;
return DashUtil.buildDataSpec(
representationHolder.representation,
representationHolder.selectedBaseUrl.url,
segmentUri,
representationHolder.representation.getCacheKey(),
flags);
}

View File

@ -189,7 +189,7 @@ public class DashManifest implements FilterableManifest<DashManifest> {
List<Representation> representations = adaptationSet.representations;
ArrayList<Representation> copyRepresentations = new ArrayList<>();
do {
Representation representation = representations.get(key.trackIndex);
Representation representation = representations.get(key.streamIndex);
copyRepresentations.add(representation);
key = keys.poll();
} while (key.periodIndex == periodIndex && key.groupIndex == adaptationSetIndex);

View File

@ -15,12 +15,15 @@
*/
package com.google.android.exoplayer2.source.dash.offline;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.extractor.ChunkIndex;
import com.google.android.exoplayer2.offline.DownloadException;
import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.source.dash.BaseUrlExclusionList;
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
import com.google.android.exoplayer2.source.dash.DashUtil;
import com.google.android.exoplayer2.source.dash.DashWrappingSegmentIndex;
@ -70,6 +73,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
*/
public final class DashDownloader extends SegmentDownloader<DashManifest> {
private final BaseUrlExclusionList baseUrlExclusionList;
/**
* Creates a new instance.
*
@ -113,6 +118,7 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
super(mediaItem, manifestParser, cacheDataSourceFactory, executor);
baseUrlExclusionList = new BaseUrlExclusionList();
}
@Override
@ -163,28 +169,32 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
throw new DownloadException("Unbounded segment index");
}
String baseUrl = representation.baseUrls.get(0).url;
RangedUri initializationUri = representation.getInitializationUri();
String baseUrl = castNonNull(baseUrlExclusionList.selectBaseUrl(representation.baseUrls)).url;
@Nullable RangedUri initializationUri = representation.getInitializationUri();
if (initializationUri != null) {
addSegment(periodStartUs, baseUrl, initializationUri, out);
out.add(createSegment(representation, baseUrl, periodStartUs, initializationUri));
}
RangedUri indexUri = representation.getIndexUri();
@Nullable RangedUri indexUri = representation.getIndexUri();
if (indexUri != null) {
addSegment(periodStartUs, baseUrl, indexUri, out);
out.add(createSegment(representation, baseUrl, periodStartUs, indexUri));
}
long firstSegmentNum = index.getFirstSegmentNum();
long lastSegmentNum = firstSegmentNum + segmentCount - 1;
for (long j = firstSegmentNum; j <= lastSegmentNum; j++) {
addSegment(periodStartUs + index.getTimeUs(j), baseUrl, index.getSegmentUrl(j), out);
out.add(
createSegment(
representation,
baseUrl,
periodStartUs + index.getTimeUs(j),
index.getSegmentUrl(j)));
}
}
}
private static void addSegment(
long startTimeUs, String baseUrl, RangedUri rangedUri, ArrayList<Segment> out) {
DataSpec dataSpec =
new DataSpec(rangedUri.resolveUri(baseUrl), rangedUri.start, rangedUri.length);
out.add(new Segment(startTimeUs, dataSpec));
private Segment createSegment(
Representation representation, String baseUrl, long startTimeUs, RangedUri rangedUri) {
DataSpec dataSpec = DashUtil.buildDataSpec(representation, baseUrl, rangedUri, /* flags= */ 0);
return new Segment(startTimeUs, dataSpec);
}
@Nullable

View File

@ -25,6 +25,7 @@ import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
import com.google.android.exoplayer2.source.dash.manifest.BaseUrl;
import com.google.android.exoplayer2.source.dash.manifest.Period;
import com.google.android.exoplayer2.source.dash.manifest.RangedUri;
import com.google.android.exoplayer2.source.dash.manifest.Representation;
import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase;
import com.google.android.exoplayer2.upstream.DummyDataSource;
@ -69,6 +70,46 @@ public final class DashUtilTest {
assertThat(format).isNull();
}
@Test
public void resolveCacheKey_representationCacheKeyIsNull_resolvesRangedUriWithFirstBaseUrl() {
ImmutableList<BaseUrl> baseUrls =
ImmutableList.of(new BaseUrl("http://www.google.com"), new BaseUrl("http://www.foo.com"));
Representation.SingleSegmentRepresentation representation =
new Representation.SingleSegmentRepresentation(
/* revisionId= */ 1L,
new Format.Builder().build(),
baseUrls,
new SingleSegmentBase(),
/* inbandEventStreams= */ null,
/* cacheKey= */ null,
/* contentLength= */ 1);
RangedUri rangedUri = new RangedUri("path/to/resource", /* start= */ 0, /* length= */ 1);
String cacheKey = DashUtil.resolveCacheKey(representation, rangedUri);
assertThat(cacheKey).isEqualTo("http://www.google.com/path/to/resource");
}
@Test
public void resolveCacheKey_representationCacheKeyDefined_usesRepresentationCacheKey() {
ImmutableList<BaseUrl> baseUrls =
ImmutableList.of(new BaseUrl("http://www.google.com"), new BaseUrl("http://www.foo.com"));
Representation.SingleSegmentRepresentation representation =
new Representation.SingleSegmentRepresentation(
/* revisionId= */ 1L,
new Format.Builder().build(),
baseUrls,
new SingleSegmentBase(),
/* inbandEventStreams= */ null,
"cacheKey",
/* contentLength= */ 1);
RangedUri rangedUri = new RangedUri("path/to/resource", /* start= */ 0, /* length= */ 1);
String cacheKey = DashUtil.resolveCacheKey(representation, rangedUri);
assertThat(cacheKey).isEqualTo("cacheKey");
}
private static Period newPeriod(AdaptationSet... adaptationSets) {
return new Period("", 0, Arrays.asList(adaptationSets));
}

View File

@ -102,12 +102,14 @@ public final class CeaUtil {
for (TrackOutput output : outputs) {
ccDataBuffer.setPosition(sampleStartPosition);
output.sampleData(ccDataBuffer, sampleLength);
if (presentationTimeUs != C.TIME_UNSET) {
output.sampleMetadata(
presentationTimeUs,
C.BUFFER_FLAG_KEY_FRAME,
sampleLength,
/* offset= */ 0,
/* encryptionData= */ null);
/* cryptoData= */ null);
}
}
}

View File

@ -85,6 +85,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
headerScratchBits = new ParsableBitArray(new byte[HEADER_SIZE]);
headerScratchBytes = new ParsableByteArray(headerScratchBits.data);
state = STATE_FINDING_SYNC;
timeUs = C.TIME_UNSET;
this.language = language;
}
@ -93,6 +94,7 @@ public final class Ac3Reader implements ElementaryStreamReader {
state = STATE_FINDING_SYNC;
bytesRead = 0;
lastByteWas0B = false;
timeUs = C.TIME_UNSET;
}
@Override
@ -104,8 +106,10 @@ public final class Ac3Reader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
if (pesTimeUs != C.TIME_UNSET) {
timeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) {
@ -133,8 +137,10 @@ public final class Ac3Reader implements ElementaryStreamReader {
output.sampleData(data, bytesToRead);
bytesRead += bytesToRead;
if (bytesRead == sampleSize) {
if (timeUs != C.TIME_UNSET) {
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
timeUs += sampleDurationUs;
}
state = STATE_FINDING_SYNC;
}
break;

View File

@ -87,6 +87,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
bytesRead = 0;
lastByteWasAC = false;
hasCRC = false;
timeUs = C.TIME_UNSET;
this.language = language;
}
@ -96,6 +97,7 @@ public final class Ac4Reader implements ElementaryStreamReader {
bytesRead = 0;
lastByteWasAC = false;
hasCRC = false;
timeUs = C.TIME_UNSET;
}
@Override
@ -107,8 +109,10 @@ public final class Ac4Reader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
if (pesTimeUs != C.TIME_UNSET) {
timeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) {
@ -136,8 +140,10 @@ public final class Ac4Reader implements ElementaryStreamReader {
output.sampleData(data, bytesToRead);
bytesRead += bytesToRead;
if (bytesRead == sampleSize) {
if (timeUs != C.TIME_UNSET) {
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
timeUs += sampleDurationUs;
}
state = STATE_FINDING_SYNC;
}
break;

View File

@ -131,12 +131,12 @@ public final class AdtsExtractor implements Extractor {
scratch.setPosition(0);
int syncBytes = scratch.readUnsignedShort();
if (!AdtsReader.isAdtsSyncWord(syncBytes)) {
// We didn't find an ADTS sync word. Start searching again from one byte further into the
// start of the stream.
validFramesCount = 0;
totalValidFramesSize = 0;
headerPosition++;
input.resetPeekPosition();
if (++headerPosition - startPosition >= MAX_SNIFF_BYTES) {
return false;
}
input.advancePeekPosition(headerPosition);
} else {
if (++validFramesCount >= 4 && totalValidFramesSize > TsExtractor.TS_PACKET_SIZE) {
@ -147,14 +147,23 @@ public final class AdtsExtractor implements Extractor {
input.peekFully(scratch.getData(), 0, 4);
scratchBits.setPosition(14);
int frameSize = scratchBits.readBits(13);
// Either the stream is malformed OR we're not parsing an ADTS stream.
if (frameSize <= 6) {
return false;
}
// The size is too small, so we're probably not reading an ADTS frame. Start searching
// again from one byte further into the start of the stream.
validFramesCount = 0;
totalValidFramesSize = 0;
headerPosition++;
input.resetPeekPosition();
input.advancePeekPosition(headerPosition);
} else {
input.advancePeekPosition(frameSize - 6);
totalValidFramesSize += frameSize;
}
}
if (headerPosition - startPosition >= MAX_SNIFF_BYTES) {
return false;
}
}
}
@Override

View File

@ -114,6 +114,7 @@ public final class AdtsReader implements ElementaryStreamReader {
firstFrameVersion = VERSION_UNSET;
firstFrameSampleRateIndex = C.INDEX_UNSET;
sampleDurationUs = C.TIME_UNSET;
timeUs = C.TIME_UNSET;
this.exposeId3 = exposeId3;
this.language = language;
}
@ -125,6 +126,7 @@ public final class AdtsReader implements ElementaryStreamReader {
@Override
public void seek() {
timeUs = C.TIME_UNSET;
resetSync();
}
@ -149,8 +151,10 @@ public final class AdtsReader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
if (pesTimeUs != C.TIME_UNSET) {
timeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) throws ParserException {
@ -529,8 +533,10 @@ public final class AdtsReader implements ElementaryStreamReader {
currentOutput.sampleData(data, bytesToRead);
bytesRead += bytesToRead;
if (bytesRead == sampleSize) {
if (timeUs != C.TIME_UNSET) {
currentOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
timeUs += currentSampleDuration;
}
setFindingSampleState();
}
}

View File

@ -66,6 +66,7 @@ public final class DtsReader implements ElementaryStreamReader {
public DtsReader(@Nullable String language) {
headerScratchBytes = new ParsableByteArray(new byte[HEADER_SIZE]);
state = STATE_FINDING_SYNC;
timeUs = C.TIME_UNSET;
this.language = language;
}
@ -74,6 +75,7 @@ public final class DtsReader implements ElementaryStreamReader {
state = STATE_FINDING_SYNC;
bytesRead = 0;
syncBytes = 0;
timeUs = C.TIME_UNSET;
}
@Override
@ -85,8 +87,10 @@ public final class DtsReader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
if (pesTimeUs != C.TIME_UNSET) {
timeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) {
@ -111,8 +115,10 @@ public final class DtsReader implements ElementaryStreamReader {
output.sampleData(data, bytesToRead);
bytesRead += bytesToRead;
if (bytesRead == sampleSize) {
if (timeUs != C.TIME_UNSET) {
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
timeUs += sampleDurationUs;
}
state = STATE_FINDING_SYNC;
}
break;

View File

@ -43,11 +43,13 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
public DvbSubtitleReader(List<DvbSubtitleInfo> subtitleInfos) {
this.subtitleInfos = subtitleInfos;
outputs = new TrackOutput[subtitleInfos.size()];
sampleTimeUs = C.TIME_UNSET;
}
@Override
public void seek() {
writingSample = false;
sampleTimeUs = C.TIME_UNSET;
}
@Override
@ -73,7 +75,9 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
return;
}
writingSample = true;
if (pesTimeUs != C.TIME_UNSET) {
sampleTimeUs = pesTimeUs;
}
sampleBytesWritten = 0;
bytesToCheck = 2;
}
@ -81,9 +85,11 @@ public final class DvbSubtitleReader implements ElementaryStreamReader {
@Override
public void packetFinished() {
if (writingSample) {
if (sampleTimeUs != C.TIME_UNSET) {
for (TrackOutput output : outputs) {
output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null);
}
}
writingSample = false;
}
}

View File

@ -87,6 +87,8 @@ public final class H262Reader implements ElementaryStreamReader {
userData = null;
userDataParsable = null;
}
pesTimeUs = C.TIME_UNSET;
sampleTimeUs = C.TIME_UNSET;
}
@Override
@ -98,6 +100,8 @@ public final class H262Reader implements ElementaryStreamReader {
}
totalBytesWritten = 0;
startedFirstSample = false;
pesTimeUs = C.TIME_UNSET;
sampleTimeUs = C.TIME_UNSET;
}
@Override
@ -182,7 +186,7 @@ public final class H262Reader implements ElementaryStreamReader {
}
if (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER) {
int bytesWrittenPastStartCode = limit - startCodeOffset;
if (startedFirstSample && sampleHasPicture && hasOutputFormat) {
if (sampleHasPicture && hasOutputFormat && sampleTimeUs != C.TIME_UNSET) {
// Output the sample.
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastStartCode;
@ -194,7 +198,9 @@ public final class H262Reader implements ElementaryStreamReader {
sampleTimeUs =
pesTimeUs != C.TIME_UNSET
? pesTimeUs
: (startedFirstSample ? (sampleTimeUs + frameDurationUs) : 0);
: (sampleTimeUs != C.TIME_UNSET
? (sampleTimeUs + frameDurationUs)
: C.TIME_UNSET);
sampleIsKeyframe = false;
pesTimeUs = C.TIME_UNSET;
startedFirstSample = true;

View File

@ -87,6 +87,7 @@ public final class H263Reader implements ElementaryStreamReader {
this.userDataReader = userDataReader;
prefixFlags = new boolean[4];
csdBuffer = new CsdBuffer(128);
pesTimeUs = C.TIME_UNSET;
if (userDataReader != null) {
userData = new NalUnitTargetBuffer(START_CODE_VALUE_USER_DATA, 128);
userDataParsable = new ParsableByteArray();
@ -107,6 +108,7 @@ public final class H263Reader implements ElementaryStreamReader {
userData.reset();
}
totalBytesWritten = 0;
pesTimeUs = C.TIME_UNSET;
}
@Override
@ -123,8 +125,10 @@ public final class H263Reader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
// TODO (Internal b/32267012): Consider using random access indicator.
if (pesTimeUs != C.TIME_UNSET) {
this.pesTimeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) {
@ -462,7 +466,10 @@ public final class H263Reader implements ElementaryStreamReader {
}
public void onDataEnd(long position, int bytesWrittenPastPosition, boolean hasOutputFormat) {
if (startCodeValue == START_CODE_VALUE_VOP && hasOutputFormat && readingSample) {
if (startCodeValue == START_CODE_VALUE_VOP
&& hasOutputFormat
&& readingSample
&& sampleTimeUs != C.TIME_UNSET) {
int size = (int) (position - samplePosition);
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
output.sampleMetadata(

View File

@ -86,6 +86,7 @@ public final class H264Reader implements ElementaryStreamReader {
sps = new NalUnitTargetBuffer(NAL_UNIT_TYPE_SPS, 128);
pps = new NalUnitTargetBuffer(NAL_UNIT_TYPE_PPS, 128);
sei = new NalUnitTargetBuffer(NAL_UNIT_TYPE_SEI, 128);
pesTimeUs = C.TIME_UNSET;
seiWrapper = new ParsableByteArray();
}
@ -93,6 +94,7 @@ public final class H264Reader implements ElementaryStreamReader {
public void seek() {
totalBytesWritten = 0;
randomAccessIndicator = false;
pesTimeUs = C.TIME_UNSET;
NalUnitUtil.clearPrefixFlags(prefixFlags);
sps.reset();
pps.reset();
@ -113,7 +115,9 @@ public final class H264Reader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
if (pesTimeUs != C.TIME_UNSET) {
this.pesTimeUs = pesTimeUs;
}
randomAccessIndicator |= (flags & FLAG_RANDOM_ACCESS_INDICATOR) != 0;
}
@ -495,6 +499,9 @@ public final class H264Reader implements ElementaryStreamReader {
}
private void outputSample(int offset) {
if (sampleTimeUs == C.TIME_UNSET) {
return;
}
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
int size = (int) (nalUnitStartPosition - samplePosition);
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);

View File

@ -85,12 +85,14 @@ public final class H265Reader implements ElementaryStreamReader {
pps = new NalUnitTargetBuffer(PPS_NUT, 128);
prefixSei = new NalUnitTargetBuffer(PREFIX_SEI_NUT, 128);
suffixSei = new NalUnitTargetBuffer(SUFFIX_SEI_NUT, 128);
pesTimeUs = C.TIME_UNSET;
seiWrapper = new ParsableByteArray();
}
@Override
public void seek() {
totalBytesWritten = 0;
pesTimeUs = C.TIME_UNSET;
NalUnitUtil.clearPrefixFlags(prefixFlags);
vps.reset();
sps.reset();
@ -114,8 +116,10 @@ public final class H265Reader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
// TODO (Internal b/32267012): Consider using random access indicator.
if (pesTimeUs != C.TIME_UNSET) {
this.pesTimeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) {
@ -536,6 +540,9 @@ public final class H265Reader implements ElementaryStreamReader {
}
private void outputSample(int offset) {
if (sampleTimeUs == C.TIME_UNSET) {
return;
}
@C.BufferFlags int flags = sampleIsKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0;
int size = (int) (nalUnitPosition - samplePosition);
output.sampleMetadata(sampleTimeUs, flags, size, offset, null);

View File

@ -49,11 +49,13 @@ public final class Id3Reader implements ElementaryStreamReader {
public Id3Reader() {
id3Header = new ParsableByteArray(ID3_HEADER_LENGTH);
sampleTimeUs = C.TIME_UNSET;
}
@Override
public void seek() {
writingSample = false;
sampleTimeUs = C.TIME_UNSET;
}
@Override
@ -73,7 +75,9 @@ public final class Id3Reader implements ElementaryStreamReader {
return;
}
writingSample = true;
if (pesTimeUs != C.TIME_UNSET) {
sampleTimeUs = pesTimeUs;
}
sampleSize = 0;
sampleBytesRead = 0;
}
@ -120,7 +124,9 @@ public final class Id3Reader implements ElementaryStreamReader {
if (!writingSample || sampleSize == 0 || sampleBytesRead != sampleSize) {
return;
}
if (sampleTimeUs != C.TIME_UNSET) {
output.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
}
writingSample = false;
}
}

View File

@ -78,11 +78,13 @@ public final class LatmReader implements ElementaryStreamReader {
this.language = language;
sampleDataBuffer = new ParsableByteArray(INITIAL_BUFFER_SIZE);
sampleBitArray = new ParsableBitArray(sampleDataBuffer.getData());
timeUs = C.TIME_UNSET;
}
@Override
public void seek() {
state = STATE_FINDING_SYNC_1;
timeUs = C.TIME_UNSET;
streamMuxRead = false;
}
@ -95,8 +97,10 @@ public final class LatmReader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
if (pesTimeUs != C.TIME_UNSET) {
timeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) throws ParserException {
@ -306,9 +310,11 @@ public final class LatmReader implements ElementaryStreamReader {
sampleDataBuffer.setPosition(0);
}
output.sampleData(sampleDataBuffer, muxLengthBytes);
if (timeUs != C.TIME_UNSET) {
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, muxLengthBytes, 0, null);
timeUs += sampleDurationUs;
}
}
private void resetBufferForSize(int newSize) {
sampleDataBuffer.reset(newSize);

View File

@ -69,6 +69,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
headerScratch = new ParsableByteArray(4);
headerScratch.getData()[0] = (byte) 0xFF;
header = new MpegAudioUtil.Header();
timeUs = C.TIME_UNSET;
this.language = language;
}
@ -77,6 +78,7 @@ public final class MpegAudioReader implements ElementaryStreamReader {
state = STATE_FINDING_HEADER;
frameBytesRead = 0;
lastByteWasFF = false;
timeUs = C.TIME_UNSET;
}
@Override
@ -88,8 +90,10 @@ public final class MpegAudioReader implements ElementaryStreamReader {
@Override
public void packetStarted(long pesTimeUs, @TsPayloadReader.Flags int flags) {
if (pesTimeUs != C.TIME_UNSET) {
timeUs = pesTimeUs;
}
}
@Override
public void consume(ParsableByteArray data) {
@ -227,8 +231,10 @@ public final class MpegAudioReader implements ElementaryStreamReader {
return;
}
if (timeUs != C.TIME_UNSET) {
output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, frameSize, 0, null);
timeUs += frameDurationUs;
}
frameBytesRead = 0;
state = STATE_FINDING_HEADER;
}

View File

@ -21,6 +21,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.TimestampAdjuster;
import com.google.android.exoplayer2.util.Util;
@ -41,6 +42,8 @@ import java.io.IOException;
*/
/* package */ final class PsDurationReader {
private static final String TAG = "PsDurationReader";
private static final int TIMESTAMP_SEARCH_BYTES = 20_000;
private final TimestampAdjuster scrTimestampAdjuster;
@ -102,6 +105,10 @@ import java.io.IOException;
long minScrPositionUs = scrTimestampAdjuster.adjustTsTimestamp(firstScrValue);
long maxScrPositionUs = scrTimestampAdjuster.adjustTsTimestamp(lastScrValue);
durationUs = maxScrPositionUs - minScrPositionUs;
if (durationUs < 0) {
Log.w(TAG, "Invalid duration: " + durationUs + ". Using TIME_UNSET instead.");
durationUs = C.TIME_UNSET;
}
return finishReadDuration(input);
}

View File

@ -21,6 +21,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.TimestampAdjuster;
import com.google.android.exoplayer2.util.Util;
@ -38,6 +39,8 @@ import java.io.IOException;
*/
/* package */ final class TsDurationReader {
private static final String TAG = "TsDurationReader";
private final int timestampSearchBytes;
private final TimestampAdjuster pcrTimestampAdjuster;
private final ParsableByteArray packetBuffer;
@ -98,6 +101,10 @@ import java.io.IOException;
long minPcrPositionUs = pcrTimestampAdjuster.adjustTsTimestamp(firstPcrValue);
long maxPcrPositionUs = pcrTimestampAdjuster.adjustTsTimestamp(lastPcrValue);
durationUs = maxPcrPositionUs - minPcrPositionUs;
if (durationUs < 0) {
Log.w(TAG, "Invalid duration: " + durationUs + ". Using TIME_UNSET instead.");
durationUs = C.TIME_UNSET;
}
return finishReadDuration(input);
}

View File

@ -1 +0,0 @@
../../proguard-rules.txt

View File

@ -555,6 +555,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
chunkSource.setIsTimestampMaster(isTimestampMaster);
}
/**
* Called if an error is encountered while loading a playlist.
*
* @param playlistUrl The {@link Uri} of the playlist whose load encountered an error.
* @param loadErrorInfo The load error info.
* @param forceRetry Whether retry should be forced without considering exclusion.
* @return True if excluding did not encounter errors. False otherwise.
*/
public boolean onPlaylistError(Uri playlistUrl, LoadErrorInfo loadErrorInfo, boolean forceRetry) {
if (!chunkSource.obtainsChunksForPlaylist(playlistUrl)) {
// Return early if the chunk source doesn't deliver chunks for the failing playlist.
@ -571,7 +579,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
exclusionDurationMs = fallbackSelection.exclusionDurationMs;
}
}
return chunkSource.onPlaylistError(playlistUrl, exclusionDurationMs);
// We must call ChunkSource.onPlaylistError in any case to give the chunk source the chance to
// mark the playlist as failing.
return chunkSource.onPlaylistError(playlistUrl, exclusionDurationMs)
&& exclusionDurationMs != C.TIME_UNSET;
}
// SampleStream implementation.

View File

@ -308,7 +308,7 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
T stream = streams.get(i);
for (int j = 0; j < streamKeys.size(); j++) {
StreamKey streamKey = streamKeys.get(j);
if (streamKey.groupIndex == groupIndex && streamKey.trackIndex == i) {
if (streamKey.groupIndex == groupIndex && streamKey.streamIndex == i) {
copiedStreams.add(stream);
break;
}

View File

@ -43,11 +43,11 @@ import java.util.HashMap;
/** Parses the RTPMAP attribute value (with the part "a=rtpmap:" removed). */
public static RtpMapAttribute parse(String rtpmapString) throws ParserException {
String[] rtpmapInfo = Util.split(rtpmapString, " ");
String[] rtpmapInfo = Util.splitAtFirst(rtpmapString, " ");
checkArgument(rtpmapInfo.length == 2);
int payloadType = parseInt(rtpmapInfo[0]);
String[] mediaInfo = Util.split(rtpmapInfo[1], "/");
String[] mediaInfo = Util.split(rtpmapInfo[1].trim(), "/");
checkArgument(mediaInfo.length >= 2);
int clockRate = parseInt(mediaInfo[1]);
int encodingParameters = C.INDEX_UNSET;

View File

@ -501,7 +501,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
ImmutableList<RtspTrackTiming> trackTimingList =
rtpInfoString == null
? ImmutableList.of()
: RtspTrackTiming.parseTrackTiming(rtpInfoString);
: RtspTrackTiming.parseTrackTiming(rtpInfoString, uri);
onPlayResponseReceived(new RtspPlayResponse(response.status, timing, trackTimingList));
break;

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.source.rtsp;
import static com.google.android.exoplayer2.source.rtsp.MediaDescription.MEDIA_TYPE_AUDIO;
import static com.google.android.exoplayer2.source.rtsp.RtpPayloadFormat.getMimeTypeFromRtpMediaType;
import static com.google.android.exoplayer2.source.rtsp.SessionDescription.ATTR_CONTROL;
import static com.google.android.exoplayer2.source.rtsp.SessionDescription.ATTR_RTPMAP;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.NalUnitUtil.NAL_START_CODE;
@ -95,13 +94,6 @@ import com.google.common.collect.ImmutableMap;
formatBuilder.setAverageBitrate(mediaDescription.bitrate);
}
// rtpmap is mandatory in an RTSP session with dynamic payload types (RFC2326 Section C.1.3).
checkArgument(mediaDescription.attributes.containsKey(ATTR_RTPMAP));
String rtpmapAttribute = castNonNull(mediaDescription.attributes.get(ATTR_RTPMAP));
// rtpmap string format: RFC2327 Page 22.
String[] rtpmap = Util.split(rtpmapAttribute, " ");
checkArgument(rtpmap.length == 2);
int rtpPayloadType = mediaDescription.rtpMapAttribute.payloadType;
String mimeType = getMimeTypeFromRtpMediaType(mediaDescription.rtpMapAttribute.mediaEncoding);

View File

@ -94,18 +94,18 @@ import java.util.regex.Pattern;
// Session header pattern, see RFC2326 Sections 3.4 and 12.37.
private static final Pattern SESSION_HEADER_PATTERN =
Pattern.compile("([\\w$-_.+]+)(?:;\\s?timeout=(\\d+))?");
Pattern.compile("([\\w$\\-_.+]+)(?:;\\s?timeout=(\\d+))?");
// WWW-Authenticate header pattern, see RFC2068 Sections 14.46 and RFC2069.
private static final Pattern WWW_AUTHENTICATION_HEADER_DIGEST_PATTERN =
Pattern.compile(
"Digest realm=\"([\\w\\s@.]+)\""
+ ",\\s?(?:domain=\"(.+)\",\\s?)?"
+ "nonce=\"(\\w+)\""
+ "(?:,\\s?opaque=\"(\\w+)\")?");
"Digest realm=\"([^\"\\x00-\\x08\\x0A-\\x1f\\x7f]+)\""
+ ",\\s?(?:domain=\"(.+)\""
+ ",\\s?)?nonce=\"([^\"\\x00-\\x08\\x0A-\\x1f\\x7f]+)\""
+ "(?:,\\s?opaque=\"([^\"\\x00-\\x08\\x0A-\\x1f\\x7f]+)\")?");
// WWW-Authenticate header pattern, see RFC2068 Section 11.1 and RFC2069.
private static final Pattern WWW_AUTHENTICATION_HEADER_BASIC_PATTERN =
Pattern.compile("Basic realm=\"([\\w\\s@.]+)\"");
Pattern.compile("Basic realm=\"([^\"\\x00-\\x08\\x0A-\\x1f\\x7f]+)\"");
private static final String RTSP_VERSION = "RTSP/1.0";
private static final String LF = new String(new byte[] {Ascii.LF});

View File

@ -15,10 +15,15 @@
*/
package com.google.android.exoplayer2.source.rtsp;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.util.UriUtil;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
@ -49,11 +54,12 @@ import com.google.common.collect.ImmutableList;
* </pre>
*
* @param rtpInfoString The value of the RTP-Info header, with header name (RTP-Info) removed.
* @param sessionUri The session URI, must include an {@code rtsp} scheme.
* @return A list of parsed {@link RtspTrackTiming}.
* @throws ParserException If parsing failed.
*/
public static ImmutableList<RtspTrackTiming> parseTrackTiming(String rtpInfoString)
throws ParserException {
public static ImmutableList<RtspTrackTiming> parseTrackTiming(
String rtpInfoString, Uri sessionUri) throws ParserException {
ImmutableList.Builder<RtspTrackTiming> listBuilder = new ImmutableList.Builder<>();
for (String perTrackTimingString : Util.split(rtpInfoString, ",")) {
@ -69,7 +75,7 @@ import com.google.common.collect.ImmutableList;
switch (attributeName) {
case "url":
uri = Uri.parse(attributeValue);
uri = resolveUri(/* urlString= */ attributeValue, sessionUri);
break;
case "seq":
sequenceNumber = Integer.parseInt(attributeValue);
@ -96,6 +102,48 @@ import com.google.common.collect.ImmutableList;
return listBuilder.build();
}
/**
* Resolves the input string to always be an absolute URL with RTP-Info headers
*
* <p>Handles some servers do not send absolute URL in RTP-Info headers. This method takes in
* RTP-Info header's url string, and returns the correctly formatted {@link Uri url} for this
* track. The input url string could be
*
* <ul>
* <li>A correctly formatted URL, like "{@code rtsp://foo.bar/video}".
* <li>A correct URI that is missing the scheme, like "{@code foo.bar/video}".
* <li>A path to the resource, like "{@code video}" or "{@code /video}".
* </ul>
*
* @param urlString The URL included in the RTP-Info header, without the {@code url=} identifier.
* @param sessionUri The session URI, must include an {@code rtsp} scheme, or {@link
* IllegalArgumentException} is thrown.
* @return The formatted URL.
*/
@VisibleForTesting
/* package */ static Uri resolveUri(String urlString, Uri sessionUri) {
checkArgument(checkNotNull(sessionUri.getScheme()).equals("rtsp"));
Uri uri = Uri.parse(urlString);
if (uri.isAbsolute()) {
return uri;
}
// The urlString is at least missing the scheme.
uri = Uri.parse("rtsp://" + urlString);
String sessionUriString = sessionUri.toString();
String host = checkNotNull(uri.getHost());
if (host.equals(sessionUri.getHost())) {
// Handles the case that the urlString is only missing the scheme.
return uri;
}
return sessionUriString.endsWith("/")
? UriUtil.resolveToUri(sessionUriString, urlString)
: UriUtil.resolveToUri(sessionUriString + "/", urlString);
}
/**
* The timestamp of the next RTP packet, {@link C#TIME_UNSET} if not present.
*

View File

@ -359,6 +359,16 @@ public final class RtspMessageUtilTest {
assertThat(sessionHeader.sessionId).isEqualTo("610a63df-9b57.4856_97ac$665f+56e9c04");
}
@Test
public void parseSessionHeader_withSessionIdContainingSpecialCharactersAndTimeout_succeeds()
throws Exception {
String sessionHeaderString = "610a63df-9b57.4856_97ac$665f+56e9c04;timeout=60";
RtspMessageUtil.RtspSessionHeader sessionHeader =
RtspMessageUtil.parseSessionHeader(sessionHeaderString);
assertThat(sessionHeader.sessionId).isEqualTo("610a63df-9b57.4856_97ac$665f+56e9c04");
assertThat(sessionHeader.timeoutMs).isEqualTo(60_000);
}
@Test
public void removeUserInfo_withUserInfo() {
Uri uri = Uri.parse("rtsp://user:pass@foo.bar/foo.mkv");
@ -442,10 +452,10 @@ public final class RtspMessageUtilTest {
@Test
public void parseWWWAuthenticateHeader_withBasicAuthentication_succeeds() throws Exception {
RtspAuthenticationInfo authenticationInfo =
RtspMessageUtil.parseWwwAuthenticateHeader("Basic realm=\"WallyWorld\"");
RtspMessageUtil.parseWwwAuthenticateHeader("Basic realm=\"Wally - World\"");
assertThat(authenticationInfo.authenticationMechanism).isEqualTo(RtspAuthenticationInfo.BASIC);
assertThat(authenticationInfo.nonce).isEmpty();
assertThat(authenticationInfo.realm).isEqualTo("WallyWorld");
assertThat(authenticationInfo.realm).isEqualTo("Wally - World");
}
@Test
@ -453,13 +463,13 @@ public final class RtspMessageUtilTest {
throws Exception {
RtspAuthenticationInfo authenticationInfo =
RtspMessageUtil.parseWwwAuthenticateHeader(
"Digest realm=\"testrealm@host.com\", domain=\"host.com\","
"Digest realm=\"test-realm@host.com\", domain=\"host.com\","
+ " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+ " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"");
assertThat(authenticationInfo.authenticationMechanism).isEqualTo(RtspAuthenticationInfo.DIGEST);
assertThat(authenticationInfo.nonce).isEqualTo("dcd98b7102dd2f0e8b11d0f600bfb0c093");
assertThat(authenticationInfo.realm).isEqualTo("testrealm@host.com");
assertThat(authenticationInfo.realm).isEqualTo("test-realm@host.com");
assertThat(authenticationInfo.opaque).isEmpty();
}

View File

@ -35,7 +35,7 @@ public class RtspTrackTimingTest {
"url=rtsp://video.example.com/twister/video;seq=12312232;rtptime=78712811";
ImmutableList<RtspTrackTiming> trackTimingList =
RtspTrackTiming.parseTrackTiming(rtpInfoString);
RtspTrackTiming.parseTrackTiming(rtpInfoString, Uri.parse("rtsp://video.example.com"));
assertThat(trackTimingList).hasSize(1);
RtspTrackTiming trackTiming = trackTimingList.get(0);
@ -50,7 +50,7 @@ public class RtspTrackTimingTest {
"url=rtsp://foo.com/bar.avi/streamid=0;seq=45102,url=rtsp://foo.com/bar.avi/streamid=1;seq=30211";
ImmutableList<RtspTrackTiming> trackTimingList =
RtspTrackTiming.parseTrackTiming(rtpInfoString);
RtspTrackTiming.parseTrackTiming(rtpInfoString, Uri.parse("rtsp://foo.com"));
assertThat(trackTimingList).hasSize(2);
RtspTrackTiming trackTiming = trackTimingList.get(0);
@ -67,27 +67,88 @@ public class RtspTrackTimingTest {
public void parseTiming_withInvalidParameter_throws() {
String rtpInfoString = "url=rtsp://video.example.com/twister/video;seq=123abc";
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
}
@Test
public void parseTiming_withInvalidUrl_throws() {
String rtpInfoString = "url=video.example.com/twister/video;seq=36192348";
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
assertThrows(
ParserException.class,
() ->
RtspTrackTiming.parseTrackTiming(
rtpInfoString, Uri.parse("rtsp://video.example.com/twister")));
}
@Test
public void parseTiming_withNoParameter_throws() {
String rtpInfoString = "url=rtsp://video.example.com/twister/video";
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
assertThrows(
ParserException.class,
() ->
RtspTrackTiming.parseTrackTiming(
rtpInfoString, Uri.parse("rtsp://video.example.com/twister")));
}
@Test
public void parseTiming_withNoUrl_throws() {
String rtpInfoString = "seq=35421887";
assertThrows(ParserException.class, () -> RtspTrackTiming.parseTrackTiming(rtpInfoString));
assertThrows(
ParserException.class,
() ->
RtspTrackTiming.parseTrackTiming(
rtpInfoString, Uri.parse("rtsp://video.example.com/twister")));
}
@Test
public void resolveUri_withAbsoluteUri_succeeds() {
Uri uri =
RtspTrackTiming.resolveUri(
"rtsp://video.example.com/twister/video=1?a2bfc09887ce",
Uri.parse("rtsp://video.example.com/twister"));
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/video=1?a2bfc09887ce"));
}
@Test
public void resolveUri_withCompleteUriMissingScheme_succeeds() {
Uri uri =
RtspTrackTiming.resolveUri(
"video.example.com/twister/video=1", Uri.parse("rtsp://video.example.com/twister"));
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/video=1"));
}
@Test
public void resolveUri_withPartialUriMissingScheme_succeeds() {
Uri uri = RtspTrackTiming.resolveUri("video=1", Uri.parse("rtsp://video.example.com/twister"));
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/video=1"));
}
@Test
public void resolveUri_withMultipartPartialUriMissingScheme_succeeds() {
Uri uri =
RtspTrackTiming.resolveUri(
"container/video=1", Uri.parse("rtsp://video.example.com/twister"));
assertThat(uri).isEqualTo(Uri.parse("rtsp://video.example.com/twister/container/video=1"));
}
@Test
public void resolveUri_withPartialUriMissingSchemeWithIpBaseUri_succeeds() {
Uri uri = RtspTrackTiming.resolveUri("video=1", Uri.parse("rtsp://127.0.0.1:18888/test"));
assertThat(uri).isEqualTo(Uri.parse("rtsp://127.0.0.1:18888/test/video=1"));
}
@Test
public void resolveUri_withPartialUriMissingSchemeWithIpBaseUriWithSlash_succeeds() {
Uri uri = RtspTrackTiming.resolveUri("video=1", Uri.parse("rtsp://127.0.0.1:18888/test/"));
assertThat(uri).isEqualTo(Uri.parse("rtsp://127.0.0.1:18888/test/video=1"));
}
@Test
public void resolveUri_withSessionUriMissingScheme_throwsIllegalArgumentException() {
assertThrows(
IllegalArgumentException.class,
() -> RtspTrackTiming.resolveUri("video=1", Uri.parse("127.0.0.1:18888/test")));
}
}

View File

@ -191,6 +191,25 @@ public class SessionDescriptionTest {
assertThat(sessionDescription.attributes).containsEntry(ATTR_CONTROL, "session1");
}
@Test
public void parse_sdpStringWithExtraSpaceInRtpMapAttribute_succeeds() throws Exception {
String testMediaSdpInfo =
"v=0\r\n"
+ "o=MNobody 2890844526 2890842807 IN IP4 192.0.2.46\r\n"
+ "s=SDP Seminar\r\n"
+ "t=0 0\r\n"
+ "a=control:*\r\n"
+ "m=audio 3456 RTP/AVP 0\r\n"
+ "a=rtpmap:97 AC3/44100 \r\n";
SessionDescription sessionDescription = SessionDescriptionParser.parse(testMediaSdpInfo);
MediaDescription.RtpMapAttribute rtpMapAttribute =
sessionDescription.mediaDescriptionList.get(0).rtpMapAttribute;
assertThat(rtpMapAttribute.payloadType).isEqualTo(97);
assertThat(rtpMapAttribute.mediaEncoding).isEqualTo("AC3");
assertThat(rtpMapAttribute.clockRate).isEqualTo(44100);
}
@Test
public void buildMediaDescription_withInvalidRtpmapAttribute_throwsIllegalStateException() {
assertThrows(

View File

@ -339,7 +339,7 @@ public class SsManifest implements FilterableManifest<SsManifest> {
copiedFormats.clear();
}
currentStreamElement = streamElement;
copiedFormats.add(streamElement.formats[key.trackIndex]);
copiedFormats.add(streamElement.formats[key.streamIndex]);
}
if (currentStreamElement != null) {
// Add the last stream element.

View File

@ -512,6 +512,9 @@ public class DefaultTimeBar extends View implements TimeBar {
@Override
public void setPosition(long position) {
if (this.position == position) {
return;
}
this.position = position;
setContentDescription(getProgressText());
update();
@ -519,12 +522,18 @@ public class DefaultTimeBar extends View implements TimeBar {
@Override
public void setBufferedPosition(long bufferedPosition) {
if (this.bufferedPosition == bufferedPosition) {
return;
}
this.bufferedPosition = bufferedPosition;
update();
}
@Override
public void setDuration(long duration) {
if (this.duration == duration) {
return;
}
this.duration = duration;
if (scrubbing && duration == C.TIME_UNSET) {
stopScrubbing(/* canceled= */ true);

View File

@ -20,6 +20,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_SEEK_FORWARD;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_WINDOW;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS;
import static com.google.android.exoplayer2.Player.EVENT_AVAILABLE_COMMANDS_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAY_WHEN_READY_CHANGED;
@ -41,10 +42,13 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.DoNotInline;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ControlDispatcher;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
@ -339,6 +343,8 @@ public class PlayerControlView extends FrameLayout {
private long[] extraAdGroupTimesMs;
private boolean[] extraPlayedAdGroups;
private long currentWindowOffset;
private long currentPosition;
private long currentBufferedPosition;
public PlayerControlView(Context context) {
this(context, /* attrs= */ null);
@ -377,7 +383,8 @@ public class PlayerControlView extends FrameLayout {
TypedArray a =
context
.getTheme()
.obtainStyledAttributes(playbackAttrs, R.styleable.PlayerControlView, 0, 0);
.obtainStyledAttributes(
playbackAttrs, R.styleable.PlayerControlView, defStyleAttr, /* defStyleRes= */ 0);
try {
showTimeoutMs = a.getInt(R.styleable.PlayerControlView_show_timeout, showTimeoutMs);
controllerLayoutId =
@ -424,8 +431,8 @@ public class PlayerControlView extends FrameLayout {
if (customTimeBar != null) {
timeBar = customTimeBar;
} else if (timeBarPlaceholder != null) {
// Propagate attrs as timebarAttrs so that DefaultTimeBar's custom attributes are transferred,
// but standard attributes (e.g. background) are not.
// Propagate playbackAttrs as timebarAttrs so that DefaultTimeBar's custom attributes are
// transferred, but standard attributes (e.g. background) are not.
DefaultTimeBar defaultTimeBar = new DefaultTimeBar(context, null, 0, playbackAttrs);
defaultTimeBar.setId(R.id.exo_progress);
defaultTimeBar.setLayoutParams(timeBarPlaceholder.getLayoutParams());
@ -782,6 +789,7 @@ public class PlayerControlView extends FrameLayout {
}
updateAll();
requestPlayPauseFocus();
requestPlayPauseAccessibilityFocus();
}
// Call hideAfterTimeout even if already visible to reset the timeout.
hideAfterTimeout();
@ -830,18 +838,30 @@ public class PlayerControlView extends FrameLayout {
return;
}
boolean requestPlayPauseFocus = false;
boolean requestPlayPauseAccessibilityFocus = false;
boolean shouldShowPauseButton = shouldShowPauseButton();
if (playButton != null) {
requestPlayPauseFocus |= shouldShowPauseButton && playButton.isFocused();
requestPlayPauseAccessibilityFocus |=
Util.SDK_INT < 21
? requestPlayPauseFocus
: (shouldShowPauseButton && Api21.isAccessibilityFocused(playButton));
playButton.setVisibility(shouldShowPauseButton ? GONE : VISIBLE);
}
if (pauseButton != null) {
requestPlayPauseFocus |= !shouldShowPauseButton && pauseButton.isFocused();
requestPlayPauseAccessibilityFocus |=
Util.SDK_INT < 21
? requestPlayPauseFocus
: (!shouldShowPauseButton && Api21.isAccessibilityFocused(pauseButton));
pauseButton.setVisibility(shouldShowPauseButton ? VISIBLE : GONE);
}
if (requestPlayPauseFocus) {
requestPlayPauseFocus();
}
if (requestPlayPauseAccessibilityFocus) {
requestPlayPauseAccessibilityFocus();
}
}
private void updateNavigation() {
@ -1020,14 +1040,21 @@ public class PlayerControlView extends FrameLayout {
position = currentWindowOffset + player.getContentPosition();
bufferedPosition = currentWindowOffset + player.getContentBufferedPosition();
}
if (positionView != null && !scrubbing) {
boolean positionChanged = position != currentPosition;
boolean bufferedPositionChanged = bufferedPosition != currentBufferedPosition;
currentPosition = position;
currentBufferedPosition = bufferedPosition;
// Only update the TextView if the position has changed, else TalkBack will repeatedly read the
// same position to the user.
if (positionView != null && !scrubbing && positionChanged) {
positionView.setText(Util.getStringForTime(formatBuilder, formatter, position));
}
if (timeBar != null) {
timeBar.setPosition(position);
timeBar.setBufferedPosition(bufferedPosition);
}
if (progressUpdateListener != null) {
if (progressUpdateListener != null && (positionChanged || bufferedPositionChanged)) {
progressUpdateListener.onProgressUpdate(position, bufferedPosition);
}
@ -1064,6 +1091,15 @@ public class PlayerControlView extends FrameLayout {
}
}
private void requestPlayPauseAccessibilityFocus() {
boolean shouldShowPauseButton = shouldShowPauseButton();
if (!shouldShowPauseButton && playButton != null) {
playButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
} else if (shouldShowPauseButton && pauseButton != null) {
pauseButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
}
private void updateButton(boolean visible, boolean enabled, @Nullable View view) {
if (view == null) {
return;
@ -1279,7 +1315,8 @@ public class PlayerControlView extends FrameLayout {
EVENT_REPEAT_MODE_CHANGED,
EVENT_SHUFFLE_MODE_ENABLED_CHANGED,
EVENT_POSITION_DISCONTINUITY,
EVENT_TIMELINE_CHANGED)) {
EVENT_TIMELINE_CHANGED,
EVENT_AVAILABLE_COMMANDS_CHANGED)) {
updateNavigation();
}
if (events.containsAny(EVENT_POSITION_DISCONTINUITY, EVENT_TIMELINE_CHANGED)) {
@ -1338,4 +1375,12 @@ public class PlayerControlView extends FrameLayout {
}
}
}
@RequiresApi(21)
private static final class Api21 {
@DoNotInline
public static boolean isAccessibilityFocused(View view) {
return view.isAccessibilityFocused();
}
}
}

Some files were not shown because too many files have changed in this diff Show More