Unlike Assertions, the introduced method cannot be disabled and throws
a ParserException instead. This method is meant to replace regular
assertions (which throw RuntimeExceptions) which check input in the
parsing code.
PiperOrigin-RevId: 375085160
We need to avoid reading and skipping into preload chunks as they
may need to be discarded. The current code iterates over all chunks,
but this can be simplified by just checking the last chunk knowing
that the preload chunk must always be the last one.
As a result, we avoid calling getFirstSampleIndex on all chunks. This
is a bug since the method is not allowed to be called for chunks
that have been spliced in. This still leaves the smaller issue of
potentially calling this method for spliced-in preload chunks, which
will be solved separately.
Issue: #8937
#minor-release
PiperOrigin-RevId: 375053638
Preload chunks may still need to be discarded. However, we don't
currently support discarding spliced-in chunks. Thus, we need to
avoid loadng a preload chunk that needs to be spliced-in.
Issue: #8937
#minor-release
PiperOrigin-RevId: 374851661
This media source wraps another source and publishes a Timeline with
ads. The created MediaPeriods for ad and content are mapped back to
the original stream to allow seamless playback.
PiperOrigin-RevId: 374836091
There is a newly added condition to help advancing between SSAI ads
and content in case the ad group position or ad duration changed. The
condition currently doesn't check directly whether it's a SSAI
transition but relies on indrect signals. Making this more direct
helps to understand the purpose and avoid unintentional bugs where
this condition would apply in other cases too.
In addition, we need to exclude TextRenderer from the check because
its read position doesn't correspond to the actual decode position
since the decoding happens in the renderer itself (b/181312195).
PiperOrigin-RevId: 374835985
We can instead just save this information in MediaPeriodInfo, similar
to how we store whether the MediaPeriod is last in the timeline etc.
PiperOrigin-RevId: 374835918
It only covers MediaSession - MediaController
(Does not consider cases that either a legacy session or a legacy controller is involved)
Add PlayerInfo#Builder to clean it up.
PiperOrigin-RevId: 374785779
Notes:
- The only functional change is that createForRemote now assings ERROR_CODE_REMOTE_ERROR.
- createForSource still uses ERROR_CODE_UNSPECIFIED, even though it expects an
IOException. The reason for not using ERROR_CODE_IO_UNSPECIFIED is that the reason for
the error might not be IO. For example, malformed media, or BehindLiveWindowException,
which have non-IO error codes. So using UNSPECIFIED saves a later change in category.
PiperOrigin-RevId: 374390407
When working with SSAI ads, we need to easily convert positions between
the underlying stream and the media model that exposes ad groups. To
simplify this, we can add util methods (that are testable on their own).
In addition, we need an easy way to build AdPlaybackStates for SSAI
inserted ads. The metadata is obtained out-of-band and usually has the
ad group start and end times in the underlying stream only. Hence, we
also add a util method to add a new ad group based on this information.
PiperOrigin-RevId: 374369360
MediaSession default command state contains all
commands.
To avoid having to update MediaSession when a command
is added, allow to create a Commands.Builder that
starts with all commands.
PiperOrigin-RevId: 374183484
Make ForwardingPlayer implement Player and not extend BasePlayer so that
ForwardingPlayer forwards each Player method directly to the wrapped
Player instance.
PiperOrigin-RevId: 374161084
Fix bug where rubies and boutens are missing, tate-chu-yoko is rendered
incorrectly when SubtitleView.setApplyEmbeddedStyles(false). This method
should only affect styling elements and not remove any language features.
There are two main changes that need to be made:
1. Whenever we determine the next ad to play, we need to select a
server-side inserted ad even if it has been played already (because
it's part of the stream).
2. When the Timeline is updated in the player, we need to avoid changes
that would unnecessarily reset the renderers. Whenever a Timeline
change replaces content with a server-side inserted ad at the same
position we can just keep the existing MediaPeriod and also if the
duration of the current MediaPeriod is reduced but it is followed by
a MediaPeriod in the same SSAI stream, we can don't need to reset
the renderers as we keep playing the same stream.
PiperOrigin-RevId: 373745031
In Android 12 mutability flags have to be set on PendingIntents. If they are not, and the app targets Android 12, then the app will be crashed by the system.
PiperOrigin-RevId: 373427591
Content after ad groups currently always resumes at the ad break position (unless
overridden by a seek or similar). In some cases, media inserting ads wants to
specify an offset after the ad group at which playback should resume. A common
example is a live stream that inserts an ad and then wants to continue streaming
at the current live edge.
Support this use case by allowing ad groups to specify a content resume offset
and making sure that the content start position after the ad group uses this offset.
PiperOrigin-RevId: 373393807
NAT will block off incoming UDP connection because the router has no knowledge
of the necessary port mapping (the mapping is never set up because UDP is
connectionless).
The end result is, the UDP socket to receive RTP data will timeout. After the
`SocketTimeoutException` is caught, the following takes place to try streaming
with TCP (or, RTP over RTSP).
- `RtspClient` sends TEARDOWN to tear down the current session.
- `RtspClient` re-connect to the RTSP server.
- `RtspMediaPeriod` cancels all loading `RtpDataLoadables` (that are using UDP)
- `RtspMediaPeriod` constructs new `RtpDataLoadables` that use
`TransferRtpDataChannel`, and starts loading.
- Once the `RtpDataLoadables` are up and running, we are ready to receive.
`RtspClient` sends the SETUP requests.
- The rest of the flow is unchanged.
#minor-release
PiperOrigin-RevId: 373310774
The player already supports changing durations of periods and ads.
The only thing not yet supported is a change in ad break positions
which changes the duration of clipped content ending in an ad break.
Adding support for this requires updating the end position in
MediaPeriodInfo and changing the clip end position of the respective
ClippingMediaPeriod.
Issue: #5067
PiperOrigin-RevId: 373139724
RTSP interleaving enables RTP packets to be sent using RTSP's TCP connection.
The interleaving RTSP messages contain binary data only and always start with a
'$'. Normal RTSP messages contain line breaks (CRLFs) that indicate complete
lines.
#minor-release
PiperOrigin-RevId: 372990181
The method to handle Timeline updates currently uses
isAd() || isPlaceholder()
to trigger two things:
1. Using the existing requested content position as the content
position.
2. Re-resolving the content position from window to period in case
it changed since the last update.
The condition is correct for case (1) because ads must use the content
position (and not the position in the ad) and a placeholder period must
keep using the requested content position as well until the media
information is no longer a placeholder.
However, case (2) only needs to be done if the content position is
C.TIME_UNSET (to start at the default position) OR if the period is
still a placeholder and we want to re-resolve the position.
The case where re-resolution shouldn't be done is for ads with a non-
placeholder period and a concrete content position. This likely only
affects ads in live stream where the content position is currently
moving with the live stream instead of staying where it is.
PiperOrigin-RevId: 372929439
- Don't deprecate methods not deprecated in the base class and that
could one day be useful.
- Better document deprecation of other methods.
#minor-release
PiperOrigin-RevId: 372919080
The existing code results in flaky tests, where sometimes the write
fails (with "EPIPE (broken pipe)") and the exception propagates out
and causes the test to never complete and time out.
Swallowing the exception resolves this flakiness.
#minor-release
PiperOrigin-RevId: 372909415
First intention to support parsing MPEG-H 3D Audio in ExoPlayer is to
take advantage of parsing capability from MediaParser API in AOSP.
Just with this change ExoPlayer does't support decoding MPEG-H 3D Audio
but can support decoding either by adding decoder with an extension or
by using Android OS which has decoder capability with MediaCodec API.
It was originally introduced because it was guaranteed to be non-null
unlike the inherited field. But ExoPlaybackException.cause has been
nullable for some time, so there's no gain in not using the inherited
field.
PiperOrigin-RevId: 372329740
Also make future similar issues less likely by adding isPlaceholder
to the set method of Period (in case forwarding Timeline
implementations use this instead of just updating values selectively)
#minor-release
PiperOrigin-RevId: 372138523
Issues have been identified around
offload gapless track transitions blocking
the track timestamp.
Until those issues are root caused, this settings
allows to disable gapless offload completely.
PiperOrigin-RevId: 372081545
In RtpDataLoadable.load, the second UDP data source is opened on the port we
specify. If the port is already in use, a BindException is thrown.
#minor-release
PiperOrigin-RevId: 371319522
All `add*Listener` and `add*Output` methods are
deprecated in favor of `addListener`.
As for the class themselves `VideoListener` and
`AudioListener` are not used internaly by ExoPlayer,
`VideoRendererEventListener`
and `AudioRendererEventListener` are use in their
place.
As a result `VideoListener` and `AudioListener`
can be deprecated in favor `Listener`.
On the other hand `TextOutput` and `MedataOutput`
are used both in the player interface and internally in
renderers.
This means that those class can't be deprecated.
There usage in the public interface are indirectly
deprecated as their is no way to use them without
using the deprecated `add*Output`.
Thus it's not an issue that the class themselves are
not deprecated.
#minor-release
PiperOrigin-RevId: 371318268
Imported from GitHub PR https://github.com/google/ExoPlayer/pull/8858
Fix bug in text alignment inheritance where child does not correctly inherit ancestor's setting
@icbaker
Merge 70eb4bceb73b3f07e2f8d545b4fa7961189ac52a into 45616f916b
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/ExoPlayer/pull/8877 from dlafayet:multirowalign-cue d942b50a40525fea5d11b35a33d3bbc512550960
PiperOrigin-RevId: 371306966
This change adds an API in the ForwardingPlayer to disable commands.
This is affecting what Player.isCommandAvailable() returns as
well as what is being advertised from the
EventListener.onAvailableCommandsChanged() callback.
For the callback case, the ForwardingPlayer needs to intercept the
callback. It does so by wrapping registered EventListener and Listener
instances, which resulted in some boiler-plate code. In addition, there
is logic on the wrapped listeners to avoid triggering a queued callback
if all listeners have been removed in the meantime. This includes the
case where new listeners are added while callbacks scheduled for the
removed listeners are still pending.
PiperOrigin-RevId: 371139703
Move VideoSize in the common module and have the Player return it.
`Listener` and `AnalyticsListener` `onVideoSizeChanged` are updated
with the old method deprecated.
`VideoRendererEventListener.onVideoSizeChanged` was also migrated to
`VideoSize` but the old method is removed, not deprecated.
This is because:
- apps calling/listening to this method is a rare and niche use-case.
- it would introduce hard to diagnostic issues where if only the caller
or the callee is updated to use the new method, the event will be lost.
This doesn't occur with the other 2 listeners as the caller is always
in ExoPlayer library and was updated to call both the old and new methods.
VideoSize is used everywhere except in `Format` as this would lead to
too much refactoring and backward compatibility breakage for little gain.
#minor-release
PiperOrigin-RevId: 371087419
Rating class should be in the same module as MediaMetadata.
Tested:
$ ./gradlew --stacktrace :exo-library-common:tDUT
$ ./gradlew --stacktrace :media2-session:tDUT
$ ./gradlew --stacktrace :media2-session-vct-current:cAT
PiperOrigin-RevId: 370902917
Session pre-fetching caused this ordering assertion to no longer be
always true. It should have been removed in
795ddfee40
#minor-release
PiperOrigin-RevId: 370880530
1. Clarify intention of getAdGroupIndexForPositionUs and
getAdGroupIndexAfterPositionUs. Both methods are used for very
specific but different purposes and encode the logic of which
ads should be played at which time, so it's helpful to clarify
this in the documentation as well.
2. Change one usage getAdGroupIndexForPositionUs to use the already
existing nextAdGroupIndex. This is also more in line with the
intended usage as clarified in step 1.
3. Update MediaPeriodQueueTest for updateQueuedPeriods to only
look for duration changes in future periods, not in the
current one, because that's not handled MediaPeriodQueue for ads
and the test is just passing by chance now. Also remove wrong
advancePlaying() calls that are already implicitly included in
the preceding enqueueNext() call.
4. Fix a minor bug where post-roll ads are not checked whether they
are played already before using them as the next ad group. Also
added a test covering this case.
#minor-release
PiperOrigin-RevId: 370664131
Previously loadingFinished will never be set to true because it started in
false, and we are and'ing it with `canceled`.
#minor-release
PiperOrigin-RevId: 370662456
The ForwardingPlayer implements the Player interface and forwards all
operations to another Player instance. Apps will be able to override
methods of ForwardinPlayer in order to modify and/or suppress specific
Player funcionalities.
This commit introduces the ForwardingPlayer which simply forwards all
Player operations to another Player instance. In follow-up changes,
the ForwardingPlayer will be extended so that it eventually reaches the
feature-set offered by ControlDispatcher.
PiperOrigin-RevId: 370653167
Release is a life cycle operation that should only be called when
the player is no longer needed. It's linked to the player lifecycle
and thus very different from prepare/stop.
As a result, it should not be in the same command.
Additionally it's not clear if remote players will ever need to call release,
as the player creator is best candidate to release it.
As a result the release operation doesn't have a use case for a command.
A release command can be added later if a need is identified.
PiperOrigin-RevId: 370649214
We remove other source related listeners if a MediaSource is
removed from the playlist or the player/source is released.
This isn't currently done for the DRM listener.
#minor-release
PiperOrigin-RevId: 370482571
MediaCodecRenderer is calling its protected methods
resetCodecStateForRelease() and resetCodecStateForFlush() from its
constructor. Classess that override the methods (eg.
DebugMediaCodecVideoRenderer) need to checks if the methods
are called from the superclass constructor thus their members are not
initialized yet.
With this change, the MCR constructor does not call the two
methods and sets the respective state directly on its fields.
PiperOrigin-RevId: 370445978
Remove references to deprecated methods. I didn't replace the DRM info
with references to non-deprecated methods because I'm not sure it
belongs at class level. The methods themselves are already documented
in detail.
PiperOrigin-RevId: 370421087
* @Nullable is not a TYPE_USE annotation, so should appear before any modifiers and after Javadocs.
(see go/java-style#s4.8.5-annotations)
This CL looks good? Just LGTM and Approve it!
This CL doesn’t look good? This is what you can do:
* Suggest a fix on the CL (go/how-to-suggest-fix).
* Revert this CL, by replying "REVERT: <provide reason>"
* File a bug under go/error-prone-bug for category ErrorProneStyle if the change looks generally problematic.
* Revert this CL and not get a CL that cleans up these paths in the future by
replying "BLOCKLIST: <provide reason>". This is not reversible! We recommend to
opt out the respective paths in your CL Robot configuration instead:
go/clrobot-opt-out.
This CL was generated by CL Robot - a tool that cleans up code findings
(go/clrobot). The affected code paths have been enabled for CL Robot in //depot/google3/java/com/google/android/libraries/exoplayer/METADATA which is reachable following include_presubmits from //depot/google3/third_party/java_src/android_libs/media/METADATA.
Anything wrong with the signup? File a bug at go/clrobot-bug.
#codehealth
PiperOrigin-RevId: 370377751
Add method getAvailableCommands() in Player interface to return
the available commands. Method isCommandAvailable() moved to
BasePlayer since it can be implelented by calling
getAvailableCommands().
PiperOrigin-RevId: 370059328
A subsequent change will make the UI module access
SphericalGLSurfaceView and VideoDecoderGLSurfaceView
using reflection, now we're at the point where we only
need to reflect the constructors.
PiperOrigin-RevId: 369630102
*** Original commit ***
Rollback of e60609e344
*** Original commit ***
Prevent creation of new sessions if the Timeline is empty.
We currently create sessions based on the placeholder window
index. This shouldn't be needed as we now set a non-empty
timeline as soon as the first MediaItem...
***
PiperOrigin-RevId: 369609523
The protected visibility causes problems in Kotlin (Issue: #8830) and
also prevents a subclass of AdaptiveTrackSelection.Factory that isn't
nested inside a subclass of AdaptiveTrackSelection (in both Java and
Kotlin).
#minor-release
PiperOrigin-RevId: 369468841
*** Original commit ***
Prevent creation of new sessions if the Timeline is empty.
We currently create sessions based on the placeholder window
index. This shouldn't be needed as we now set a non-empty
timeline as soon as the first MediaItem is added to the playlist.
Once this check is part of the session manager, we can also remove
the equivalent workarounds from the various code integrations.
***
PiperOrigin-RevId: 369452067
This method shouldn't be used anymore since the thread enforcement
is the default already. We still keep it for now to ease the transition
for apps that use ExoPlayer on multiple threads and want to temporarily
disable the enforcement while the threading problems are fixed.
PiperOrigin-RevId: 369440789
We currently create sessions based on the placeholder window
index. This shouldn't be needed as we now set a non-empty
timeline as soon as the first MediaItem is added to the playlist.
Once this check is part of the session manager, we can also remove
the equivalent workarounds from the various code integrations.
PiperOrigin-RevId: 369432853
The original cl has been fixed by not implementing
VideoListener but Player.Listener in
StyledPlayerView.
VideoFrameMetadataListener and CameraMotionListener are still part
of the Player interface as a good way to break the UI dependency
on them has not yet been finalised.
PiperOrigin-RevId: 369417682
This change moves the responsibility of creating, configuring and starting the MediaCodec from the MediaCodecRender to the MediaCodecAdapter.Factory.
This move allows ExoPlayer's client to decide how and when codecs are created and/or reused.
To allow the move, this CL replaces MediaCodecRenderer.ConfigureCodec with MediaCodecRenderer.getCodecConfiguration
PiperOrigin-RevId: 369273887
*** Original commit ***
Move VideoComponent in ExoPlayer
VideoFrameMetadataListener and CameraMotionListener are still part
of the Player interface as a good way to break the UI dependency
on them has not yet been finalised.
***
PiperOrigin-RevId: 369194309
* Prefer instanceof to getClass when implementing Object#equals.
(see http://go/bugpattern/EqualsGetClass)
This CL looks good? Just LGTM and Approve it!
This CL doesn’t look good? This is what you can do:
* Suggest a fix on the CL (go/how-to-suggest-fix).
* Revert this CL, by replying "REVERT: <provide reason>"
* File a bug under go/error-prone-bug for category ErrorProneFragileCode if the change looks generally problematic.
* Revert this CL and not get a CL that cleans up these paths in the future by
replying "BLOCKLIST: <provide reason>". This is not reversible! We recommend to
opt out the respective paths in your CL Robot configuration instead:
go/clrobot-opt-out.
This CL was generated by CL Robot - a tool that cleans up code findings
(go/clrobot). The affected code paths have been enabled for CL Robot in //depot/google3/java/com/google/android/libraries/exoplayer/METADATA which is reachable following include_presubmits from //depot/google3/third_party/java_src/android_libs/exoplayer/METADATA.
Anything wrong with the signup? File a bug at go/clrobot-bug.
#codehealth
PiperOrigin-RevId: 369180513
VideoFrameMetadataListener and CameraMotionListener are still part
of the Player interface as a good way to break the UI dependency
on them has not yet been finalised.
PiperOrigin-RevId: 368863829
Before this change:
- SimpleExoPlayer.prepare(mediaSource) ended up calling
ExoPlayerImpl.setMediaSourcesInternal() with startWindowIndex=0 and
resetToDefaultPosition=false.
- ExoPlayerImpl.prepare(mediaSource) ended up calling
ExoPlayerImpl.setMediaSourcesInternal() with
startWindowIndex=C.INDEX_UNSET and resetToDefaultPosition=true.
This was functionaly equivalent but a bit confusing.
#minor-release
PiperOrigin-RevId: 368818143
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
This is necessary to migrate apps which are using
ExoPlayer.Builder.experimentalSetForegroundModeTimeoutMs
from ExoPlayerImpl to SimpleExoPlayer.
PiperOrigin-RevId: 368657557
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
If this condition isn't true, the player may enter a cycle of discarding
and reloading the same format. As minDurationToRetainAfterDiscard is a
parameter likely left at its default, and minDurationForQualityIncrease
is likely adjusted more often, we correct the value in the problematic
case and log a warning instead of asserting it outright to prevent
unnecessary app breakages.
Issue: #8807
PiperOrigin-RevId: 368207417