flutter audio_service:完全播放媒体项目后 AudioProcessingState 未更新
flutter audio_service: AudioProcessingState not updating after completely playing media item
我正在用 flutter 开发一个音乐播放器应用程序。
场景:
当用户从列表中选择一首歌曲时,一旦选择的歌曲完全播放,自动需要开始列表中的下一首歌曲。
目前我正在收听 PlaybackState
、Position
流,以便在 UI 上更新歌曲详细信息和滑块信息。但是,我无法确定所选歌曲何时播放完毕。这里的想法是,一旦播放了选定的歌曲,就必须播放列表中的下一首歌曲。
最初,AudioProcessingState 从连接状态变为就绪状态。第一个媒体项目已成功播放。但是,
问题 1:
即使在第一个媒体项目完全播放之后,AudioProcessingState 仍然是 ready
(未更改为完成)。就连演奏也总是true
。下面是播放和暂停 UI.
的逻辑
StreamBuilder<PlaybackState>(
stream: AudioService.playbackStateStream,
builder: (context, snapshot) {
final processingState = snapshot.data?.processingState;
print('Current Processingstate: $processingState');
final playing = snapshot.data?.playing ?? false;
if (playing)
return IconButton(
iconSize: 40,
onPressed: () {
AudioService.pause();
},
icon: Icon(FontAwesomeIcons.pause,
color: Colors.white));
else
return IconButton(
iconSize: 40,
onPressed: () {
if (AudioService.running) {
AudioService.play();
} else {
List<dynamic> list = [];
for (int i = 0;
i < this.widget.mediaList.length;
i++) {
var m = this.widget.mediaList[i].toJson();
list.add(m);
}
var params = {
"data": list,
'index': this.widget.currentIndex
};
AudioService.connect();
AudioService.start(
backgroundTaskEntrypoint:
_backgroundTaskEntrypoint,
params: params);
}
},
icon: Icon(FontAwesomeIcons.play,
color: Colors.white));
},
),
问题二:
此外,即使在完成所选歌曲后,位置流也会持续接收。因此,我无法停止更新持续时间标签。
StreamBuilder<Duration>(
stream: AudioService.positionStream,
builder: (context, snapshot) {
final mediaState = snapshot.data;
return SeekBar(
duration: this.widget.mediaList[current].duration ??
Duration.zero,
position: aPosition,
onChangeEnd: (newPosition) {
AudioService.seekTo(newPosition);
},
);
},
),
简而言之,
- 如何知道所选歌曲播放完毕?
- 歌曲播放完毕后如何更新滑块?
有一项未完成的功能请求,要求添加一种新型的事件订阅,当玩家自动前进到序列中的下一个项目时,它会通知您 here。您可以通过点击竖起大拇指按钮为该功能投票。
但是,this comment 中还描述了一种解决方法。您可以做的是收听 player.currentIndexStream
,它会在当前项目发生变化时告诉您。当玩家自动前进到下一个项目时,这个索引会改变,但你不能假设每次当前索引改变都是因为自动前进,因为它也可能是因为手动搜索.出于这个原因,解决方法是只保留一个布尔变量,指示是否使用了手动搜索,以便您了解情况。每次搜索时,将该布尔变量设置为 true,并在搜索完成后将其设置回 false。
为了方便起见,您可以制作自己的搜索方法版本来执行此操作,例如mySeek
甚至将此作为扩展方法添加到 AudioPlayer
:
bool _seeking = false;
extension AudioPlayerExtension on AudioPlayer {
Future<void> mySeek(Duration position, {int? index}) async {
_seeking = true;
await seek(position);
_seeking = false;
}
}
那么解决的另一部分就是听currentIndexStream
:
_player.currentIndexStream.listen((index) {
if (index == null) return;
if (_seeking) {
// the index changed due to a manual seek
} else {
// the index changed due to an auto-advance
onAutoAdvance();
}
});
所以现在,每次你想手动搜索不同的项目时,你使用:
player.mySeek(pos, index: i);
然后在项目因自动推进而更改时处理,在此处编写代码来处理它:
void onAutoAdvance() {
}
我正在用 flutter 开发一个音乐播放器应用程序。
场景: 当用户从列表中选择一首歌曲时,一旦选择的歌曲完全播放,自动需要开始列表中的下一首歌曲。
目前我正在收听 PlaybackState
、Position
流,以便在 UI 上更新歌曲详细信息和滑块信息。但是,我无法确定所选歌曲何时播放完毕。这里的想法是,一旦播放了选定的歌曲,就必须播放列表中的下一首歌曲。
最初,AudioProcessingState 从连接状态变为就绪状态。第一个媒体项目已成功播放。但是,
问题 1:
即使在第一个媒体项目完全播放之后,AudioProcessingState 仍然是 ready
(未更改为完成)。就连演奏也总是true
。下面是播放和暂停 UI.
StreamBuilder<PlaybackState>(
stream: AudioService.playbackStateStream,
builder: (context, snapshot) {
final processingState = snapshot.data?.processingState;
print('Current Processingstate: $processingState');
final playing = snapshot.data?.playing ?? false;
if (playing)
return IconButton(
iconSize: 40,
onPressed: () {
AudioService.pause();
},
icon: Icon(FontAwesomeIcons.pause,
color: Colors.white));
else
return IconButton(
iconSize: 40,
onPressed: () {
if (AudioService.running) {
AudioService.play();
} else {
List<dynamic> list = [];
for (int i = 0;
i < this.widget.mediaList.length;
i++) {
var m = this.widget.mediaList[i].toJson();
list.add(m);
}
var params = {
"data": list,
'index': this.widget.currentIndex
};
AudioService.connect();
AudioService.start(
backgroundTaskEntrypoint:
_backgroundTaskEntrypoint,
params: params);
}
},
icon: Icon(FontAwesomeIcons.play,
color: Colors.white));
},
),
问题二: 此外,即使在完成所选歌曲后,位置流也会持续接收。因此,我无法停止更新持续时间标签。
StreamBuilder<Duration>(
stream: AudioService.positionStream,
builder: (context, snapshot) {
final mediaState = snapshot.data;
return SeekBar(
duration: this.widget.mediaList[current].duration ??
Duration.zero,
position: aPosition,
onChangeEnd: (newPosition) {
AudioService.seekTo(newPosition);
},
);
},
),
简而言之,
- 如何知道所选歌曲播放完毕?
- 歌曲播放完毕后如何更新滑块?
有一项未完成的功能请求,要求添加一种新型的事件订阅,当玩家自动前进到序列中的下一个项目时,它会通知您 here。您可以通过点击竖起大拇指按钮为该功能投票。
但是,this comment 中还描述了一种解决方法。您可以做的是收听 player.currentIndexStream
,它会在当前项目发生变化时告诉您。当玩家自动前进到下一个项目时,这个索引会改变,但你不能假设每次当前索引改变都是因为自动前进,因为它也可能是因为手动搜索.出于这个原因,解决方法是只保留一个布尔变量,指示是否使用了手动搜索,以便您了解情况。每次搜索时,将该布尔变量设置为 true,并在搜索完成后将其设置回 false。
为了方便起见,您可以制作自己的搜索方法版本来执行此操作,例如mySeek
甚至将此作为扩展方法添加到 AudioPlayer
:
bool _seeking = false;
extension AudioPlayerExtension on AudioPlayer {
Future<void> mySeek(Duration position, {int? index}) async {
_seeking = true;
await seek(position);
_seeking = false;
}
}
那么解决的另一部分就是听currentIndexStream
:
_player.currentIndexStream.listen((index) {
if (index == null) return;
if (_seeking) {
// the index changed due to a manual seek
} else {
// the index changed due to an auto-advance
onAutoAdvance();
}
});
所以现在,每次你想手动搜索不同的项目时,你使用:
player.mySeek(pos, index: i);
然后在项目因自动推进而更改时处理,在此处编写代码来处理它:
void onAutoAdvance() {
}