media icon indicating copy to clipboard operation
media copied to clipboard

I am not able to continue playing when the app is swiped away.

Open colorgold opened this issue 1 year ago • 3 comments

I am not able to continue playing when the app is swiped away. My service looks like this:

public class PlayerService extends MediaSessionService {
    private static final String TAG = "PlayerService";
    private MediaSession mediaSession = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ExoPlayer player = new ExoPlayer.Builder(this).build();
        mediaSession = new MediaSession.Builder(this, player)
                .setSessionActivity(getMainIntent()).build();
        

    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    private PendingIntent getMainIntent() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.putExtra(Common.isPlaying, mediaSession != null && mediaSession.getPlayer().isPlaying());
        return PendingIntent.getActivity(this, 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ?
                        PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT));
    }

    @Nullable
    @Override
    public MediaSession onGetSession(@NonNull MediaSession.ControllerInfo controllerInfo) {
        return mediaSession;
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Player player = mediaSession.getPlayer();
        if (!player.getPlayWhenReady()
                || player.getMediaItemCount() == 0
                || player.getPlaybackState() == Player.STATE_ENDED) {
            stopSelf();
        }
    }

    @Override
    public void onDestroy() {
        if (mediaSession != null) {
            mediaSession.getPlayer().release();
            mediaSession.release();
            mediaSession = null;
        }
        super.onDestroy();
    }
}

My MainAcitivty:


    @Override
    protected void onStart() {
        super.onStart();
        SessionToken sessionToken = new SessionToken(this,
                new ComponentName(this, PlayerService.class));
        controllerListenableFuture = new MediaController.Builder(this, sessionToken).buildAsync();
        controllerListenableFuture.addListener(() -> {
            try {
                player = controllerListenableFuture.get();
                player.addMediaItem(media); //media created from uri
                player.prepare();
                player.play();
            } catch (ExecutionException | InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, MoreExecutors.directExecutor());
    }

Whenever I close the app, playback stops, and the notification disappears. How do I keep the player running in the background?

Originally posted by @colorgold in https://github.com/androidx/media/issues/389#issuecomment-2192874277

colorgold avatar Jun 27 '24 23:06 colorgold

If you add logging, do you see control flow entering the if inside onTaskRemoved when you close the app? If so, which of the 3 OR'd conditions is true to result in that happening?

If you don't see control flow entering that if, do you see anything in logcat to indicate why your service is being stopped?

icbaker avatar Jun 28 '24 14:06 icbaker

If you add logging, do you see control flow entering the if inside onTaskRemoved when you close the app? If so, which of the 3 OR'd conditions is true to result in that happening?

If you don't see control flow entering that if, do you see anything in logcat to indicate why your service is being stopped?

I added the following logs in the PlayerService:

@Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.d(TAG, "PlayerService: onTaskRemoved called");
        Player player = mediaSession.getPlayer();
        if (!player.getPlayWhenReady()
                || player.getMediaItemCount() == 0
                || player.getPlaybackState() == Player.STATE_ENDED) {
            Log.d(TAG, "PlayerService: onTaskRemoved: Service will be stopped");
            stopSelf();
        }else{
            Log.d(TAG, "PlayerService: onTaskRemoved service continues");
        }
    }

@Override
    public void onDestroy() {
        Log.d(TAG, "PlayerService: onDestroy called");
        if (mediaSession != null) {
            mediaSession.getPlayer().release();
            mediaSession.release();
            mediaSession = null;
            Log.d(TAG, "PlayerService: onDestroy: service destroyed");
        }
        super.onDestroy();
    }

When I close the application while the media is playing, the control flow never enters the if statement, but the service gets destroyed. It only enters when the media is not playing, as expected.

In MainActivity I added a button that controls playback:

private void togglePlay() {
        if (player.isPlaying()) {
           player.pause()
        } else {
            player.play()
        }
    }

Logcat shows this error when I press play:

MediaResumeListener     com.android.systemui             E  Cannot resume with ComponentInfo{com.murcianys.micaster/com.murcianys.micaster.services.PlayerService}

When I remove the app from recents while playing and then I reopen and press play again, I get these in logcat

MediaResumeListener     com.android.systemui                 D  Testing if we can connect to ComponentInfo{com.murcianys.micaster/com.murcianys.micaster.services.PlayerService}
2024-06-28 18:46:35.127  1972-2072  ResumeMediaBrowser      com.android.systemui                 D  Service connected for ComponentInfo{com.murcianys.micaster/com.murcianys.micaster.services.PlayerService}
2024-06-28 18:46:35.128  1972-2072  MediaResumeListener     com.android.systemui                 D  Connected to ComponentInfo{com.murcianys.micaster/com.murcianys.micaster.services.PlayerService}
2024-06-28 18:46:35.130  1972-2072  ResumeMediaBrowser      com.android.systemui                 D  Subscribe error for ComponentInfo{com.murcianys.micaster/com.murcianys.micaster.services.PlayerService}: androidx.media3.session.MediaLibraryService

I added a screen recording for reference.

https://github.com/androidx/media/assets/45986859/b11dda3e-57b7-4328-b39c-a0fefde3cf50

colorgold avatar Jun 29 '24 00:06 colorgold

Please can you capture an adb bugreport shortly after reproducing the issue (including your additional logging) and either upload it here or send it to [email protected] with the subject Issue #1507.

icbaker avatar Jul 01 '24 08:07 icbaker

dumpstate-2024-07-02-17-08-51.zip

I've attached a zip file of the report. Thanks for the help!

colorgold avatar Jul 02 '24 22:07 colorgold

This line from the BR makes it look like your service crashed (but I can't see any stack trace or similar before that to indicate what would have caused the crash):

07-02 17:08:44.821  1000  1039  2511 W ActivityManager: Scheduling restart of crashed service com.murcianys.micaster/.services.PlayerService in 1000ms for start-requested

Looking elsewhere, it also seems like the service is stopped ~2s before that:

07-02 17:08:42.961  1000  1039  1109 I am_foreground_service_stop: [0,com.murcianys.micaster/.services.PlayerService,1,PROC_STATE_TOP,34,34,0,0,8261,1,STOP_FOREGROUND,2]

And then the same restart is logged:

07-02 17:08:44.821  1000  1039  2511 I am_schedule_service_restart: [0,com.murcianys.micaster/.services.PlayerService,1000]

I noticed the BR is from a Samsung A51. Does the same issue reproduce on a Pixel device or an emulator created from Android Studio? I wonder if your service is being killed by some background battery saving logic added by Samsung: https://www.samsung.com/us/support/troubleshoot/TSG10001536

icbaker avatar Jul 08 '24 13:07 icbaker

This line from the BR makes it look like your service crashed (but I can't see any stack trace or similar before that to indicate what would have caused the crash):

07-02 17:08:44.821  1000  1039  2511 W ActivityManager: Scheduling restart of crashed service com.murcianys.micaster/.services.PlayerService in 1000ms for start-requested

Looking elsewhere, it also seems like the service is stopped ~2s before that:

07-02 17:08:42.961  1000  1039  1109 I am_foreground_service_stop: [0,com.murcianys.micaster/.services.PlayerService,1,PROC_STATE_TOP,34,34,0,0,8261,1,STOP_FOREGROUND,2]

And then the same restart is logged:

07-02 17:08:44.821  1000  1039  2511 I am_schedule_service_restart: [0,com.murcianys.micaster/.services.PlayerService,1000]

I noticed the BR is from a Samsung A51. Does the same issue reproduce on a Pixel device or an emulator created from Android Studio? I wonder if your service is being killed by some background battery saving logic added by Samsung: https://www.samsung.com/us/support/troubleshoot/TSG10001536

I followed the steps in the link you provided, specifically #2 Remove the app from Sleeping apps. My app was listed in the Sleeping apps section, so after removing it, the notification works in the background.

I had the app installed on the phone long ago and just came back to work on it. The device has a setting that puts unused apps to sleep which caused the service to stop.

Thanks for the help!

colorgold avatar Jul 09 '24 23:07 colorgold

Great, glad you got it sorted.

icbaker avatar Jul 10 '24 09:07 icbaker