While investigating a different test failure on a pending change I
noticed that sometimes the "testAddSessions_removedWhenClose" session
was being released before it could be fully connected - and this
results in a failure like:
```
expected not to contain: androidx.media3.session.MediaSession@50a9ef1
but was : [androidx.media3.session.MediaSession@50a9ef1, androidx.media3.session.MediaSession@3a6bac]
at androidx.media3.session.MediaSessionServiceTest.addSessions_removedWhenReleased(MediaSessionServiceTest.java:376)
```
It also shows up in the logs like:
```
MediaController future failed (so we couldn't release it)
...
Caused by: java.lang.SecurityException: Session rejected the connection request.
```
Adding some debug logging revealed that the `session.release` call
posted to the test thread was happening before the call to
`MediaSessionStub.connect` on the main thread (this is triggered deep
in prod media3 session logic).
PiperOrigin-RevId: 563431265
This change ensures that a different package is used for
`test_session_current/src/main:support_app` and
`test_session_current/src/androidTest:test_app` - previously they used
the same package which was unusual (and possibly led to some confusing
behaviour).
PiperOrigin-RevId: 563051818
The `controller.prepare()` call can trigger the callback `onPrepare()`, however, this will count down the latch by one before the callback `onStop()` is triggered.
PiperOrigin-RevId: 560988209
There are multiple problems in the test:
1. The controller must run on the main thread due to the Player
interface requirement to add surfaces on the thread their
callbacks will be called on.
2. This test made assertions about an expected callback that
aren't true. Setting an anonymous surface will not result in
a size change callback because the size stays unknown.
But clearing a surface (even if never set) ensures the returned
size is guaranteed to be zero.
PiperOrigin-RevId: 559080905
This changes the default logic of shouldShowPlayButton to show a play
button while the playback is temporarily suppressed. This helps to
provide better UI feedback to the fact that playback stopped and
provides a quick way for users to override the suppression and attempt
to restart playback.
Some apps may want to keep the legacy behavior depending on their app's
needs. Hence, we also add a config parameter to set this behavior both
in MediaSession and our default UI components.
Issue: google/ExoPlayer#11213
PiperOrigin-RevId: 557129171
Unlike ExoPlayer, when play/pause is called on MediaController, the playback suppression reason is set to default causing a change in it and subsequent callbacks on the Player.Listener.
PiperOrigin-RevId: 548088931
This change also marks the buttons of the custom layout as
enabled/disabled according to available commands in the controller.
Accordingly, `CommandButton.Builder.setEnabled(boolean)` is deprecated
because the value is overridden by the library.
Issue: androidx/media#38
#minor-release
PiperOrigin-RevId: 547272588
This removes some stack traces in unit tests when a
`RemoveMediaController` was created with `waitForConnection=false`
in which case the missing controller in the
`MediaControllerProviderService` caused a `NullPointerException`.
PiperOrigin-RevId: 546795181
MP4 edit lists sometimes ask to start playback between two samples.
If this happens, we currently change the timestamp of the first
sample to zero to trim it (e.g. to display the first frame for a
slightly shorter period of time). However, we can't do this to audio
samples are they have an inherent duration and trimming them this
way is not possible.
#minor-release
PiperOrigin-RevId: 543420218
`MediaControllerImplBase` has 2 methods for updating listeners about `PlayerInfo` changes - `updatePlayerInfo` (for masking the state) and `onPlayerInfoChanged` (when communicating with the session). There is a set number of listener callbacks related to `PlayerInfo` updates and both methods should go through the same control flow (whether we know that masking will ignore most of them or not).
A unified method `notifyPlayerInfoListenersWithReasons` encapsulates only the shared logic of 2 methods - listeners' callbacks. This ensures that both methods call them in the same order and none are missed out.
PiperOrigin-RevId: 542587879
*** Original commit ***
Rollback of 2a6f893fba
*** Original commit ***
Set video size to 0/0 when video render is disabled
In terms of MCVR wi...
***
PiperOrigin-RevId: 540525069
Currently, the implementation of `MediaControllerImplBase` differs from `ExoPlayerImpl`. The listeners of the former are notified of player error changes only in `onPlayerInfoChanged` and not `updatePlayerInfo` (masking method). Whereas `ExoPlayerImpl` has one unified method - `updatePlaybackInfo` - which sends the events to all the available listeners.
This change fixes the lack of 2 particular callbacks - `onPlayerErrorChanged` and `onPlayerError`, however, there might be more differences. Ideally, there should be a unified method for oldPlayerInfo/newPlayerInfo comparison-update-notify-listeners flow.
Issue: androidx/media#449
#minor-release
PiperOrigin-RevId: 539961618
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it.
However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information.
Issue: androidx/media#282
#minor-release
PiperOrigin-RevId: 537993460
*** Original commit ***
BEGIN_PUBLIC
Set video size to 0/0 when video render is disabled
In terms of MCVR with a `VideoRendererEventListener`, the video size is set to
0/0 right after `onVideoDisabled()` is called and is set to the actual size as
soon as the video size is known after 'onVideoEnabled()`.
For ExoPlayer and in terms of the `Player` interface, `Player.getVideoSize()`
returns a video size of 0/0 when `Player.getCurrentTracks()` does not support
`C.TRACK_TYPE_VIDEO`. This is ensured by the masking behavior
***
PiperOrigin-RevId: 537938947
This change moves the default logic into the actual Player
implementations, but does not introduce any behavior changes compared
to addMediaItems+removeMediaItems except to make the updates "atomic"
in ExoPlayerImpl, SimpleBasePlayer and MediaController. It also
provides backwards compatbility for cases where Players don't support
the operation.
Issue: google/ExoPlayer#8046
#minor-release
PiperOrigin-RevId: 534945089
This is a follow-up to 99dac0be0f where we made the same change in
ExoPlayerImpl and SimpleBasePlayer, but for consistency it makes
sense to also update the masking code in MediaControllerImplBase to
assume the same logic.
Note: MediaControllerImplLegacy already handles this case via
setMediaItems and doesn't need to be updated further.
#minor-release
PiperOrigin-RevId: 534038759
MediaControllerImplBase currently drops the pending initial seek
position when a user sets an empty playlist.
When seeking in empty playlists and setting new empty playlists,
the class also drops the the period index (and wrongly assigns zero
instead of the windowIndex).
#minor-release
PiperOrigin-RevId: 534035046
In terms of MCVR with a `VideoRendererEventListener`, the video size is set to
0/0 right after `onVideoDisabled()` is called and is set to the actual size as
soon as the video size is known after 'onVideoEnabled()`.
For ExoPlayer and in terms of the `Player` interface, `Player.getVideoSize()`
returns a video size of 0/0 when `Player.getCurrentTracks()` does not support
`C.TRACK_TYPE_VIDEO`. This is ensured by the masking behavior of
`ExoPlayerImpl` that sets an empty track selection result when the playing
period changes due to a seek or timeline removal.
When transitioning playback from a video media item to the next, or when
seeking within the same video media item, the renderer is not disabled.
#minor-release
PiperOrigin-RevId: 533479600
This is a pre-requisite for the Android Studio upgrade assistant to
upgrade from AGP 7.2.2 to 8.0.1, otherwise it fails and complains
this is missing.
Issue: androidx/media#409
PiperOrigin-RevId: 533463246
The periodic updates are only meant to happen while we are in the
same period or ad. This was already guaranteed except for two cases:
1. The Player in a session has updated its state without yet calling
its listeners
2. The session scheduled a PlayerInfo update that hasn't been sent yet
... and in both cases, the following happened:
- The change updated the mediaItemIndex to an index that didn't exist
in a previous Timeline known to the Controller
- One of the period position updates happened to be sent at exactly
this time
This problem can be avoided by only scheduling the update if we are
still in the same period/ad and haven't scheduled a normal PlayerInfo
update already.
Since new MediaControllers may still connect to old sessons with this
bug, we need an equivalent change on the controller side to ignore such
buggy updates.
PiperOrigin-RevId: 532089328
When a `MediaButtonReceiver` is found in the manifest, the library
can implement the contract of SystemUI to signal that the app wants
a playback resumption notification to be displayed.
And, vice versa, if no `MediaButtonReceiver` is in the manifest, the
library will signal to not show the notification after the app has been
terminated.
#minor-release
PiperOrigin-RevId: 531516023
The session activity is already sent to the controller with the
`ConnectionState` when it connects. This change adds the ability to update the
activity.
This allows an app to change the intent that is used to open an activity
for the notification. An app is likely to want to change the session activity
just before the session is released. This allows to use a different activity or
more importantly the back stack of the activity for while the app is running
and when used for the playback resumption notification.
PiperOrigin-RevId: 530627102
The media button has API support with
`Callback.getPlaybackResumption()` that apps need to override to provide
a playlist to resume playback with.
Issue: androidx/media#167
PiperOrigin-RevId: 529495845
This is a helper method that can used to obtain information about
the controller that is currently calling a Player method.
PiperOrigin-RevId: 527268994
This simplifies the addition of new fields in the future.
Also do some misc clean up for the volume limit values:
- Add some documentation to mention assumed defaults
- Add the IntRange annotations to match the ones we have in Player
already
- Mention the limits in the relevant Player methods
- Avoid bundling default values
- Improve range checks for masking in MediaController
PiperOrigin-RevId: 526029619
This is a bug currently, where commands are created once but never
updated again if the actions in MediaSessionCompat are changed.
PiperOrigin-RevId: 525999084
This check was a leftover from when the metadata was generated from
the MediaItem only. Since we moved to the actual MediaMetadata fields,
the check is completely unnecessary and prevents accessing metadata
when the GET_CURRENT_MEDIA_ITEM command is not available.
#minor-release
PiperOrigin-RevId: 524837587
The overrides specified by a MediaController may not use the exact
same TrackGroup instances as known to the Player because the groups
have been bundled to and from the controller. This bundling may
alter the instance slightly depending on the version used on each
side of the communication and the fields set (e.g. Format.metadata
is not supported for bundling).
This issue can be solved by creating unique track group ids for
each group on the session side before bundling. On the way back,
the groups in the track selection parameters can be mapped backed
to their original instances based on this id.
#minor-release
Issue: androidx/media#296
PiperOrigin-RevId: 523986626
Previously, ExoPlayerImpl had volume flags hardcoded to SHOW_UI, but now the developer can choose what happens on volume change. The old methods have been deprecated.
PiperOrigin-RevId: 523974358
The setter command is only used for setPlaylistMetadata and can
be named COMMAND_SET_PLAYLIST_METADATA. The getter commnad is
used to access getMediaMetadata and getPlaylistMetadata and can
be better named COMMAND_GET_METADATA to reflect this usage.
PiperOrigin-RevId: 523673286
If the duration is reported in MediaMetadataCompat, it should
also be set in the QueueTimeline to match controller.getDuration()
PiperOrigin-RevId: 522022953
MediaItems are not meant to be unique in a playlist. If a legacy
session publishes multiple items that get converted to equal MediaItems,
the current code fails because we look up queue ids in a Map (that
doesn't allow duplicate entries).
Fix this by storing a simple list of items with additional data.
#minor-release
Issue: androidx/media#290
PiperOrigin-RevId: 521993802
This wasn't added so far because releasing is always allowed from a
MediaController (as it just releases the connection, not the session
player). But Player instances can be created for other purposes and
the receiver of a Player instance should not always be allowed to
call release if it doesn't own the player resource.
PiperOrigin-RevId: 519121122
This change includes 3 things:
- when the legacy media session is created, FLAG_HANDLES_QUEUE_COMMANDS
is advertised if the player has the COMMAND_CHANGE_MEDIA_ITEMS
available.
- when the player changes its available commands, a new
PlaybackStateCompat is sent to the remote media controller to
advertise the updated PlyabackStateCompat actions.
- when the player changes its available commands, the legacy media
session flags are sent accoridingly: FLAG_HANDLES_QUEUE_COMMANDS is
set only if the COMMAND_CHANGE_MEDIA_ITEMS is available.
#minor-release
PiperOrigin-RevId: 506605905
This change fixes an issue that can be reproduced when
a controller `onConnect` creates a `QueueTimeline` out
of the state of a legacy session and then `prepare` is called.
`activeQueueItemId`, `metadata` and the `queue` of the legacy
session are used when a `QueueTimeline` is created. The change
adds unit tests to cover the different combinatoric cases these
properties being set or unset.
PiperOrigin-RevId: 505731288
Added onSetMediaItems callback listener to allow the session to modify/set MediaItem list, starting index and position before call to Player.setMediaItem(s).
Added conditional check in MediaSessionStub.setMediaItem methods to only call player.setMediaItem rather than setMediaItems if player does not support COMMAND_CHANGE_MEDIA_ITEMS
PiperOrigin-RevId: 503427927
We stop estimating new position when pausing until we
receive a new position from the player. However, this
means that we will continue to return a possible stale
previous position. Updating the current position before
pausing solves this issue.
PiperOrigin-RevId: 503153982
We currently only document it for the getCurrentMediaItem(), but
the command was always meant to cover all information about the
current media item and the position therein.
To correctly hide information for controllers, we need to filter
the Timeline when bundling the PlayerInfo class if only this
command is available.
PiperOrigin-RevId: 503098124
The migration strategy is to deprecate `androidx.media3.session.BitmapLoader` and copy the file into common since BitmapLoader is a public interface that apps could be relying on.
PiperOrigin-RevId: 501266521
The period updates were introduced to ensure the buffered position is
updated regularly and that any playback position drift is corrected.
None of these updates need to happen while the player is paused or
not loading and we can avoid the constant binder interactions.
PiperOrigin-RevId: 496329800
Some Player methods operate relative to existing indices in the
playlist (add,remove,move,seek). As these operations may be issued
from a place with a stale playlist (e.g. a controller that sends
a command while the playlist is changing), we have to handle out-
of-bounds indices gracefully. In most cases this is already
documented and implemented correctly. However, some cases are not
documented and the existing player implementations don't handle
these cases consistently (or in some cases not even correctly).
PiperOrigin-RevId: 495856295
Some Player methods like getting the Looper and adding listeners
were always allowed to be called from any thread, but this is
undocumented. This change makes the threading rules of these
methods more explicit.
Removing listeners was never meant to be called from another thread
and we also don't support it safely because final callbacks may
be triggered from the wrong thread. To find potential issues, we
can assert the correct thread when releasing listeners.
Finally, there is a potential race condition when calling addListener
from a different thread at the same time as release, which may lead to
a registered listener that could receive callbacks after the player is
released.
PiperOrigin-RevId: 493843981
The folder type has a mix of information about the item. It shows
whether the item is browsable (type != FOLDER_TYPE_NONE) and
which Bluetooth folder type to set for legacy session information.
It's a lot clearer to split this into a boolean isBrowsable and
use the existing mediaType to map back to the bluetooth folder type
where required.
folderType is not marked as deprecated yet as this would be an API
change, which will be done later.
PiperOrigin-RevId: 493544589
This allows legacy media controllers and browsers to access this
information and legacy sessions and browser services to set this
information.
PiperOrigin-RevId: 492414716
This change includes a change in the `IMediaController.aidl` file and needs
to provide backwards compatibility for when a client connects that is of an older or
newer version of the current service implementation.
This CL proposes to create a new AIDL method `onPlayerInfoChangedWithExtensions`
that is easier to extend in the future because it does use an `Bundle` rather than
primitives. A `Bundle` can be changed in a backward/forwards compatible way
in case we need further changes.
The compatibility handling is provided in `MediaSessionStub` and `MediaControllerStub`. The approach is not based on specific AIDL/Binder features but implemented fully in application code.
Issue: androidx/media#102
#minor-release
PiperOrigin-RevId: 490483068
The direct executor is not the proper way to determine on what thread to run the
`Future.Listener` and the `MediaControllerCreationListener` because the listener
may call the controller passed as argument which must happen on the same thread
that built the controller. This change makes sure this is the case.
PiperOrigin-RevId: 490478587
This avoids that apps have to depend on the legacy compat support
library when they want to make this conversion.
Also add a version to both helper methods that takes a Looper to
give apps the option to use an existing Looper, which should be
much faster than spinning up a new thread for every method call.
Issue: androidx/media#171
PiperOrigin-RevId: 490441913
When receiving the `onTimelineChanged` callback, we convert the timeline to the list of `QueueItem`s, where decoding a bitmap is needed for building each of the `QueueItem`s. The strategy is similar to what we did in <unknown commit> for list of `MediaBrowserCompat.MediaItem` - set the queue item list until the bitmaps decoding for all the `MediaItem`s are completed.
PiperOrigin-RevId: 490283587
When we currently call SessionToken.createSessionToken with a legacy
token, we call the package manager to get the process UID. This
requires visiblity to the target package, which may not be available
unless the target runs a service known to the controller app.
However, when connecting to a Media3, this UID doesn't have to be
known, so we can move the call closer to where it's needed to
avoid the unncessary visibility check.
In addition, a legacy session may reply with unknown result code
to the session token request, which we should handle as well.
One of the constructor can be removed since it was only used from
a test.
PiperOrigin-RevId: 489917706
* Transforms the `ListenableFuture<LibraryResult<MediaItem>>` and `ListenableFuture<LibraryResult<List<MediaItem>>>` to `ListenableFuture<MediaBrowserCompat.MediaItem>` and `ListenableFuture<List<MediaBrowserCompat.MediaItem>>`, and the result will be sent out when `ListenableFuture` the `MediaBrowserCompat.MediaItem` (or the list of it) is fulfilled.
* Add `artworkData` to the tests in `MediaBrowserCompatWithMediaLibraryServiceTest`.
PiperOrigin-RevId: 489205547
The MediaControllerImplBase listener invocations currently use the
class member state that can change if one of the listener method
implementations changes the state recursively.
Updating the listener invocations to use a final local variable
ensures all listeners get consistent updates.
PiperOrigin-RevId: 487503373
Creating the PlaybackStateCompat from a media3 Player state is done
already by the MediaSessionConnector (and used widely). The media3
session module should set the same states under the same circumstances
to ensure compatiblity and consistency.
PlaybackStateCompat changes made in media3 session:
- Use STATE_STOPPED when player is ended instead of STATE_PAUSED
- Use STATE_PLAYING when playback is suppressed temporarily.
- Set the playback speed to 0 if the player is not playing.
- Add extras for mediaId and user-set playback speed.
Part of the problem was that Player.isPlaying() was used to check
the state. Unfortunately, MockPlayer.isPlaying() is implemented in
a way that makes it hard to test these changes, because the value
is set independently of playbackState, playWhenReady and suppression
reason. To be able to write consistent, logical tests, this change
also removes the independent setting of isPlaying in MockPlayer to
align it better with a real player. This requires to update some
other tests to use alternative methods.
PiperOrigin-RevId: 487500859
Accepting a PlayerInfo while the MediaController is masking its state
means we are reverting all masking changes we've made earlier. This
only makes sense if the update already contains the masked operation.
If multiple operations are in flight (or are sent from the session
while they are in flight), we need to wait until all of them are
handled before accepting new updates.
In cases where a new update from the session excludes the Timeline
and the masked state is incompatible with the new update, we also
risk an exception if we accept the update too early.
PiperOrigin-RevId: 487266899
This is the follow-up commit where the onEvents callback
raised by MediaController contains the missing events, for the
case where MediaController is connected to a legacy MediaSession.
#minor-release
PiperOrigin-RevId: 487231996
The method getCurrentPosition() may return a lesser position during pause than the previous retrieved value due to ipc call delay in playerInfo update. Users see track position jump backwards at pause. Fixed to return last estimated position while paused if have not received updated playerInfo. Code is deduped to point getContentPosition() to getCurrentPosition() when !isPlayingAd.
PiperOrigin-RevId: 486617341
* Add `Listener` in `MediaSession` with method `onNotificationRefreshRequired(MediaSession)`.
* Add `MediaSessionService` as the listener of the `MediaSession` when `MediaSession` is added to `MediaSessionService`
* Load bitmap when update metadata in `MediaSessionLegacyStub` and call `onNotificationRefreshRequired` when bitmap asynchronously arrives.
PiperOrigin-RevId: 485376145
This root extra needs to be set by apps manually in media1 and we
can do that automatically in Media3 based on the available session
commands.
#minor-release
PiperOrigin-RevId: 484286833
In Media3 there is the useful concept of connection hints that a
client can set when building the session and that are sent to the
service and passed to the `Callback.onConnect()` method when the
browser connects.
These connection hints are then included in the `ControllerInfo`
object that later will be passed to every callback method and the
implementor can then take decisions specific to these connection
hints.
These connection hints are not available in media1. However, when
an app creates a `MediaBrowserCompat` object, the constructor takes
a rootHint object that is sent to
`MediaBrowserServiceCompat.onGetRoot()`.
This change uses the browser rootHints as the connection hints when
creating the `ControllerInfo` for legacy browsers and makes them
available to the `MediaLibrarySession.Callback` domain methods in
the same way as connection hints of a Media3 browser.
PiperOrigin-RevId: 484220748
This is the first commit out of two. This change adds the missing event
flags for the onEvents() callback when MediaController is connected to a
media3 session (see MediaControllerImplBase). I updated the
MediaControllerListenerTest and MediaControllerStateMaskingTest with
assertions that on onEvents() is called alongside individual
Player.Listener callbacks.
There will be a follow-up change for the case where a MediaController is
connected to a legacy MediaSession (MediaControllerImplLegacy). I've
split this in two separate changes to make the size of the commit
manageable for reviewing.
#minor-release
PiperOrigin-RevId: 481933437
Adds root extras and metadata extras to MockMediaLibraryService and MockMediaBrowserCompatService and completed test cases for asserting
interoperability with a media1 or Media3 browser.
PiperOrigin-RevId: 480854842
One of the tests in MediaBrowserListenerTest caused the remote
browser service to crash and then just timed out. As this asserts
nothing useful besides checking that the timeout method is working,
we can remove the test.
Crashing the remote browser service had the side effect of letting
subsequent tests in the same class fail because the previous session
was never released and was still present in the static MediaSession
SESSION_ID_TO_SESSION_MAP instance, which prevented the creation
of new sessions with the same id. This is only an issue in test
runs because a real process would also lose its static variables
when it crashes.
PiperOrigin-RevId: 476905337
The assertion asserts against a `Period` and an `AdPlaybackState` which actually
asserts against a resolved ad which is what `ExoPlayerImplInternal` does later and
what gives us a `SEEK_ADJUSTMENT`. However, this assertion is not required at the
moment of masking, because we are sure that the resolved seek results in a content
period and never an ad period.
#minor-release
Issue: androidx/media#122
PiperOrigin-RevId: 471827072
We create an empty CueGroup in many places as default or
where none is needed. Instead, we can define a constant
for this purpose and reuse it.
PiperOrigin-RevId: 467944841
When the player finishes playback and reaches the STATE_ENDED,
the notification remains visible with a pause button and the
service is kept in the foreground. This is a bug.
With this change, when the player reaches the STATE_ENDED, the
service is stopped from the foreground and a notification is shown
with a play button. If the play icon is tapped, the player will restart
playback of the last played item. Playing the last played item again
is the existing behavior when play/pause commands are received from
the legacy MediaSession (e.g. BT headset buttons).
#minor-release
Issue: google/ExoPlayer#112
PiperOrigin-RevId: 467231509
Once a controller bound to a MediaSessionService unbinds, this service
may be destroyed immediately if this was the last bound controller and
the service isn't started in the foreground.
At the time of releasing the controller, there may still be pending
commands that need to be handled by the session service. These commands
may cause the session service to post a foreground notification to
keep it alive. So to avoid the destruction of the service while these
commands are still handled, we need to keep the controller bound.
We also add a timeout in case the session tasks are never completed
by the session implementation. In case the controller is destroyed,
the unbinding happens automatically by the system.
PiperOrigin-RevId: 463802220
We currently clear all pending messages, including the one that flushes
pending commands to the MediaSession. To ensure all commands that have
been called before controller.release() are still sent, we can manually
trigger the flush message from the release call.
Related to handling the final flush because disconnecting the controller,
MediaSessionStub didn't post the removal of the controller to the
session thread, creating a race condition between removing the controller
and actually handling the flush.
Issue: androidx/media#99
PiperOrigin-RevId: 462342860
Some commands are run asynchronously and subsequent commands need
to wait until the previous one finished. This can be supported
by returning a Future for each command and using the existing
command execution logic to wait for each Future to complete.
As some MediaSessionStub code is now executed delayed to when it
was originally created, we also need to check if the session is
not released before triggering any actions or sending result codes.
Issue: androidx/media#85
PiperOrigin-RevId: 462101136
After this change the current tracks are sent to the controller as part of
`PlayerInfo` and call `Listener.onTracksChanged()` in case of a change in tracks.
PiperOrigin-RevId: 461578695
This code path is now completely redundant as the same effect can be
achieved by using player.setMediaItem.
#minor-release
PiperOrigin-RevId: 455115567
These calls were not implemented so far as they require a mix of
initial prepareFrom/playFrom calls and addQueueItem. We can also
support clients without queue handling to set single MediaItems.
To make the calls consistent and predictable in the session,
we need to ensure that none of the play/pause/addQueueItem/
removeQueueItem/prepare/playFromXYZ/prepareFromXYZ are called
before the controller is prepared and has media.
#minor-release
PiperOrigin-RevId: 455110246
Some Player implementations have no playlist capability but can still
set a MediaItem for playback. Examples are a MediaController connected
to a legacy MediaSession, ExoPlayer up to 2.12 or MediaPlayer.
To indicate this capability, we need an allowed command in addition
to COMMAND_CHANGE_MEDIA_ITEMS that just allows to set a single item
that replaces everything that is currently played.
#minor-release
PiperOrigin-RevId: 453879626
These legacy callbacks are currently forwarded to onSetMediaUri which
will be removed in the future.
Also make sure to only call player.prepare/play after the items have
been set.
The calls to onAddQueueItem are also forwarded to onAddMediaItems to
actually allow a session to resolve these items to playable media, which
wasn't possible so far.
PiperOrigin-RevId: 453625204
This change makes MediaSessionPermissionTest.removeMediaItems()
non-flaky. This is a quick fix though it'd be good to refactor this
test file.
PiperOrigin-RevId: 453162764
This provides an (unstable) API for apps to broadcast session extras
Bundle to all connected controllers and set the extras in the legacy
session.
Similar to the custom layout, the extras Bundle is not part of the
Media3 session state. This means that when a Media3 controller
connects to the session after the broadcast, the extras needs to be
sent to that controller in `MediaSession.Callback.onPostConnect(MediaSession session, ControllerInfo controller)`.
PiperOrigin-RevId: 451871731
This value only existed to allow setting media URLs from external sources
(e.g. in a MediaController) so that a player can start playing this item.
Now that we have MediaItem.RequestMetadata.mediaUrl we can remove this value
from MediaMetadata because it's request metadata, not media metadata.
PiperOrigin-RevId: 451857413
The MediaItemFiller is not flexible enough for most realworld usages
because:
- it doesn't allow asynchronous resolution of MediaItems (e.g. to
look up URIs from a database)
- it doesn't allow to batch updates for multiple items or do more
advanced customizations (e.g. expanding a mediaId representing
a playlist to multiple items).
Both issues can be solved by passing in a list of items and
returning a ListenableFuture. The callback itself can also move
into MediaSession.Callback for consistency with the other
callbacks.
PiperOrigin-RevId: 451857319
The MockPlayer currently:
- uses separate fields for single mediaItem vs multiple mediaItems
- replaces all items on addMediaItem operations
- does nothing on remove/move operations.
Fix all of this by using a single field that replicates the player
operations directly.
Some tests also need to be updated to make them more realistic
(for example only removing items from a playlist that have
previously been added).
PiperOrigin-RevId: 451857271
We need to pass timestamp for the list of cues so we are defining a new class CueGroup which will store both cues and timestamp.
PiperOrigin-RevId: 449212054
This provides a way for apps to send a custom layout to media3
controllers and legacy controllers by making sure to include custom
actions in the legacy playback state when built in the PlayerWrapper
for broadcasting.
PiperOrigin-RevId: 447967600
A custom action sent by legacy controllers as for instance the System UI mini player arrive at MediaSessionCompat.Callback.onCustomAction() and need to be dispatched to the session callback as a such.
PiperOrigin-RevId: 447486859
This is consistent with the IntDef name, and frees up the CONTENT_TYPE_
prefix for the @ContentType values (which are currently just TYPE_*,
and therefore ambiguous with lots of other 'type' values in C).
PiperOrigin-RevId: 445356476
This change adds the ability to update the error code of the PlaybackStateCompat in
cases we need this for backwards compatibility. It is applied in the least
intrusive way because normally, return values of a service method should not change
the state of the `PlaybackStateCompat`, just because it has nothing to do with the
playback state but rather with the state of the `MediaLibrarySession`.
For this reason only the error code `RESULT_ERROR_SESSION_AUTHENTICATION_EXPIRED`
is taken into account while all other error codes are not mapped to the
`PlaybackStateCompat'.
PiperOrigin-RevId: 438038852
The MockPlayer has a single CountDownLatch field and multiple boolean
flags that track if a player method was called. Upon calling the methods
the latch count. Tests set the latch count to match exactly with the
number of expected player interactions then block the test thread until
the latch reaches zero and assert the respective method flags are true.
This is subject to false positives. If the underneath implementation
changes and call more player method, then the test thread will unblock
as soon as a certain number of interactions is performed, which may be
less than what the test expected originally. However, the test may stil
pass if the player thread had enough time to update the expected method
flag.
This change removes the single CountDownLatch and the boolean flags and
instead it adds APIs to query the MockPlayer if a method has been called
and await until a method is called. Internally, the MockPlayer has a
ConditionVariable per method.
PiperOrigin-RevId: 432399077
(cherry picked from commit 45d512160c)
The MockPlayer has a single CountDownLatch field and multiple boolean
flags that track if a player method was called. Upon calling the methods
the latch count. Tests set the latch count to match exactly with the
number of expected player interactions then block the test thread until
the latch reaches zero and assert the respective method flags are true.
This is subject to false positives. If the underneath implementation
changes and call more player method, then the test thread will unblock
as soon as a certain number of interactions is performed, which may be
less than what the test expected originally. However, the test may stil
pass if the player thread had enough time to update the expected method
flag.
This change removes the single CountDownLatch and the boolean flags and
instead it adds APIs to query the MockPlayer if a method has been called
and await until a method is called. Internally, the MockPlayer has a
ConditionVariable per method.
PiperOrigin-RevId: 432399077
getCurrentTrackGroups and getCurrentTrackSelections are
retained for now, but moved from Player to ExoPlayer, to
ease the transition for some application code that currently
uses these methods.
PiperOrigin-RevId: 430036355
MediaNotificationHandler tries to connect session in the same
process, so tests should be aware MediaControllers from the
MediaNotificationHandler.
PiperOrigin-RevId: 422330424