I want to use audio_service
and just_audio
to play audio in the background. But the problem is I have to set queue at the start with all metadata to make sure they run automatically even when the app is in background. But I don't have song URLs to play the song. Instead, I have a function which can be used to get song play URLs. Now I want to call that function every time to get song play URL and use that URL to play the song. I want to call that function in the code of AudioBackgroundService, not in the code of my flutter UI. Because if my UI is absent i.e. in the background then that function will not be called. So to make sure that function is called everytime it have to be in AudioServiceBackground code. Is there a way to do so? I'm using the same code provided in the audio_service documentation. I guess I have to use that function in onStart
function of AudioService but I still can't figure the way out. Also, it will be much better if it can call that function for next song while playing the current one.

- 1,138
- 1
- 7
- 20
-
I'm not sure if I understand the problem. "the problem is I have to set queue at the start". Why do you HAVE to set the queue at the start? – Ryan Heise Feb 12 '21 at 02:20
-
Sorry If I'm not clear. Actually, I want to run songs in the background using just_audio and audio_service. They actually take a queue to start playing I can play single songs without queue using flutter to change song but then If my flutter UI is not present i.e. in background songs will not change. So i have to add queue to make sure they run in background – Ankit Sangwan Feb 12 '21 at 03:29
-
The problem is that I don't have any details to add songs to queue. So first I need details like title, artist and even the song url. So i have a function that uses some API to get all these thing. So I want to use that function to get song details and play it but without using flutter UI because if UI is absent i.e. background it will not call the function – Ankit Sangwan Feb 12 '21 at 03:32
-
I want to use that function with audio_service such that every time song changes it calls that function, get details and plays song then move to next item in the queue, call function, get details and play and so on, everything in AudioServiceBackground without using Flutter UI – Ankit Sangwan Feb 12 '21 at 03:33
-
The reason I'm asking why you need to set the queue is that the only purpose of this is to broadcast the queue to the client/UI for display purposes. If you only fetch metadata for the current song when the song changes, maybe you would have missing metadata for some queue items until the user eventually plays that item, so I'm not sure how you would actually display this incomplete queue. How do you want the queue to be displayed before all metadata has loaded? – Ryan Heise Feb 12 '21 at 07:23
-
I don't want to show the queue somewhere all I need is just skip-next, skip-previous to skip to next or previous song in the queue and keep working even though the app is in background. Basically, I'm making an [app](https://github.com/Sangwan5688/BlackHole) just like Spotify. And even if in future I want to show metadata then I have enough metadata to show I just don't have the play link. And I'm using an API to get play link – Ankit Sangwan Feb 12 '21 at 07:59
-
Can you edit your question to clarify that? – Ryan Heise Feb 12 '21 at 11:51
-
I have edited it. – Ankit Sangwan Feb 12 '21 at 13:33
-
Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/228634/discussion-between-ryan-heise-and-ankit-sangwan). – Ryan Heise Feb 12 '21 at 13:57
1 Answers
The URL is not required when setting the queue. You can set each MediaItem
's ID to your unique song ID, and amend this data later by storing the URL in the extras
field when it becomes known.
First, I suggest this startup sequence:
await AudioService.start(backgroundTaskEntrypoint: _entrypoint);
await AudioService.updateQueue(songs);
AudioService.play();
(For v0.18 and later, you no longer call start
, and you replacy AudioService.
with audioHandler.
)
In your background audio task (v0.17) or audio handler (v0.18), you would want fields to store your player and queue:
AudioPlayer _player = AudioPlayer();
List<MediaItem> _queue = [];
onStart
(v0.17) or your audio handler constructor (v0.18) doesn't need to do anything except any initialisation you want to do on your player, such as registering listeners for events (e.g. listen for when the currently playing audio completes so that you can call skipToNext()
). You should implement the callback for updateQueue
as follows:
// 0.17 solution:
Future<void> onUpdateQueue(List<MediaItem> queue) =>
await AudioServiceBackground.setQueue(_queue = queue);
// 0.18 solution:
Future<void> updateQueue(List<MediaItem> newQueue) async {
queue.add(_queue = newQueue);
await super.updateQueue(newQueue);
}
And for the play
callback:
// 0.17 solution:
Future<void> onPlay() => _player.play();
// 0.18 solution:
Future<void> play() => _player.play();
You will also want to implement the skipToQueueItem
callback:
// 0.17 solution:
Future<void> onSkipToQueueItem(String mediaId) async {
final index = _queue.indexWhere((item) => item.id == mediaId);
if (_queue[index].extras['url'] == null) {
// fetch from your API and update queue
_queue[index] = _queue[index].copyWith(
extras: {'url': await fetchUrl(_queue[index].id),
);
await AudioServiceBackground.setQueue(_queue);
}
await AudioServiceBackground.setMediaItem(_queue[index]);
// load URL into player
await _player.setUrl(_queue[index].extras['url']);
}
// 0.18 solution
Future<void> skipToQueueItem(index) async {
if (_queue[index].extras['url'] == null) {
// fetch from your API and update queue
_queue[index] = _queue[index].copyWith(
extras: {'url': await fetchUrl(_queue[index].id),
);
queue.add(_queue);
}
await mediaItem.add(_queue[index]);
// load URL into player
await _player.setUrl(_queue[index].extras['url']);
}
The default implementations of the skipToNext/skipToPrevious
callbacks are defined in terms of this.
Since your API call loads each URL separately on demand, this will create a gap between each song. just_audio can support gapless playback if you can stack together multiple URLs in advance.

- 2,273
- 5
- 14
-
Well, everything works fine but whenever I change song then only the Image, title, etc changes not the song. The same song keeps playing only metadata changes – Ankit Sangwan Feb 16 '21 at 04:47
-
Dart map keys are case sensitive, so using `extras['URL']` will not work since you stored the URL into the extras map with the lowercase key `url`. – Ryan Heise Feb 16 '21 at 15:59
-
I knew that what I didn't know was that I did a silly mistake at that one place and wrote `url` instead of `URL`. Thanks for pointing out – Ankit Sangwan Feb 16 '21 at 16:22
-
Hi, one last thing. When I was using a predefined list of `MediaItem`s to check it was working fine. But when I'm integrating it with my app and receiving MediaItems from other parts of the app then it's not playing. I guess something is wrong with my part of code where I setup MediaItem List. Can you check once: https://pastebin.com/QNgcitp4 – Ankit Sangwan Feb 17 '21 at 08:44
-
I didn't find anything suspicious in the code (aside from some missing `await` keywords), although it is a bit impractical to debug a program this large in the StackOverflow comments section. However, my advice would be that since you did have it working with a hard-coded list, it should be relatively easy to debug by starting from that working code as a base, and then just change one small thing at a time until it breaks, then you will know what it is. That will at least inform you as to where to insert your debug print statements. – Ryan Heise Feb 17 '21 at 14:39
-
I tried doing that but got nothing. All the I could find is that the queue becomes an empty list while playing but when I set queue it is complete. And I couldn't find anything suspicious. – Ankit Sangwan Feb 17 '21 at 15:26
-
Hi, I just wanted to confirm is the audio service code initialised at the start of the app? I found that whatever parameter I try to access in audioservice code from other parts of the code. It takes the initial values. The code was working fine when hard-coded coz all the parameters had their valve. But when I try initializing the list as empty or anything then it takes the initial valve i.e. empty or predefined in case of hardcoded. Is there a suggested way to pass values to the audio service code? Which way would you like to suggest to pass the queue to the audio service code – Ankit Sangwan Feb 19 '21 at 15:25
-
When you say "from other parts of the code" are those other parts in the same isolate as each other? Remember that there is a client/server model between the isolates and all communication should go through the provided message passing API. – Ryan Heise Feb 20 '21 at 03:31
-
https://stackoverflow.com/questions/66278441/getting-initialized-values-of-parameters-even-after-changing-them?noredirect=1#comment117185423_66278441 – Ankit Sangwan Feb 20 '21 at 03:40
-
I mean from other files. Like the audioservice code is in an file named `audioplayer.dart` and I'm trying to get the queue from `playlist.dart`. So what is heppening is that I'm trying to get mediaItems list defined in `playlist.dart`. When I initialize it to be empty list of MediaItems and then add some MediaItems and then start the audioservice and it's getting the initialized list. If I hardcode the list with some mediaItems and then change it and start audioservice then it gets the hardcoded list i.e. the one initialized. That's the reason it was working with hard-coded code – Ankit Sangwan Feb 20 '21 at 03:42