just_audio - 完成后的音频播放器,从头开始

问题描述 投票:0回答:4

我创建了播放器音频并使用了 just_audio 插件,当音频播放器完成并且不返回到开头时我遇到问题。我尝试使用

player.playerStateStream.listen()
,但是当我点击播放图标时,它不播放音频,并且开始持续时间也不会更改为0,但是当我手动移动滑块时,它可以工作,如何解决这个问题?

enter image description here

编辑:

我需要什么?

我需要在音频完成后将滑块返回到开头并重置持续时间,就像我第一次播放音频一样,并使用

onPressed
播放音频暂停音频。

代码:

String currentTime = "", endTime = "";
double minDuration = 0, maxDuration = 0, currentDuration = 0;

void setAudio(String url) async {
    setState(() => isLoadAudio = true);
    await player.setUrl(url);
    currentDuration = minDuration;
    maxDuration = player.duration!.inMilliseconds.toDouble();
    setState(() {
      currentTime = getDuration(currentDuration);
      endTime = getDuration(maxDuration);
    });
    isPlaying = false;
    changeStatusPlaying();
    player.positionStream.listen((duration) {
      currentDuration = duration.inMilliseconds.toDouble();
      setState(() => currentTime = getDuration(currentDuration));
    });
    setState(() => isLoadAudio = false);
    player.playerStateStream.listen((state) {
      if (state.processingState == ProcessingState.completed) {
        setState(() {
          currentDuration = minDuration;
          if (isRepeating == true) {
            isPlaying = true;
          } else {
            isPlaying = false;
            isRepeating = false;
          }
        });
      }
    });
  }
void changeStatusPlaying() {
    setState(() => isPlaying = !isPlaying);
    isPlaying ? player.play() : player.pause();
    currentDuration == maxDuration ? isPlaying : !isPlaying;
  }

String getDuration(double value) {
    Duration duration = Duration(milliseconds: value.round());
    return [duration.inHours, duration.inMinutes, duration.inSeconds]
        .map((e) => e.remainder(60).toString().padLeft(2, "0"))
        .join(":");
  }

Slider(
   value: currentDuration,
   min: minDuration,
   max: maxDuration,
   onChanged: (v) {
     currentDuration = v;
     playAudio(currentDuration);
   },
),
flutter dart audio slider just-audio
4个回答
3
投票
Try this:
        
bool _isPlaying = false;
bool _isCompleted = false;
Duration? _duration = Duration.zero;
Duration? _position = Duration.zero; 
                
After player has completed, move position to Duration(seconds: 0)   
                        
            Init state  
                            
                            @override
                              void initState() {
                                _initLoadFile();
                                // Listen player states
                                _audioPlayer.playerStateStream.listen((event) async {
                                  setState(() {
                                    _isPlaying = event.playing;
                                  });
                                  if (event.processingState == ProcessingState.completed) {
                                    setState(() {
                                      _isPlaying = false;
                                      _position = const Duration(seconds: 0);
                                      _isCompleted = true;
                                    });
                                  }
                                });
                                // Listen audio duration
                                _audioPlayer.durationStream.listen((newDuration) {
                                  setState(() {
                                    _duration = newDuration;
                                  });
                                });
                                // Listen audio position
                                _audioPlayer.positionStream.listen((newPosition) {
                                  setState(() {
                                    _position = newPosition;
                                  });
                                });
                                super.initState();
                              }
                            
                            
                    In widget
                            
                    ElevatedButton(
                                  onPressed: () async {
                                    if (!_isPlaying) {
                                      setState(() {
                                        _isPlaying = true;
                                        _isCompleted = false;
                                      });
                                      await _audioPlayer.play();
                                      if (_isCompleted) {
                                        await _audioPlayer.seek(const Duration(seconds: 0));
                                        await _audioPlayer.pause();
                                      }
                                    }
                                    if (_isPlaying) {
                                      setState(() {
                                        _isPlaying = false;
                                      });
                                      await _audioPlayer.pause();
                                    }
                                  },
                                  child: Icon(
                                    _isPlaying ? Icons.pause : Icons.play_arrow,
                                  ),
                                ),

0
投票

将音频播放器设置为循环播放:

player.setLoopMode(LoopMode.one);

完整示例(将音频文件放在 /assets/audio):

class MySimplePlayer extends StatefulWidget {
  final String name, asset;

  const MySimplePlayer(this.name, String filename)
      : this.asset = "assets/audio/$filename";

  @override
  _MySimplePlayerState createState() => _MySimplePlayerState();
}

class _MySimplePlayerState extends State<MySimplePlayer> {
  late AudioPlayer player;
  bool _ready = false;

  @override
  void initState() {
    super.initState();
    player = AudioPlayer();
    player.setLoopMode(LoopMode.one);    
    player.setAsset(widget.asset).then((_) {
      if (mounted) setState(() => _ready = true);
    });
  }

  @override
  void dispose() {
    player.stop();
    player.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (!_ready) return const SizedBox();

    return Card(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          const SizedBox(width: 16),
          Expanded(child: Text(widget.name)),
          if (!player.playing)
            IconButton(
              icon: Icon(Icons.play_arrow),
              onPressed: () async {
                player.play();
                setState(() {});
              },
            ),
          if (player.playing)
            IconButton(
              icon: Icon(Icons.pause),
              onPressed: () async {
                await player.pause();
                setState(() {});
              },
            ),
          IconButton(
            icon: Icon(Icons.stop),
            onPressed: () async {
              await player.stop();
              setState(() {});
            },
          ),
          const SizedBox(width: 16),
        ],
      ),
    );
  }
}

0
投票

我通过在processingState完成后暂停音频来解决这个问题,然后player.seek(Duration.zero);

StreamBuilder<PlayerState>(
      stream: player.playerStateStream,
      builder: (context, snapshot) {
         if (snapshot.data?.processingState ==
             ProcessingState.completed) {
             player.pause();
              player.seek(Duration.zero);
            }

             return Icon(
                snapshot.data?.playing == true
                    ? Icons.pause
                    : Icons.play_arrow,
        );
   }),

0
投票

我尝试使用 JS 编程中的一个古老(肮脏)技巧,它似乎有效。

让音频播放器状态机结束

completed
事件通知过程,然后再要求播放器更改其状态(使用
.pause()
.seek()
,...)。这可以通过使用
Future
(JS 世界中的
Promise
)推迟对“下一个事件循环迭代”的调用来完成。

_audioPlayer.playbackEventStream.listen((event) async {
      if (event.processingState == just_audio.ProcessingState.completed) {
        Future.delayed(Duration.zero, () async {
          await _audioPlayer.pause();
          await _audioPlayer.seek(Duration.zero);
        });
      }
    });
© www.soinside.com 2019 - 2024. All rights reserved.