audio_service
audio_service copied to clipboard
Stopping the audio doesnt remove the notification
Documented behaviour
stop() → Future
I have used both for dismissing the notification
await audioHandler?.stop();
await BaseAudioHandler().stop();
Actual behaviour
The notification doesn't get dismissed
Minimal reproduction project
Official example: example_playlist.dart
Reproduction steps
- Click the stop button and it doesn't dismiss the notification
Output of flutter doctor
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.1)
[✓] VS Code (version 1.91.1)
[✓] Connected device (4 available)
[✓] Network resources
• No issues found!```
### Devices exhibiting the bug
Pixel 6a, Android Version 14
I have used both for dismissing the notification await audioHandler?.stop(); await BaseAudioHandler().stop();
Your code is not pertinent to the bug report because your bug report submits the "official example: example_playlist.dart" as the minimal reproduction project.
Note that there are several examples demonstrating different features of audio_service. If you want to see an example that demonstrates how to close the notification, see lib/main.dart.
Same and I've done some debugging.
It does not cancel the notification even though it did call NotificationManager.cancel();
Check the answer here
The legacyStopForeground() must be called before onDestroy() or else the notification cannot be removed by code.
Got the same issue
Facing the same issue here. But, this only happens when androidStopForegroundOnPause: false and androidNotificationOngoing: false if both are true the service does stop as expected after removing the app from task manager
But, this results in an issue where user pauses for momentarily and the OS kills the whole app for memory which is not ideal. This is espeically bad in Chinese android skins. Those OEM skins are too much aggressive
One cheeky way to get around this is while keeping both androidNotificationOngoing: false, androidStopForegroundOnPause: false, is to exit(0) on the BaseAudioHandler's overriden onTaskRemoved method
class MyAudioService extends BaseAudioHandler {
// ... other stuff
@override
Future<void> onTaskRemoved() async {
await myAudioPlayer.stop();
if(Platform.isAndroid) exit(0);
}
// ... other stuff
}
[!CAUTION] This can get the app rejected on AppStore. Usually, programmatic process termination is somehow against their policy.
This behaviour can be controlled through controlled state transitions although I will also investigate @XuanTung4195 's note above as this may help it to work more robustly.
facing the same issue. the behavior is inconsistent. sometimes the notification gets removed but sometimes it just stays.
I have the same problem. I wrote my own audio service on media3. The notification deletion works. It's all about the removeSession method, maybe it's worth going this way too. If necessary, I can send a code with how to use my service.
class PlaybackService : MediaSessionService() {
private var mediaSession: MediaSession? = null
// Create your Player and MediaSession in the onCreate lifecycle event
override fun onCreate() {
super.onCreate()
val player = ExoPlayer.Builder(this).build()
mediaSession = MediaSession.Builder(this, player).build()
}
override fun onTaskRemoved(rootIntent: Intent?) {
Log.d("PlaybackService", "onTaskRemoved")
var condition = mediaSession?.player?.playWhenReady;
if (mediaSession != null) {
removeSession(mediaSession!!)
}
if (condition == null || !condition) {
stopSelf()
}
}
override fun onUpdateNotification(session: MediaSession, startInForegroundRequired: Boolean) {
Log.d("PlaybackService", "onUpdateNotification")
super.onUpdateNotification(session, startInForegroundRequired)
}
// Remember to release the player and media session in onDestroy
@OptIn(UnstableApi::class)
override fun onDestroy() {
mediaSession?.run {
Log.d("PlaybackService", "onDestroy")
player.release()
stopForeground(STOP_FOREGROUND_REMOVE)
pauseAllPlayersAndStopSelf()
if (mediaSession != null) removeSession(mediaSession!!)
release()
mediaSession = null
}
super.onDestroy()
}
// This example always accepts the connection request
override fun onGetSession(
controllerInfo: MediaSession.ControllerInfo
): MediaSession? = mediaSession
}
This package is documented quite badly...
It is not mentioned anywhere, and I spent around a week looking here and there. Finally, here is the solution to remove notification: you need to set processing state to idle.
Here is a code sample of my stop method:
@override
Future<void> stop() async {
try {
await _audioPlayer.stop();
await _audioPlayer.seek(Duration.zero);
} on Exception catch (_) {
}
// We want to remove notification when the player is stopped
playbackState.add(
playbackState.value.copyWith(
playing: false,
processingState: AudioProcessingState.idle,
),
);
}
Once you set your state to idle - the notification will be removed 😉