Flutter[Just audio]:获取播放中流的原始字节数据实现直播回退
解决方案:复用网络流实现播放+录制,避免重复请求与噪音
just_audio目前没有直接提供获取原始音频字节的公开API,但你可以通过**自定义StreamAudioSource**结合广播流的方式,复用同一份网络请求的数据流,同时实现播放和录制,完美解决你遇到的两个问题:
核心思路
- 发起一次HTTP请求获取直播流的
StreamedResponse - 将单订阅的响应流转换为多订阅广播流,让数据流可以同时分发给just_audio播放和文件写入逻辑
- 自定义
StreamAudioSource,让just_audio从广播流中读取数据进行解码播放 - 同时监听广播流的另一分支,将字节写入临时MP3文件用于回退操作
代码实现示例
import 'dart:io'; import 'dart:async'; import 'package:just_audio/just_audio.dart'; import 'package:http/http.dart' as http; class ReusableStreamAudioSource extends StreamAudioSource { final Stream<List<int>> audioStream; final String contentType; ReusableStreamAudioSource(this.audioStream, this.contentType); @override Future<StreamAudioResponse> request([int? start, int? end]) async { return StreamAudioResponse( sourceLength: null, // 直播流无固定长度 contentLength: null, offset: start ?? 0, contentType: contentType, stream: audioStream, ); } } void setupLiveStreamRecording(String streamUrl) async { final client = http.Client(); final response = await client.get(Uri.parse(streamUrl)); // 将单订阅流转为多订阅广播流,实现数据流复用 final broadcastStream = response.bodyBytes.asBroadcastStream(); // 初始化播放器,使用自定义音频源播放直播流 final player = AudioPlayer(); await player.setAudioSource( ReusableStreamAudioSource( broadcastStream, response.headers['content-type'] ?? 'audio/mpeg', ), ); player.play(); // 同时将流写入临时文件,用于后续回退操作 final tempFile = File(Directory.systemTemp.path + '/live_recording.mp3'); final fileSink = tempFile.openWrite(); await broadcastStream.pipe(fileSink); // 记得在合适时机清理资源 // player.dispose(); // client.close(); // await fileSink.close(); }
关键细节说明
asBroadcastStream()是核心:默认HTTP响应流为单订阅流,只能被消费一次,转换为广播流后可同时被播放和录制逻辑订阅- 自定义
StreamAudioSource需确保contentType与直播流实际格式匹配,否则just_audio可能无法正常解码 - 注意资源生命周期:播放器、HTTP客户端、文件写入流都需要在使用完成后关闭,避免内存泄漏
- 直播流无固定长度,因此
sourceLength和contentLength需设为null
这种实现只会发起一次网络请求,既保留了just_audio的播放能力,又能录制原始音频数据,彻底解决重复请求和录音噪音的问题。
内容的提问来源于stack exchange,提问作者Akalanka Perera
相关产品推荐
相关产品推荐

