flutter audio_service: AudioProcessingState не обновляется после полного воспроизведения медиа-элемента
Я разрабатываю приложение для музыкального плеера на флаттере.
Сценарий: когда пользователь выбирает одну песню из списка, после того, как выбранная песня полностью воспроизведена, автоматически необходимо запустить следующую песню в списке.
Сейчас слушаю
Проблема 1. Даже после полного воспроизведения первого элемента мультимедиа состояние AudioProcessingState все еще
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));
},
),
Проблема 2: Кроме того, поток Position получает непрерывный поток даже после завершения выбранной песни. Из-за этого я не могу перестать обновлять метку продолжительности.
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);
},
);
},
),
Вкратце,
- Как я могу узнать, что воспроизведение выбранной песни завершено?
- Как обновить ползунок после завершения воспроизведения песни?
1 ответ
Существует нереализованный запрос функции на добавление нового типа подписки на события, которая может проинформировать вас, когда игрок автоматически переходит к следующему элементу в последовательности здесь. Вы можете проголосовать за эту функцию, нажав кнопку «Нравится».
Однако в этом комментарии также есть обходной путь . Что вы можете сделать, так это послушать
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();
}
skipped = false;
});
Итак, теперь, каждый раз, когда вы хотите вручную перейти к другому элементу, вы используете:
player.mySeek(pos, index: i);
А затем, чтобы обработать, когда элемент изменился из-за автоматического продвижения, напишите свой код для его обработки здесь:
void onAutoAdvance() {
}