如何在Flutter Web中实现麦克风实时音频流采集及整型数据获取
实现方案
方案1:直接用dart:js/dart:js_util转换现有JS代码
首先导入Dart官方提供的Web交互依赖:
import 'dart:js'; import 'dart:js_util';
定义全局变量和参数常量:
const int bufSize = 4096; // 可根据业务需求调整缓冲区大小 late JsObject audioCtx; bool audioStarted = false;
对应你现有JS逻辑的Dart实现:
Future<void> initAudio() async { try { // 初始化AudioContext audioCtx = JsObject(context['AudioContext']); // 申请麦克风权限,把JS的Promise转为Dart的Future final stream = await promiseToFuture( context['navigator']['mediaDevices'].callMethod( 'getUserMedia', [JsObject.jsify({'audio': true, 'video': false})] ) ); // 创建音频源节点 final audioSource = audioCtx.callMethod('createMediaStreamSource', [stream]); // 创建音频处理器节点 final audioProcessor = audioCtx.callMethod('createScriptProcessor', [bufSize, 1, 1]); // 连接音频链路 audioSource.callMethod('connect', [audioProcessor]); audioProcessor.callMethod('connect', [audioCtx['destination']]); audioStarted = true; // 绑定音频帧处理回调,需用allowInterop包裹让JS可以调用Dart方法 audioProcessor['onaudioprocess'] = allowInterop((e) { checkAudioBuffer(e['inputBuffer']); }); } catch (err) { print(err); } }
音频数据转换为整型数组的实现(以常用的16位PCM格式为例):
void checkAudioBuffer(JsObject inputBuffer) { // 获取单声道Float32格式的原始音频数据 final floatData = inputBuffer.callMethod('getChannelData', [0]) as List<double>; // 映射为16位整型数组 List<int> intData = floatData.map((e) => (e * 32767).round()).toList(); // 此处直接使用intData做后续业务处理即可 }
方案2:直接复用现有JS代码(更省心,无需逐行转换)
不需要把JS逻辑转成Dart,直接把现有代码放到项目web/index.html的全局脚本里,通过全局回调和Dart侧交互即可:
- 编辑index.html,在
<body>标签内添加如下脚本:
<script> let audioCtx; let audioStarted = false; const bufSize = 4096; // 预留全局回调变量,Dart侧会把处理方法挂载到这个变量上 window.dartAudioCallback = null; function checkAudioBuffer(inputBuffer) { const floatData = inputBuffer.getChannelData(0); // 把音频数据转为普通数组传给Dart if (window.dartAudioCallback) { window.dartAudioCallback(Array.from(floatData)); } } function initAudio() { try { audioCtx = new AudioContext(); const GotAudioStream = function(stream) { const audioSource = audioCtx.createMediaStreamSource(stream); const audioProcessor = audioCtx.createScriptProcessor(bufSize, 1, 1); audioSource.connect(audioProcessor); audioProcessor.connect(audioCtx.destination); audioStarted = true; audioProcessor.onaudioprocess = function(e) { checkAudioBuffer(e.inputBuffer); }; }; navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(GotAudioStream); } catch (err) { console.log(err); } } </script>
- Dart侧调用逻辑:
import 'dart:js'; void main() { // 注册全局回调,接收JS传过来的音频数据 context['dartAudioCallback'] = allowInterop((List<double> floatData) { List<int> intData = floatData.map((e) => (e * 32767).round()).toList(); // 处理整型音频数组 }); // 直接调用JS侧的初始化方法 context.callMethod('initAudio'); }
注意事项
- 必须在
localhost或者HTTPS环境下测试运行,否则浏览器会禁用getUserMedia接口 - ScriptProcessor API已被Web标准标记为弃用,若需要长期兼容可以替换为AudioWorklet实现,整体逻辑基本一致
- 不需要引入任何第三方Flutter音频库,以上实现仅依赖Dart官方内置的Web交互能力
内容的提问来源于stack exchange,提问作者Kaisky
相关产品推荐
相关产品推荐

