如何在 just_audio 和 audio_service 中播放之前每次从 API 中获取歌曲详细信息

How to fetch song details every time from an API before playing in just_audio and audio_service

我想使用 audio_servicejust_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就可以支持无缝播放。