You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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侧交互即可:

  1. 编辑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>
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 15:36:02