【问题标题】:How to fetch song details every time from an API before playing in just_audio and audio_service在 just_audio 和 audio_service 中播放之前,如何每次从 API 获取歌曲详细信息
【发布时间】:2021-02-11 12:49:18
【问题描述】:

我想使用audio_servicejust_audio 在后台播放音频。但问题是我必须在所有元数据开始时设置队列,以确保即使应用程序处于后台,它们也会自动运行。但我没有播放歌曲的歌曲网址。相反,我有一个可用于获取歌曲播放 URL 的函数。现在我想每次都调用该函数来获取歌曲播放 URL 并使用该 URL 播放歌曲。我想在 AudioBackgroundService 的代码中调用该函数,而不是在我的颤振 UI 的代码中。因为如果我的 UI 不存在,即在后台,则不会调用该函数。因此,要确保每次必须在 AudioServiceBackground 代码中调用该函数。有没有办法这样做?我正在使用audio_service documentation 中提供的相同代码。我想我必须在 AudioService 的onStart 函数中使用该函数,但我仍然无法找到出路。此外,如果它可以在播放当前歌曲的同时为下一首歌曲调用该函数会更好。

【问题讨论】:

  • 我不确定我是否理解这个问题。 “问题是我必须在开始时设置队列”。为什么你必须在开始时设置队列?
  • 对不起,如果我不清楚。实际上,我想使用 just_audio 和 audio_service 在后台运行歌曲。他们实际上需要排队才能开始播放所以我必须添加队列以确保它们在后台运行
  • 问题是我没有任何详细信息可以将歌曲添加到队列中。所以首先我需要标题、艺术家甚至歌曲网址等详细信息。所以我有一个使用一些 API 来获取所有这些东西的函数。所以我想使用该函数来获取歌曲详细信息并播放它,但不使用 Flutter UI,因为如果 UI 不存在,即背景,它将不会调用该函数
  • 我想将该函数与 audio_service 一起使用,这样每次歌曲更改时它都会调用该函数,获取详细信息并播放歌曲,然后移动到队列中的下一个项目,调用函数,获取详细信息并播放等等开启,AudioServiceBackground 中的所有内容都无需使用 Flutter UI
  • 我问你为什么需要设置队列的原因是这样做的唯一目的是将队列广播到客户端/用户界面以进行显示。如果您只在歌曲更改时获取当前歌曲的元数据,那么在用户最终播放该项目之前,您可能会丢失某些队列项目的元数据,所以我不确定您将如何实际显示这个不完整的队列。您希望在加载所有元数据之前如何显示队列?

标签: android flutter dart flutter-layout just-audio


【解决方案1】:

设置队列时不需要 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 回调的默认实现是根据 this 定义的。

由于您的 API 调用会根据需要分别加载每个 URL,因此这会在每首歌曲之间产生间隙。如果您可以提前将多个 URL 堆叠在一起,just_audio 可以支持无缝播放。

【讨论】:

  • 嗯,一切正常,但每当我改变歌曲时,只有图像、标题等改变了歌曲。同一首歌曲一直在播放,只有元数据发生变化
  • Dart 映射键区分大小写,因此使用 extras['URL'] 将不起作用,因为您使用小写键 url 将 URL 存储到附加映射中。
  • 我知道我不知道的是我在那个地方犯了一个愚蠢的错误并写了url而不是URL。谢谢指出
  • 嗨,最后一件事。当我使用MediaItems 的预定义列表来检查它是否工作正常时。但是当我将它与我的应用程序集成并从应用程序的其他部分接收 MediaItems 时,它就不会播放。我想我设置 MediaItem 列表的部分代码有问题。你能检查一次吗:pastebin.com/QNgcitp4
  • 我没有在代码中发现任何可疑之处(除了缺少一些 await 关键字),尽管在 StackOverflow cmets 部分调试这么大的程序有点不切实际。但是,我的建议是,由于您确实使用硬编码列表工作,因此从该工作代码作为基础开始调试应该相对容易,然后一次只更改一件小事,直到它坏掉,然后你就会知道它是什么。这至少会告诉你在哪里插入你的调试打印语句。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 2013-05-20
  • 2021-03-18
  • 1970-01-01
  • 2022-12-22
  • 2014-06-04
  • 2014-10-15
相关资源
最近更新 更多