Even when fixed to the US locale (and thus avoiding surprising behaviour
in e.g. Turkish locale with "i" and "I") there are unexpected behaviours
when upper and lower casing non-ASCII characters.
For example it's sometimes not symmetric, e.g.:
"ẞ".toLowerCase() -> "ß"
"ß".toUpperCase() -> "SS"
In all the ExoPlayer usages we are either dealing with known-ASCII
strings (e.g. MIME types) or comparing against ASCII constant strings
anyway, so it seems easier to just use Guava's ASCII-only class in these
cases.
Util.toUpperInvariant() is null-tolerant, while Ascii.toLowercase() is
not. Most usages in this change are clearly non-null. The BandwidthMeter
usages aren't annotated @Nullable, but the current code *would* work if
countryCode was null in both cases. These methods will now throw NPE if
they're passed null.
PiperOrigin-RevId: 368816287
Discontinuity reasons may not be precisely obtained for remote
player. 'Remote Player' means that playback is owned by another
app or device and the same playback can be controller by other
clients simultaneously. The MediaController is an example.
If the remote playback doesn't provide discontinuity reason, then
player cannot differentiate between automatic playback transition
and seekTo() from another client.
This CL tweaks the discontinuity reason definitions, so reasons
can be obtained without remote playback's support.
This doesn't effect the local Players, such as SimpleExoPlayer.
PiperOrigin-RevId: 368579577
Even when fixed to the US locale (and thus avoiding surprising behaviour
in e.g. Turkish locale with "i" and "I") there are unexpected behaviours
when upper and lower casing non-ASCII characters.
For example it's sometimes not symmetric, e.g.:
"ẞ".toLowerCase() -> "ß"
"ß".toUpperCase() -> "SS"
In all the ExoPlayer usages we are either dealing with known-ASCII
strings (e.g. MIME types) or comparing against ASCII constant strings
anyway, so it seems easier to just use Guava's ASCII-only class in these
cases.
This change also includes some null-twiddling, because
Util.toLowerInvariant() is null tolerant, while Ascii.toLowerCase() is
not. Most of the usages were already non-null, and it was easy enough to
change the remaining ones to be so by simple reordering of statements.
I'll make an equivalent change for Util.toUpperInvariant() next.
PiperOrigin-RevId: 368419813
Previously, we had separate MSG_SET_SURFACE and
MSG_SET_VIDEO_DECODER_OUTPUT_BUFFER_RENDERER messages for
setting different types of supported output. Use of these
constants to switch between outputs during use of a player
was confusing because not all video renderers support both
message types.
To switch from VideoDecoderOutputBufferRenderer to a Surface,
it was sufficient just to send MSG_SET_SURFACE, since all
video renderers support this and clear any other output that
might be set. Conversely, to switch in the opposite direction,
just sending a MSG_SET_VIDEO_DECODER_OUTPUT_BUFFER_RENDERER was
not sufficient, because not all video renderers handle this
message to clear any previous output. Hence it was necessary to
explicitly clear a previously set surface using a separate
MSG_SET_SURFACE message. Passing two messages to switch the
output may prevent renderers from implementing the output switch
efficiently.
This change passes all outputs using a single message type, and
requires that all renderers treat unsupported outputs as though
null were passed (i.e., they clear any existing output). There
are some other miscellaneous improvements:
1. Non-surface outputs are now passed to onRenderedFirstFrame.
This fixes a bug in SimpleExoPlayer's onRenderedFirstFrame,
where previously it could not correctly equality check the
output corresponding to the event to its current output in
the VideoDecoderOutputBufferRenderer case.
2. Fix SimpleExoPlayer to report surface size changes for the
VideoDecoderOutputBufferRenderer case. Even though the
surface is rendered to indirectly in this case, we can still
query (and listen to changes to) the surface's size.
PiperOrigin-RevId: 368215850
We added a source that allows mixed placeholder and non-placeholder
periods, but have no way to denote that in the Timeline because the
placeholder flag only exists on Window level. This causes a bug if
the first item in a concatenation has a window-period offset and the
player can't detect whether it's still a placeholder or not.
Adding this flag to Period allows the player to detect this reliably.
In addition we need to make sure that re-resolving pending positions
only happens for the first placeholder period where the window-offset
can actually change. As all subsequent periods have to start at position
0, so they don't need to be re-resolved (and shouldn't).
PiperOrigin-RevId: 367171518
A TrackGroup must contain the same content in all Formats (except for
the quality, encoding etc). Verify that the language and role flags
are the same and log an error if don't match. Don't throw to avoid
breaking existing use cases that just happen to work by chance.
PiperOrigin-RevId: 365539240
The BasePlayer implementation of add/remove
Listener knows about Components.
As those are removed from the Player
interface, the implementation of those
methods needs to be moved down in Player
implementations.
This commit makes no functional change.
PiperOrigin-RevId: 364985291
Null was an alias for DEFAULT. Remove this for nullness
safety in the API.
The ExoPlayer implementation still checks for null and
replaces it by DEFAULT, so this is ABI compatible.
PiperOrigin-RevId: 364370017
The main user of the Util method is the bandwidth meter to set the
initial network type. If this is the first call to the
NetworkTypeObserver, then we should also allow the first update to
a known network type even if no reset on network type is activated.
The other uses are analytics listeners that check the network type
at certain events. This can just use the lookup method of the
NetworkTypeObserver.
PiperOrigin-RevId: 363670771
- Update the three `HttpDataSource` implementations to use the
Content-Range response header to determine when this is the
case. The Content-Range header is included when the status
code is 416. See [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416).
- Update `ByteArrayDataSource` to conform to the requirement.
- Update `DataSourceContractTest` to enforce the requirement.
PiperOrigin-RevId: 363642114
- SampleQueue.peek is replaced with SampleQueue.read with
FLAG_PEEK. This also exposes peek functionality through
SampleStream.
- Use of DecoderInputBuffer.isFlagsOnly is replaced with
FLAG_OMIT_SAMPLE_DATA. This flag can be used with or
without FLAG_PEEK, where-as previously the read position
would never be advanced for an isFlagsOnly buffer.
- formatRequired is replaced with FLAG_FORMAT_REQUIRED.
PiperOrigin-RevId: 363460105
This makes HLS playback less liable to become stuck if discontinuity
tags are inserted at different times across media playlists.
Issue: #8700
Issue: #8372
PiperOrigin-RevId: 362903428
Part of aligning HttpDataSource behavior will require adding
logic that's common across the DataSource implementations. This
change establishes a util class to house it, and moves a bit of
existing logic that's related and can be easily shared into it.
There is one small behavior change in this CL, which is that our
handling of Content-Range response headers can now parse the body
length if the "document size" part of the Content-Range is unknown,
for example "bytes 5-9/*". Previously the pattern we were matching
to required the "size" part to be set, for example "bytes 5-9/100",
despite the fact we don't need or use it.
PiperOrigin-RevId: 362396976
Adds a new Listener that extends all other listener.
This is part of the component flattening goal.
After components have been flattened in Player,
and clients transitioned, existing listeners will be deprecated.
PiperOrigin-RevId: 362287507
Includes fixes for the HTTP implementations, which previously
broke this contract specifically in the case when a server
responds to a range request with a HTTP 200 response. To fix
this case, skipping to the requested position is moved from
read() to open(). As a side effect, this nicely simplifies
CronetDataSource!
PiperOrigin-RevId: 359737301
The API is a lot more useful if apps can rely on the fact
that the gain is linear and applied to all channels.
This is already guaranty by AudioTrack and should be too
by any reasonable implementation.
PiperOrigin-RevId: 359706113
The concept of Renderers is not needed in the
Player interface. Move it to ExoPlayer.
This should not break most users as they use SimpleExoPlayer.
PiperOrigin-RevId: 359220977
- Ensure consistency between (Styled)PlayerControlView,
PlayerNotificationManager, TimelineQueueNavigator and
DefaultControlDispatcher.
- Handle the case where a live stream has ended when enabling previous
and next actions (window.isLive() is true and window.isDynamic is
false in that case)
#minor-release
PiperOrigin-RevId: 359063793
Assert that an exception is not thrown from DataSource.open
if the DataSpec's start position is valid but its end position
extends beyond the end of the data.
HTTP based DataSource implementations have no good way of
knowing when this is the case, so it makes sense to make this
the required behaviour, rather than requiring an exception to
be thrown or allowing both.
There are also use cases where the caller may want to use the
end position as an upper bound, without knowing for sure how
long the content is. An example of this use case is wanting to
pre-cache the first N bytes of a stream. This implies that any
exception should be thrown after reading to the end of the
data, rather than preemptively in open.
Issue: #7326
PiperOrigin-RevId: 359063721
When we add DRM pre-acquire support to SampleQueue, we'll dispatch
twice the number of acquire and release events. This is slightly
confusing, since there's the same number of
DrmSessionManager#acquireSession() calls.
We can mitigate this by only dispatching each acquire and release
event to at most one EventDispatcher.
This also changes the events fired when playing a stream with both audio
and video encrypted with the same keys (even without pre-acquisition).
Before: The EventDispatcher would see 2 aquires, 1 key load and 2
release events.
After: The EventDispatcher will see 1 acquire, 1 key load and 1 release.
PiperOrigin-RevId: 358804502
There are two different patterns we use at the moment:
1. Call both deprecated and non-deprecated method from call site with
no default method implementation body.
2. Use default method of non-deprecated method to call deprecated
method.
Pattern 1 is easier to reason about as it makes the calls more explicit,
so changing all usages of pattern 2 to pattern 1.
PiperOrigin-RevId: 358769803
This type is different to the selection reason, which is
dynamic (i.e., corresponds to the individual selected track,
which can change during playback). The static type is
exposed via TrackSelection, where-as the selection reason
will be internal to the core (i.e., player) module.
PiperOrigin-RevId: 357578201
It allows Bundleable classes throw a RuntimeException which is broader
than IAE. Now, Bundleable implementation may utilize checkNotNull for
brevity.
PiperOrigin-RevId: 357546375
It's used by the UI and mediasession modules. We may be able to move
it into the UI module if/when the mediasession module goes away.
PiperOrigin-RevId: 356734939
ControlDispatcher and DefaultControlDispatcher also need
to move to common for the UI module. As does PlaybackPreparer,
although that will be removed entirely in a future release.
PiperOrigin-RevId: 356467394
Also allow the player's prepared ad media period durations array to exceed the
length of the loaded ad URIs array, as it's possible for the player to buffer
an ad media period fully at the point where it's known that an ad is coming up
but its URI is still unknown.
#minor-release
PiperOrigin-RevId: 356249284