我正在使用flutter audio_service(https://pub.dev/packages/audio_service)和just_audio(https://pub.dev/packages/just_audio)在前景和背景中播放音频文件。
我将BackgroundAudioTask子类化,添加了AudioPlayer的实例,并覆盖了所需的方法。例如,我更新了重复模式:
@override
Future<void> onSetRepeatMode(AudioServiceRepeatMode repeatMode) async {
super.onSetRepeatMode(repeatMode);
switch (repeatMode)
{
case AudioServiceRepeatMode.all:
_audioPlayer.setLoopMode(LoopMode.all);
break;
case AudioServiceRepeatMode.none:
_audioPlayer.setLoopMode(LoopMode.off);
break;
case AudioServiceRepeatMode.one:
_audioPlayer.setLoopMode(LoopMode.one);
break;
case AudioServiceRepeatMode.group:
_audioPlayer.setLoopMode(LoopMode.all);
break;
}
}
@override
Future<void> onPlayFromMediaId(String mediaId) async {
await _audioPlayer.stop();
// Get queue index by mediaId.
_queueIndex = _queue.indexWhere((test) => test.id == mediaId);
// Set url source to _audioPlayer.
downloadAndPlay(_mediaItem);
}
我正在尝试添加一个播放列表并有一个音频文件循环,但是似乎丢失了一些,播放了#1曲目后,播放器想从同一#1曲目开始并再次播放。这是我的代码(downloadAndPlay的一部分):
var list=List<AudioSource>();
for (int t=0;t<_queue.length;t++)
{
var mi=_queue[t];
var url = mi.extras['source'];
list.add(AudioSource.uri(Uri.parse(url)));
}
D("Loading list with ${list.length} items");
D("Seeking to index : $_queueIndex");
await _audioPlayer.load(ConcatenatingAudioSource(children: list),
initialIndex: _queueIndex, initialPosition: Duration.zero);
AudioService.updateQueue(_queue);
AudioService.setRepeatMode(AudioServiceRepeatMode.all);
_audioPlayer.play();
我添加了此代码,以检查是否触发了ProcessingState.completed,这意味着它已到达轨道的尽头,但并未触发:
playerEventSubscription = _audioPlayer.playbackEventStream.listen((event) {
D("audioPlayerTask: playbackEventStream : ${event.processingState}");
switch (event.processingState) {
case ProcessingState.ready:
_setState(state: AudioProcessingState.ready);
break;
case ProcessingState.buffering:
_setState(state: AudioProcessingState.buffering);
break;
case ProcessingState.completed:
_handlePlaybackCompleted();
break;
default:
break;
}
});
你从未调用过,_audioPlayer.setLoopMode()
因此它不会循环。
你还使用了audio_service,但是你的音频代码似乎在audio_service的一半内,而在audio_service的一半外。具体来说,你的实例_audioPlayer
生活在audio_service之外,而你的实现则setRepeatMode
生活在audio_service之内,并且将无法访问你_audioPlayer
在audio_service之外的实例。
将所有音频逻辑封装在audio_service中,以便你的setRepeatMode
实现能够引用你的_audioPlayer
实例并对其进行调用_audioPlayer.setLoopMode()
。这实际上就是我们封装(将方法与它们需要操作的数据捆绑在一起)的原因,但是在这种情况下,我们在audio_service中进行封装还有另一个原因,那就是audio_service之外的所有东西都“封装”了随时可能被摧毁。因此,如果你的应用程序转换为后台并且UI被破坏,则你不希望音频逻辑的一半被破坏。如果将它们全部封装在audio_service中,它将能够在UI毁灭后幸存下来,并且由于它是自包含的,因此它具有在后台继续播放音频所需的一切。
而且,事实上,你的应用程序可能还想玩的前景音频并不意味着你需要打破封装。这种封装的音频代码完全可以在没有UI的情况下与UI一起运行,因此你实际上不需要更改编程样式即可支持前台情况。
我分享的不够多,但是_audioPlayer在BackgroundAudioTask的范围之内。我在那里重写onSetRepeatMode(在上面的代码中更新)。但是仍然无法正常工作!
有一段代码块,您可以在其中使用客户端API(例如AudioService.updateQueue)将消息“从客户端”发送到后台任务。相同的代码块(在客户端)引用了一个名为_audioPlayer的变量。因此,该音频播放器在客户端,而不在后台任务中。您从未在该播放器上调用_audioPlayer.setLoopMode()。如果该块实际上在后台任务中,则看起来不像它。它使用的是客户端API,因此该代码在这种解释中也没有意义。您需要清楚地将两层分开。
我想我发现了问题:当轨道结束并开始播放下一个轨道时,AudioService.currentMediaItemStream不会触发。
正如我在上面解释的那样,您似乎有两个不同的_audioPlayer变量,一个在后台任务内部,另一个在外部,并且您正在混在一起,使用媒体源加载其中的一个,但使用循环模式配置另一个。如果不是这种情况,则需要回答我之前的评论,并说明所讨论的代码块是在后台音频任务内部还是外部,如果在内部,为什么要使用仅应从外部使用的客户端API。
不,先生,我没有使用两个音频播放器,只是一个,它完全位于您订购的BackgroundAudioTask子类中:)但是,当轨道自动转到下一个时,AudioService.currentMediaItemStream不会添加任何内容。