Audio_service: How to update the media item dynamically?

Created on 21 Feb 2020  路  16Comments  路  Source: ryanheise/audio_service

To which pages does your suggestion apply?

Describe your suggestion
Instruction how I can update the MediaItem dynamically.

I don't want to use the .setQueue(), I only need to play one track at a time and I have my own queuing/playlist structure. However when the track does change I would like to update the MetaData displayed on Android Notification and iOS Control Center.

1 backlog documentation

Most helpful comment

@ryanheise I managed to solve it by creating an onCustomAction within my extends BackgroundAudioTask class.

void onCustomAction(_function, params) { switch (_function) { case 'updateMedia': AudioServiceBackground.setMediaItem(MediaItem( id: params['mediaID'], album: params['mediaAlbum'], title: params['mediaTitle'])); break; } }

And my controller class:

updateMedia(Map<String, dynamic> _media) async {
  await AudioService.customAction('updateMedia', _media);
}

Is it good practice? It's working correctly. I can update the media information without having to add another item.

All 16 comments

You can update the currently playing media item dynamically by calling AudioServiceBackground.setMediaItem. All clients are notified of the updated media item so the change will be displayed everywhere. I would be happy to improve the documentation for that method if it's unclear to you, but can you suggest how it could be improved?

You do not need to set the queue if you don't want to have a queue.

From the documentation I understood that I was not able to call AudioServiceBackground from the UI? Is this not correct?

If it is correct then my question is on how to update the mediaItem from the UI.
Example a user clicks on a new track to play. I will set the url and play using my audio library however the mediaItem is part of AudioServiceBackground, which from my understanding is started once and not restarted for different track.

The clients (e.g. the Flutter UI, the notification, the control center, a headset, Android Auto) can send messages to your background task to request it to do something, but it is the background task that actually does everything. Therefore, AudioServiceBackground.setMediaItem is accessed from the background task. If none of the pre-defined messages fit your mold, you can always use customAction.

I would be open to add more pre-defined messages if they make sense, although the current set of pre-defined messages is based on the Android media session APIs and are based around the ways that remote control media players like Android Auto would interact with an app. Because these are "thin" clients, that is why they do not actually do things like setQueue and setMediaItem. A thin client doesn't have that info, it's the app itself that contains the logic and hosts the data, and this is all to be encapsulated in the background task. Adding a pre-defined message for setMediaItem might be "convenient" in your use case, but it would go against the idea of having a thin client. It's something I can think more about, but until then, if you have a fat client, you can hopefully still send the message you want with customAction.

Ahh okay I think I understand now. That was a helpful explanation, I will try and implement this using a customAction. Will leave this open if I have any further issues on the matter, otherwise I will close this if I get it working. Thank you for the help

Please, can you provide an example of the code? Lets assume we have an official example app and I want to start playing the song (stored as MediaItem) in _MyAppState's variable when user taps on the 'audioPlayerButton'. I can't figure out, how to pass this object to background service from UI. Thank you.

@jkubicko , I'd like to create a wiki with more documentation and a cookbook, although last time I checked it was unclear what the standard practice is for applying a license to a wiki. One way you could help make this happen faster is if you could help provide some references to how licenses typically work for GitHub. See in particular #98 .

I'd say that the wiki is under the same license as the "main" repository, but if you want to specify it explicitly, wiki's footer is the best place to do it.

@ryanheise Hello, I still don't quite understand how to update mediaItem and I'm stuck with it. When using AudioServiceBackground.setMediaItem I get the error:

E/flutter ( 3263): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The method 'invokeMethod' was called on null.
E/flutter ( 3263): Receiver: null
E/flutter ( 3263): Tried calling: invokeMethod("setMediaItem", _LinkedHashMap len:12)

Can't setMediaItem be called outside the class? Can you help me?

Thank you.

@jkubicko Thanks for the link. In the Github TOS, it is a little unclear whether the wiki is part of the same repository or whether it is a different repository. The reason I thought this is that the change history of the wiki does not actually appear in the git commit history for the main project. However, that link you provided does seem to refer to the wiki as being "part of" the repository, and I think therefore that "repository" has two meanings here. One is the git repository, and one is the "GitHub" repository which includes both the git repo and the wiki (which I think may have its own underlying git repo).

I'll have a think about this more when I get time, and thank you for the link.

@niicolasalves I will work on the documentation request, but to your immediate issue I can only point you to search the past issues where similar questions have been asked. It sounds like you may benefit from starting at the pinned issue.

@ryanheise here is another (but not very satisfying) answer I found

@niicolasalves I'm not sure if this is the best solution, but this helped me to make it work https://github.com/ryanheise/audio_service/issues/157.

Thanks, @jkubicko . Yeah, the situation is not terribly clear. For now, I've decided to add a notice to the Wiki indicating that it is considered part of the overall GitHub repository, and therefore covered by the same license. In future, if it turns out to be unclear, I can always copy the license across to the wiki, and still use the same license.

Anyway, I've now written up a tutorial in the wiki. The next step is to write up a cookbook.

@niicolasalves , I will add your specific request to the cookbook. But just briefly, I think the easiest way to achieve what you want to do would be to actually use a queue, but just with a singleton item. So:

await AudioService.start(...);
await AudioService.addQueueItem(mediaItem);
await AudioService.play();

Then in your background audio task, you can make it so that onStart doesn't do anything except return a future that controls when the isolate is shut down.

In onPlay, you can play the media item that's in the queue.

Even though you said you don't want to use the queue, you don't actually have to use the queue to reflect your app's playlist if you don't want to, but you can still use the queue as simply mechanism for passing a media item into the background audio task. My preference would of course to use the queue for its intended purpose, but you don't have to.

Thank you for the wiki. Great job!

@ryanheise I managed to solve it by creating an onCustomAction within my extends BackgroundAudioTask class.

void onCustomAction(_function, params) { switch (_function) { case 'updateMedia': AudioServiceBackground.setMediaItem(MediaItem( id: params['mediaID'], album: params['mediaAlbum'], title: params['mediaTitle'])); break; } }

And my controller class:

updateMedia(Map<String, dynamic> _media) async {
  await AudioService.customAction('updateMedia', _media);
}

Is it good practice? It's working correctly. I can update the media information without having to add another item.

@niicolasalves I believe that is how it is supposed to be done. From the comments by @ryanheise that is how I understood it. This is exactly what I was going be doing in my code when I had a chance.

@ryanheise I managed to solve it by creating an onCustomAction within my extends BackgroundAudioTask class.

void onCustomAction(_function, params) {
    switch (_function) {
      case 'updateMedia':
        AudioServiceBackground.setMediaItem(MediaItem(
            id: params['mediaID'],
            album: params['mediaAlbum'],
            title: params['mediaTitle']));
        break;
    }
  }

And my controller class:

updateMedia(Map<String, dynamic> _media) async {
  await AudioService.customAction('updateMedia', _media);
}

Is it good practice? It's working correctly. I can update the media information without having to add another item.

thanks

I've added a bit more about custom actions to the FAQ in the wiki, and opened a new issue to consider adding AudioService.updateMediaItem to the API since it may be a common use case. If you are interested in that feature, please follow #276 , and I'll close this one. Thanks, everyone.

Was this page helpful?
0 / 5 - 0 ratings