Flutter使用just_audio实现两个音频播放器同步播放问题
解决just_audio多轨音频同步播放问题
你当前的实现之所以会出现不同步,核心问题在于:
- 播放前的播放器初始化(
fillXXXList)在两个并行的Future中执行,两者的完成时间无法保证一致,导致其中一组音频可能先开始播放。 - 两组音频的播放循环各自独立执行,逐个播放+延迟的逻辑会因为异步调度、音频加载差异等因素产生时间差。
优化方案
要实现严格同步,需要把播放器初始化和播放控制分离,并统一触发所有对应轨道的播放操作:
1. 提前初始化所有播放器
把播放器的创建和资源加载逻辑提前到播放操作之前(比如页面初始化、用户选择资源完成时),避免播放时的异步操作拖慢节奏:
// 初始化和弦播放器列表 Future<void> initChordsPlayers(List<AudioPlayer> chordsPlayers, Controller c) async { for (final source in c.assetSources) { final player = AudioPlayer(); await player.setAsset(source.toString()); chordsPlayers.add(player); } } // 初始化鼓点播放器列表 Future<void> initDrumsPlayers(List<AudioPlayer> drumsPlayers, Controller c) async { final drumPath = 'assets/drum_beats/${c.rhythmsFolderSelected}/${c.bpmSliderValue.toInt()}BPM.mp3'; for (int i = 0; i < c.assetSources.length; i++) { final player = AudioPlayer(); await player.setAsset(drumPath); drumsPlayers.add(player); } }
2. 统一控制同步播放
在播放时,同时触发对应索引的和弦与鼓点播放器,并使用统一的时间基准来控制循环延迟:
Future<void> playSynchronized(List<AudioPlayer> chordsPlayers, List<AudioPlayer> drumsPlayers, Controller c) async { // 校验播放器列表状态,确保数量匹配且已初始化 if (chordsPlayers.isEmpty || drumsPlayers.isEmpty || chordsPlayers.length != drumsPlayers.length) { return; } for (int i = 0; i < c.assetSources.length; i++) { // 同时启动当前轨道的和弦与鼓点音频 chordsPlayers[i].play(); drumsPlayers[i].play(); // 以和弦音频的时长作为统一延迟基准(可根据实际需求替换为鼓点时长) final trackDuration = chordsPlayers[i].duration ?? const Duration(seconds: 0); await Future.delayed(trackDuration - const Duration(milliseconds: 100)); } }
3. 调用方式调整
先在合适的时机完成播放器初始化,再在按钮点击时触发同步播放:
// 提前初始化(比如在initState或用户选择资源后) await Future.wait([ initChordsPlayers(chordsAudioPlayersList, c), initDrumsPlayers(drumsAudioPlayersList, c), ]); // 按钮点击时调用 await playSynchronized(chordsAudioPlayersList, drumsAudioPlayersList, c);
额外优化建议
- 复用播放器:不要每次播放都创建新的
AudioPlayer实例,播放结束后可以重置播放器(seek(Duration.zero)),下次播放直接复用,减少资源开销和初始化时间。 - 统一时间基准:如果鼓点音频时长固定,可以预先计算好延迟时长,避免依赖播放器的
duration获取(可能存在微小误差)。
内容的提问来源于stack exchange,提问作者bbr
相关产品推荐
相关产品推荐

