-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update Notification Title during playback #951
Comments
Hi @AmrSubZero, You can utilize the
In this way, the player can emit an Hope this helps! |
Hello @tianyif Actually the The logic, since Media3 or ExoPlayer does not have built in See here// ProgressTracker is a custom class that tracks player.getCurrentPosition() every 1 second.
ProgressTracker tracker;
MediaMetadata metadata = new MediaMetadata.Builder()....build();
player.addListener(new Player.Listener() {
@Override
public void onIsPlayingChanged(boolean isPlaying) {
if(isPlaying) {
tracker = new ProgressTracker(player, new ProgressTracker.PositionListener() {
@Override
public void progress(long current_position) {
if(current_position >= something) {
// Replace the current MediaItem with new Title
MediaItem mediaItem = player.getCurrentMediaItem();
if(mediaItem != null) {
mediaItem
.buildUpon()
.setMediaMetadata(metadata.buildUpon()
.setTitle("Part: x")
.build())
.build();
player.replaceMediaItem(0, mediaItem);
}
}
}
}
}else {
// Purge the position tracker (handler.removeCallbacks())
if(tracker != null) { tracker.purgeHandler(); }
}
}
}
@Override
public void onDestroy() {
// Purge the position tracker (handler.removeCallbacks())
if(tracker != null) { tracker.purgeHandler(); }
}
// The position tracker class (ProgressTracker.java)
public class ProgressTracker implements Runnable {
public interface PositionListener{
public void progress(long position);
}
private final Player player;
private final Handler handler;
private PositionListener positionListener;
public ProgressTracker(Player player, PositionListener positionListener) {
this.player = player;
this.positionListener = positionListener;
handler = new Handler();
handler.post(this);
}
public void run() {
long position = player.getCurrentPosition();
positionListener.progress(position);
handler.postDelayed(this, 1000);
}
public void purgeHandler() {
handler.removeCallbacks(this);
}
} Then i check if the current position equals something, there i need to update the meta title like "Part: 13", this runs very frequently! Using See hereposition: 50 --> first
position: 845
position: 1846
position: 2849
position: 3858
-- called player.replaceMediaItem()
position: 49 -- > should be 4xxx
position: 1051 -- > should be 5xxx
position: 6890
position: 7892
-- called player.replaceMediaItem()
position: 118 -- > should be 8xxx
position: 9994
position: 10996
position: 11999
position: 12993
position: 13994
-- called player.replaceMediaItem()
position: 115 -- > should be 14xxx
position: 16030
position: 17031
position: 18033
-- called player.replaceMediaItem()
position: 124 -- > should be 19xxx
position: 1124 -- > should be 20xxx
position: 2125 -- > should be 21xxx
position: 22074
-- called player.replaceMediaItem()
position: 101 -- > should be 23xxx
position: 1103 -- > should be 24xxx
position: 25080
position: 26080
position: 27081
-- called player.replaceMediaItem()
position: 100 -- > should be 28xxx
position: 1101 -- > should be 29xxx
position: 2102 -- > should be 30xxx
position: 31124
position: 32125
-- called player.replaceMediaItem()
position: 75 -- > should be 33xxx
position: 34126
position: 35128 Therefore, when i get incorrect also is it a best practice calling So, my hopes:
Thanks! |
Thanks for the details! Did you reproduce this on demo-session app? I tried to reproduce on demo app with pasting your snippet in
I'm not sure if you're suggesting something like a current position listener. We had such requests (eg. google/ExoPlayer#3980) before, and the short answer is sending a huge amount of callbacks according to the position update frequency (per 10 ms) is less efficient than polling the progress infrequently. And the |
Hello @tianyif thanks for keeping up! after hours of debugging and trying several methods, here's what i've discovered!
// PlaybackService.java
public class PlaybackService extends MediaSessionService {
ExoPlayer player;
@Override
public void onCreate() {
player = new ExoPlayer.Builder(this).build();
}
}
// MainActivity.java
MediaController player;
ListenableFuture<MediaController> controllerFuture;
@Override
protected void onStart() {
SessionToken sessionToken =
new SessionToken(this, new ComponentName(this, PlaybackService.class));
controllerFuture =
new MediaController.Builder(this, sessionToken).buildAsync();
controllerFuture.addListener(() -> {
try {
player = controllerFuture.get();
} catch (Exception e) { e.printStackTrace(); }
}, MoreExecutors.directExecutor());
} When i tested getting
i tried several methods to track See herepublic class MainActivity extends AppCompatActivity {
MediaController player;
ListenableFuture<MediaController> controllerFuture;
PlayerView playerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
playerView = findViewById(R.id.playerView);
}
private void getCurrentPlayerPosition() {
Log.i("PLAYBACK_STATE", "Playback Position: " + player.getCurrentPosition());
if (player.isPlaying()) {
playerView.postDelayed(this::getCurrentPlayerPosition, 1000);
}
}
@Override
protected void onStart() {
SessionToken sessionToken =
new SessionToken(this, new ComponentName(this, PlaybackService.class));
controllerFuture =
new MediaController.Builder(this, sessionToken).buildAsync();
controllerFuture.addListener(() -> {
try {
player = controllerFuture.get();
// Set Player to the PlayerView
playerView.setPlayer(player);
player.addListener(new Player.Listener() {
@Override
public void onIsPlayingChanged(boolean isPlaying) {
if(isPlaying) {
// Track the current playback position (every 1 second)
playerView.postDelayed(MainActivity.this::getCurrentPlayerPosition, 1000);
}
}
} catch (Exception e) { e.printStackTrace(); }
}, MoreExecutors.directExecutor());
}
} Either way, updaing the MediaMetaData title (frequently) is working now by calling But i'm still curious, why the Here is a repo of projects for both ways. Thanks! 👏 |
Hi @AmrSubZero, Thanks for the impressive details! Yes, I could reproduce the interrupted position with the test controller app with connecting to a session from the demo session app. The reason being this is based on the four facts -
Then I added some logs and found that -
The wrong position was marked as WRONG, which is 1003. I marked the logs corresponding to each above steps, and you can see between replacing the item and getting the wrong position 1003, there is neither [2] and [3] that update the My rough thought is around whether we should use the default position 0 to mask the current position when the item is being replaced (corresponding to the above [1]). It makes sense in the case that the current playing item is completely removed and the default position of the next item will be immediately used, but in the case that the current playing item is replaced, using the current position instead of 0 would be a better option. We will further look into and provide a proper solution to it. Thanks a lot for all the details and repo of the project! |
When the controller replaces the current item, the masking position will be changed to the default position of the new item for a short while, before the correct position comes from the session. This will interrupt the current position fetched from the controller when the playback doesn't interrupted by the item replacing. Issue: #951 #minor-release PiperOrigin-RevId: 611417539
When the controller replaces the current item, the masking position will be changed to the default position of the new item for a short while, before the correct position comes from the session. This will interrupt the current position fetched from the controller when the playback doesn't interrupted by the item replacing. Issue: #951 PiperOrigin-RevId: 611417539 (cherry picked from commit 1bdc58d)
When the controller replaces the current item, the masking position will be changed to the default position of the new item for a short while, before the correct position comes from the session. This will interrupt the current position fetched from the controller when the playback doesn't interrupted by the item replacing. Issue: androidx#951 PiperOrigin-RevId: 611417539 (cherry picked from commit 1bdc58d)
Using Media3 [email protected] with a
PlaybackService
that extends MediaSessionServiceusing
setMediaNotificationProvider
to create aNotification
for API below 33.in
MainActivity
i set theMediaMetaData
(title/description)TLDR: i need to update title/description of the media playback notification (during playback), after it's already set before using
.setMediaMetadata(new MediaMetadata.Builder().setTitle(..))
and.setContentTitle(metadata.title)
Now, what i'm trying to achieve, lets say at some point
(during playback)
i need to update the title/description (or MediaMetaData title/description) of the Notification for the current playing media item, wether it is theMedia3 Session Notification
orLegacy Notification
below API Level 33Here's how it's currently working:
I can't seem to find any documentation or workaround to achieve this approach.
How can i achieve this?
The text was updated successfully, but these errors were encountered: