如何在 just_audio 和 audio_service 中播放之前每次从 API 中获取歌曲详细信息
How to fetch song details every time from an API before playing in just_audio and audio_service
我想使用 audio_service
和 just_audio
在后台播放音频。但问题是我必须在开始时使用所有元数据设置队列,以确保即使应用程序处于后台,它们也会自动 运行 。但是我没有 song URLs 来播放这首歌。相反,我有一个函数可以用来播放歌曲 URLs。现在我想每次都调用该函数来播放歌曲 URL 并使用 URL 来播放歌曲。我想在 AudioBackgroundService 的代码中调用那个函数,而不是在我的 flutter UI 的代码中。因为如果我的 UI 不存在,即在后台,那么该函数将不会被调用。因此,要确保每次必须在 AudioServiceBackground 代码中调用该函数。有办法吗?我使用的是 audio_service documentation 中提供的相同代码。我想我必须在 AudioService 的 onStart
函数中使用该函数,但我仍然想不出出路。另外,如果它能在播放当前歌曲的同时为下一首歌曲调用该函数,那就更好了。
设置队列时不需要URL。您可以将每个 MediaItem
的 ID 设置为您唯一的歌曲 ID,并在知道后通过将 URL 存储在 extras
字段中来修改此数据。
首先,我建议这样的启动顺序:
await AudioService.start(backgroundTaskEntrypoint: _entrypoint);
await AudioService.updateQueue(songs);
AudioService.play();
(v0.18及之后版本,不再调用start
,将AudioService.
替换为audioHandler.
)
在您的后台音频任务 (v0.17) 或音频处理程序 (v0.18) 中,您需要字段来存储您的播放器和队列:
AudioPlayer _player = AudioPlayer();
List<MediaItem> _queue = [];
onStart
(v0.17) 或您的音频处理程序构造函数 (v0.18) 除了您想在播放器上执行的任何初始化外不需要执行任何操作,例如为事件注册侦听器 (例如,监听当前播放的音频何时播放完毕,以便您可以调用 skipToNext()
)。您应该按如下方式实现 updateQueue
的回调:
// 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);
}
对于 play
回调:
// 0.17 solution:
Future<void> onPlay() => _player.play();
// 0.18 solution:
Future<void> play() => _player.play();
您还需要实施 skipToQueueItem
回调:
// 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']);
}
skipToNext/skipToPrevious
回调的默认实现是根据此定义的。
由于您的 API 调用会按需分别加载每个 URL,因此这会在每首歌曲之间造成间隙。 just_audio如果可以提前叠加多个URL就可以支持无缝播放。
我想使用 audio_service
和 just_audio
在后台播放音频。但问题是我必须在开始时使用所有元数据设置队列,以确保即使应用程序处于后台,它们也会自动 运行 。但是我没有 song URLs 来播放这首歌。相反,我有一个函数可以用来播放歌曲 URLs。现在我想每次都调用该函数来播放歌曲 URL 并使用 URL 来播放歌曲。我想在 AudioBackgroundService 的代码中调用那个函数,而不是在我的 flutter UI 的代码中。因为如果我的 UI 不存在,即在后台,那么该函数将不会被调用。因此,要确保每次必须在 AudioServiceBackground 代码中调用该函数。有办法吗?我使用的是 audio_service documentation 中提供的相同代码。我想我必须在 AudioService 的 onStart
函数中使用该函数,但我仍然想不出出路。另外,如果它能在播放当前歌曲的同时为下一首歌曲调用该函数,那就更好了。
设置队列时不需要URL。您可以将每个 MediaItem
的 ID 设置为您唯一的歌曲 ID,并在知道后通过将 URL 存储在 extras
字段中来修改此数据。
首先,我建议这样的启动顺序:
await AudioService.start(backgroundTaskEntrypoint: _entrypoint);
await AudioService.updateQueue(songs);
AudioService.play();
(v0.18及之后版本,不再调用start
,将AudioService.
替换为audioHandler.
)
在您的后台音频任务 (v0.17) 或音频处理程序 (v0.18) 中,您需要字段来存储您的播放器和队列:
AudioPlayer _player = AudioPlayer();
List<MediaItem> _queue = [];
onStart
(v0.17) 或您的音频处理程序构造函数 (v0.18) 除了您想在播放器上执行的任何初始化外不需要执行任何操作,例如为事件注册侦听器 (例如,监听当前播放的音频何时播放完毕,以便您可以调用 skipToNext()
)。您应该按如下方式实现 updateQueue
的回调:
// 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);
}
对于 play
回调:
// 0.17 solution:
Future<void> onPlay() => _player.play();
// 0.18 solution:
Future<void> play() => _player.play();
您还需要实施 skipToQueueItem
回调:
// 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']);
}
skipToNext/skipToPrevious
回调的默认实现是根据此定义的。
由于您的 API 调用会按需分别加载每个 URL,因此这会在每首歌曲之间造成间隙。 just_audio如果可以提前叠加多个URL就可以支持无缝播放。