如何用Flutter与just_audio实现ElevenLabs音频流式播放?
实现ElevenLabs流式音频边下载边播放
问题根源
你当前的代码用http.post请求音频,这个方法会等待整个响应完全接收后才返回bodyBytes,所以必须等全部音频下载完才能播放,没法实现流式效果。要解决这个问题,需要直接处理API返回的字节流,而不是缓冲整个响应。
解决方案步骤
- 改用
http.Client.send获取实时字节流:这个方法不会缓冲整个响应,而是返回一个Stream<List<int>>,每收到一块音频数据就会触发流事件。 - 适配just_audio的流式源:自定义
StreamAudioSource来对接这个实时流,让播放器可以边接收数据边解码播放。 - 调整播放逻辑:直接将流式源传给音频播放器,无需等待全部数据加载完成。
修改后的完整代码
1. 获取音频流的函数
Stream<List<int>> _fetchAudioStream(String text) async* { final client = http.Client(); try { final request = http.Request( 'POST', Uri.parse('https://api.elevenlabs.io/v1/text-to-speech/${widget.voiceId}/stream'), ); request.headers.addAll({ 'Content-Type': 'application/json', 'xi-api-key': dotenv.env['ELEVENLABSKEY']!, }); request.body = jsonEncode({ "text": text.replaceAll('*', ''), "model_id": myModel, "voice_settings": widget.voiceSetting, }); final response = await client.send(request); if (response.statusCode == 200) { // 直接转发API返回的字节流 yield* response.stream; } else { throw Exception('请求失败,状态码: ${response.statusCode}'); } } catch (e) { print('获取音频流错误: $e'); rethrow; } finally { client.close(); } }
2. 适配实时流的自定义音频源
class ElevenLabsStreamSource extends StreamAudioSource { final Stream<List<int>> audioStream; final int? contentLength; ElevenLabsStreamSource(this.audioStream, [this.contentLength]); @override Future<StreamAudioResponse> request([int? start, int? end]) async { // ElevenLabs流式API不支持范围请求,所以忽略start/end参数 return StreamAudioResponse( sourceLength: contentLength ?? -1, // 未知总长度时传入-1 contentLength: -1, offset: start ?? 0, stream: audioStream, contentType: 'audio/mpeg', ); } }
3. 流式播放逻辑
void _playStreamingAudio(String text) async { try { // 获取实时音频流并创建流式源 final audioStream = _fetchAudioStream(text); await _audioPlayer.setAudioSource(ElevenLabsStreamSource(audioStream)); // 立即开始播放 _audioPlayer.play(); } catch (e) { print('播放错误: $e'); } }
额外说明
- 如果需要实现队列播放,可以用
ConcatenatingAudioSource将多个ElevenLabsStreamSource加入队列,播放器会自动按顺序播放。 - 确保你的
just_audio包是最新稳定版,旧版本可能对流式源的支持有问题。 - 处理流中断的情况:比如网络断开时,流会抛出异常,需要在播放逻辑中捕获并处理(比如提示用户重新播放)。
内容的提问来源于stack exchange,提问作者Sahil Singh
相关产品推荐
相关产品推荐

