Flutter just_audio 循环模式不循环
Flutter just_audio loop mode is not looping
我正在使用 flutter audio_service (https://pub.dev/packages/audio_service) and 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,但您的音频代码似乎一半 inside 一半 outside 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,所以你实际上不需要改变你的编程风格来支持前景情况。
在你的 BackgroundAudioTask
subclass 中你应该覆盖 onSetRepeatMode
方法。
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
class AudioPlayerTask extends BackgroundAudioTask {
AudioPlayer _player = new AudioPlayer();
...
@override
Future<void> onSetRepeatMode(AudioServiceRepeatMode repeatMode) async {
switch (repeatMode) {
case AudioServiceRepeatMode.none:
await _player.setLoopMode(LoopMode.off);
break;
case AudioServiceRepeatMode.one:
await _player.setLoopMode(LoopMode.one);
break;
case AudioServiceRepeatMode.all:
case AudioServiceRepeatMode.group:
await _player.setLoopMode(LoopMode.all);
break;
}
}
}
此特定实现使用 just_audio as the audio player. Note that AudioPlayerTask
is the only class that the just_audio AudioPlayer
appears in. It shouldn't be in any other class of your app. Everywhere else you'll use audio_service 的 AudioService
class。
例如,当用户按下按钮时,您可以运行以下代码行:
AudioService.setRepeatMode(AudioServiceRepeatMode.none);
这将通知系统并让 BackgroundAudioTask
运行 onSetRepeatMode
以便内部 AudioPlayer
class 可以做它的事情。
我的做法是简单地放入 onStart 方法:
await _player.setLoopMode(LoopMode.all);
这当然是用户无法更改的。
我正在使用 flutter audio_service (https://pub.dev/packages/audio_service) and 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,但您的音频代码似乎一半 inside 一半 outside 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,所以你实际上不需要改变你的编程风格来支持前景情况。
在你的 BackgroundAudioTask
subclass 中你应该覆盖 onSetRepeatMode
方法。
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
class AudioPlayerTask extends BackgroundAudioTask {
AudioPlayer _player = new AudioPlayer();
...
@override
Future<void> onSetRepeatMode(AudioServiceRepeatMode repeatMode) async {
switch (repeatMode) {
case AudioServiceRepeatMode.none:
await _player.setLoopMode(LoopMode.off);
break;
case AudioServiceRepeatMode.one:
await _player.setLoopMode(LoopMode.one);
break;
case AudioServiceRepeatMode.all:
case AudioServiceRepeatMode.group:
await _player.setLoopMode(LoopMode.all);
break;
}
}
}
此特定实现使用 just_audio as the audio player. Note that AudioPlayerTask
is the only class that the just_audio AudioPlayer
appears in. It shouldn't be in any other class of your app. Everywhere else you'll use audio_service 的 AudioService
class。
例如,当用户按下按钮时,您可以运行以下代码行:
AudioService.setRepeatMode(AudioServiceRepeatMode.none);
这将通知系统并让 BackgroundAudioTask
运行 onSetRepeatMode
以便内部 AudioPlayer
class 可以做它的事情。
我的做法是简单地放入 onStart 方法:
await _player.setLoopMode(LoopMode.all);
这当然是用户无法更改的。