使用just_audio实现无间断播放API返回的音频片段
无间断播放音频片段:基于just_audio的解决方案
问题背景
我有一个GET API接口,返回audio/mpeg格式的音频片段,需要持续调用接口获取数据并通过just_audio播放器实现无间断播放,求可行的代码示例。
现有实现及问题
当前我用以下代码实现连续播放,但每次播放完一个片段切换下一个时存在明显延迟:
String url = 'url'; await _player.setUrl(url, headers: {}); _player.playerStateStream.listen((event) { if (event.processingState == ProcessingState.completed) { print('completed'); _player.setUrl(url, headers: {}); } });
核心条件
音频片段为audio/mpeg格式,字节可拼接成完整音频流;单次API请求响应耗时300-400ms;当前是在每个片段播放完成后才发起下一次请求。
解决方案代码
要消除延迟,核心是提前预加载下一个音频片段,不要等当前播放结束才发起请求。以下是基于ConcatenatingAudioSource的实现:
import 'package:just_audio/just_audio.dart'; import 'package:http/http.dart' as http; class ContinuousAudioPlayer { final AudioPlayer _player = AudioPlayer(); final ConcatenatingAudioSource _playlist = ConcatenatingAudioSource(children: []); final String apiUrl; final Map<String, String> headers; bool _isLoadingNext = false; ContinuousAudioPlayer({required this.apiUrl, required this.headers}); Future<void> start() async { // 先加载第一个音频片段并启动播放 await _loadNextAudio(); await _player.setAudioSource(_playlist); _player.play(); // 监听播放进度,提前加载下一个片段 _player.positionStream.listen((position) { final currentDuration = _player.duration; if (currentDuration == null) return; // 当剩余播放时间小于请求耗时的1.5倍时,触发预加载(可根据实际情况调整阈值) final remainingMs = currentDuration.inMilliseconds - position.inMilliseconds; if (remainingMs <= 600 && !_isLoadingNext) { _loadNextAudio(); } }); // 兜底:播放完成时检查是否需要补充片段 _player.playerStateStream.listen((state) { if (state.processingState == ProcessingState.completed) { final nextIndex = _player.currentIndex! + 1; if (_playlist.children.length <= nextIndex && !_isLoadingNext) { _loadNextAudio(); } } }); } Future<void> _loadNextAudio() async { _isLoadingNext = true; try { final response = await http.get(Uri.parse(apiUrl), headers: headers); if (response.statusCode == 200 && response.bodyBytes.isNotEmpty) { // 将请求到的音频字节转为AudioSource final audioSource = AudioSource.uri( Uri.dataFromBytes(response.bodyBytes, mimeType: 'audio/mpeg'), ); // 添加到播放列表末尾 await _playlist.add(audioSource); } } catch (e) { print('加载音频片段失败: $e'); } finally { _isLoadingNext = false; } } // 释放资源 Future<void> stop() async { await _player.dispose(); } }
使用方式
// 初始化并启动播放器 final player = ContinuousAudioPlayer( apiUrl: '你的API地址', headers: {'你的请求头键': '值'}, ); await player.start(); // 停止播放时释放资源 // await player.stop();
关键说明
- 预加载时机:设置剩余600ms时触发请求(略大于单次请求的300-400ms),确保当前片段播放结束时,下一个片段已经加载完成。
- 队列管理:用
ConcatenatingAudioSource管理多个音频片段,just_audio会自动衔接播放下一个,无需手动切换。 - 请求防抖:通过
_isLoadingNext标记避免同时发起多个请求,防止资源浪费。
内容的提问来源于stack exchange,提问作者dev
相关产品推荐
相关产品推荐

