If I pause playback and leave my phone alone for a couple minutes, the notification disappears. Will see if I can capture some logs but it's pretty consistent.
Okay, figured it out:
10-24 22:22:07.882 1677 1692 W ActivityManager: Stopping service due to app idle: u0a89 -1m8s633ms com.decoderhq.indieshuffle/com.guichaguri.trackplayer.service.MusicService
10-24 22:22:07.886 4707 4707 D RNTrackPlayer: Releasing service resources...
10-24 22:22:07.886 4707 4707 I ExoPlayerImpl: Release f9d6af2 [ExoPlayerLib/2.9.0] [generic_x86, Android SDK built for x86, Google, 26] [goog.exo.core]
10-24 22:22:07.900 1677 1688 D MediaSessionService: Media button session is changed to null
I had it paused for just over 1 minute, as the logs show. Seems a bit too quick...
Once I resume the app, things like getQueue have reset, which leaves my app in quite a mess.
Unfortunately it's the new service policy Google made in Android 8. There is no way to keep the service alive in this case, the only way is to work around it caching the queue.
Do you think the module should be storing the queue (and the rest of the options) somewhere when the service is destroyed, retrieving and loading it back when the app gets back up or should we leave this to be stored by the app devs instead?
Unless the app is in foreground or the service is actually playing music, the OS might remove it.
I definitely think it's a good idea to store the queue and the rest of the options so that it's easy to resume where you left off. There would probably also need to be an option to clear that cache, in the event that someone doesn't want it to always resume with that information remembered. Personally, I wouldn't clear -- I'd always resume with the cached state. Sounds like a great addition.
I don't think my Spotify notification gets dismissed after 1 minute... maybe 15 minutes would be more understandable, but 1 minute is very quick. Sometimes you're just pausing music to have a quick conversation, and right now, if you want to resume your playback you're out of luck -- even when opening the app. So anything that can be done to keep it alive for longer is a win.
@jasongrishkoff what is the device you are testing on? I'm asking because after running tests targeting this specific issue, the only devices that behaved like that were running on Samsung Experience 9.0 pre July patch.
crashing after the notification is dismissed however, was consistent among all devices running android 8.0 ( and only 8.0).
Another concern here -- related -- is that if I have network issues while listening, the notification gets dismissed and the music never starts playing again :(
Hi @Guichaguri, have you had any thoughts on how to improve this experience?
This is a release blocker for us, so we’re going to try and fix it by caching the queue.
I don’t have much experience with java and android development, so I’m trying to map out what needs to be done. As I see it there are three main parts: caching, handling the media button push, and replacing the notification.
Caching the queue in MusicService, when it is destroyed. I’m guessing this should live in MusicService, as this is where the session is going to be ‘restarted’. Not sure how this should be done so I would appreciate some pointers.
Then there is handling the media button push (in MusicService.java).
Right now it crashes because manager is set to null onDestroy.
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
MediaButtonReceiver.handleIntent(manager.getMetadata().getSession(), intent);
return START_NOT_STICKY;
}
I would add a try catch here, so if manager is null, we start the service based on the cache.
Then the notification needs to be updated, so that it is not killed when the service is destroyed. I’m thinking the existing actions would still work to trigger the media button push.
Any hints would be appreciated :) Thanks for all the work you all have put into this repo.
I would never add a try catch there, here is why:
I still want to explore more options before adding the cache.
@jasongrishkoff Are you using stopWithApp? If you aren't, is it happening while the app is in foreground?
@Guichaguri I'm not using stopWithApp, but I have seen the notification occasionally dismissed mid-song while the app is in the foreground. It's hard to replicate tho.
@Guichaguri any thoughts on this? Caching + ability to easily resume playback from the app when the notification has been dismissed are essential -- I can't use 1.0.0 in production until that component works. I can try code the caching part myself using mobx, but that'd be pointless if we can accomplish it through track-player.
For what it's worth, my Spotify notification doesn't dismiss very easily on Android 8. The album I was listening to finished ~45 minutes ago and the notification widget is still on my screen. Not sure how they're going that ¯_(ツ)_/¯
At the moment, the notification is removed when the service is removed, that's why it's removed pretty quickly. I'll start pushing commits for the cache tomorrow, and we should be able to leave the notification after the service is destroyed.
I'm going to make a pull request later today of the work we have been doing.
It's working for our use, but might need some work for general use. I had some trouble understanding the how to leave the notification in place, so i simply replaced it when the service was removed.
Hey there, thanks again for all the work on this library.
I see alot of different issues regarding the lifecycle of the MusicService and the Notification.
For me these issues are last tasks on my todo list before launch. Yeah!
So I would like to offer my help. I am not an android guy usually but I am willing to change hats. Is there something I can do?
It appears to me the library is struggling to keep the notification visible after the service has been disconnected and then both the app and the notification (if it is still visible) are unable to reconnect to or recreate the service.
I am curious if the Exoplayer's PlayerNotificationManager class could help remove the pressure of managing the lifecycle. It appears to create and destroy services as the notifications are shown and removed essentially syncing them. Then the RNTrackplayer only needs to manage the notifcations and the service will follow accodingly
Recommended here https://github.com/google/ExoPlayer/issues/4482
And explained in this vid https://youtu.be/svdq1BWl4r8?t=703
@antontanderup any luck with your pullrequest?
@brenwell You can try it out. It works (for us), but it is not perfect. The notification will momentarily disappear when the service is removed and revived.
Great thanks, didn't realise that you had already made one. And thankfully I am also only using 1 track at a time, and managing the playlists myself
The pull request for those interested -> https://github.com/react-native-kit/react-native-track-player/pull/358
Just checked it an it appears to work. As you stated its not the best solution as the notification keeps opening and closing but better than not working at all.
I have been working on a proper solution, that keeps the service alive as long as the notification is alive. It works as expected. However I am struggling with the final piece of the task and that is closing the service when the app is closed or crashes
If someone with more android service experience can help me with killing the service on crash then I would have a potential solution.
Here is my skeleton example https://github.com/brenwell/react-native-audio-player
@brenwell The PlayerNotificationManager wouldn't get us anywhere, we already are doing the most of the logic that it does, except we have events for each button press, so the app can react however it wants.
Here is the problem:
And here is the PlayerNotificationManager solution:
Both are viable options, the original idea is harder to implement and to maintain, but the latter has a UX issue. I don't know if any of you mind that.
@antontanderup did an awesome job with the PR. I won't be merging it just yet, there are a lot of code to review and clean up there, but you should definitely use it for now.
@Guichaguri Thank you very much for the detailed explanation. That helps a lot to understand the issues. It appears to me that there is a direction that needs to be chosen as they both have UX issues.
stopAction - Sets which stop action should be used. If set to null, the stop action is not displayed.
https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/ui/PlayerNotificationManager.html
My vote would be the second solution as I personally don't mind the stop button, obviously others may disagree. But on my Nexus 5X the service is stopped about 1 a minute and therefore the notification is constantly opening and closing. Furthermore I believe option 2 is less error prone, less code is needed in this library and can be maintained by the Exoplayer team, which undoubtedly has more resources.
The counter argument is that the PlayerNotificationManager is probably more work. How much I don't know, but that is certainly a factor. Plus having the ability to cache the player state and recreate the service is very useful functionality. As it would allow the service to restart under many unforeseen situations. Potentially we could create both solutions and then we could put a timer on the notification, if it is paused for 15 minutes then kill the service + notification. Then if the user wants to continue we could start it up again.
I have been checking Spotify and they seem to have best of both worlds, but I am not sure how they are doing. So there is still a 3rd option I can't see
Let me know if there is something I can do
After a bit more research I think I have discovered how Spotify is doing it. I noticed that you cannot swipe the notification away while the audio is playing. So upon pause they replace the notification with a swipeable one.
https://stackoverflow.com/a/35721582/1393746
The user is not allowed to swipe away a notification generated by an ongoing foreground service.
Hence, stopForeground(false) first, which allows the notification to be swiped away by the user thereafter (at least on Lollipop+). For pre-Lollipop, you may have to stopForeground(true), which stops foreground and removes the notification, then re-issue the notification with notificationManager.notify(yourNotificationID, yourNotificationObject), so that your notification is visible but swipeable.
You can ignore my last comment, I see you guys are basically doing that right now.
I suppose you are right then, caching the player state is probably the better solution. Just a shame the services get killed so quickly. Be nice to keep them alive for at least 5 minutes.
Like I said, let me know if I can help
@brenwell
Yes, you are right, but then you get another UX problem: the user can't remove the notification in an easy way.
The notification is cancelled when null is passed to setPlayer(Player) or when an intent with action ACTION_STOP is received
https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer2/ui/PlayerNotificationManager.html
We'll not use PlayerNotificationManager, but it's concept instead, we already have all of the notification logic in place, we should adapt it to work exactly like it because it's a "two-line change", really simple.
Spotify uses the first solution, mostly because they already have all the state synchronization being done between devices in their servers. The service probably queries it when it's initialized.
I'll go directly into the second option and publish a new version. We can look into @antontanderup solution after.
Ok. Terrific
@jasongrishkoff @brenwell Can you try 80b97301bf340fa29ab9d971b9781c81d578e243?
The service will be kept alive as long as it can, which can become a problem if you don't destroy it. I should probably change it to be removed from the foreground when the player stops or something like that.
@Guichaguri so far so good. Any thoughts re: caching if the user resumes at a later state? Does this make that no longer necessary?
Yes, I still want to look into that in the future, but for now that fixes it. Unfortunately, this simple fix comes with two problems:
destroy() the playback and not only stop() it.On the bright side, you can make sure you'll be able to control the lifecycle of the service.
I was also thinking about adding an optional "X" button to the notification, so you don't have to use the stop button for that, what do you think?
Edit: 553a19f483fe9b6a3f1372b8d9bb852356549b48 changes the service to be in background when the music is stopped (so it will be removed sometime after)
I'm all for trying to put a stop button in -- from my initial testing it seems to work well, and is intuitive. However, when I try to re-initiate after destroying the player, I'm not seeing any of the CAPABILITY buttons.
Edit -- the buttons show up if I re-initiate the player from scratch, which was fairly easy.
I think the X button makes sense, especially if you are in a situation where the notification would usually be swipable (paused).
Edit:
I have just noticed that YouTube also displays the X in the notification when paused and in the background (on P).
Hi all, late to the conversation. Could someone explain the problem with making the notification swipe dismissable when the audio is paused?
Foreground services require a notification. And if I understand correctly you can then never swipe them if you want to make the service permanent. This is the same behaviour for Spotify I believe. Please anyone correct me if I am wrong
there must be a solution here without needing a stop button
There is, you can save the state and then change back to a background service when the playback pauses. The service should be killed by the OS at some point, and when you receive a media button, you have to restore the state of the service and then change it to foreground again.
I still want to explore this in the future, but I still have to look into the issues that it may cause (for instance, you also have to restore you also have to restore your state properly in the "playback service"
@antontanderup created #358 to implement this exact behavior. For now I'll keep the solution we have due to it being the safest one.
@Guichaguri is there any progress on track-player on general stability so that it feels more okay to merge https://github.com/react-native-kit/react-native-track-player/pull/358?
cc @antontanderup
@lode While we are using #358 for our android builds, i would not recommend it. It works for our usecase, but has not been tested for use with multiple tracks in the queue. Because it seems like this is not the direction for RNTrackplayer we have not kept the branch up-to-date the dev branch.
We are mainly using it while we wait for a fix for https://github.com/react-native-kit/react-native-track-player/issues/473
Most helpful comment
I'm going to make a pull request later today of the work we have been doing.
It's working for our use, but might need some work for general use. I had some trouble understanding the how to leave the notification in place, so i simply replaced it when the service was removed.