核心流程概述

无论采用哪种方式,其核心流程通常都包含以下几个步骤:

  1. 采集 (Capture) :通过浏览器的 MediaDevices.getUserMedia() API 获取麦克风的音频流(MediaStream)。
  2. 处理 (Process) :(可选)对音频流进行加工,如降噪、增益、编码格式转换等。
  3. 编码与封装 (Encode & Package) :将音频数据转换为特定的格式(如 WAV, MP3, WebM, OPUS 等)并可能封装成文件或数据块。
  4. 传输 (Transmit) :通过网络协议(如 HTTP, WebSocket)将数据发送到后端。
  5. 后端处理:后端接收数据,进行解码、转码、存储或分析(如语音识别)。

常用方式详解

1. 录制为文件后上传 (HTTP Multipart/form-data)

这是最传统、兼容性最好的方式。用户录制一段语音,结束后生成一个音频文件(如 MP3),然后通过普通的表单提交上传到后端。

  • 实现步骤

    1. 使用 MediaRecorder API 录制 MediaStream
    2. 录制结束后,生成一个音频文件(通常是 Blob 对象)。
    3. 创建一个 FormData 对象,将 Blob 文件添加到其中。
    4. 通过 fetch 或 XMLHttpRequest 以 POST 请求发送这个 FormData
  • 代码示例

    let mediaRecorder; let audioChunks = []; // 1. 请求麦克风权限并开始录制 navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' }); // 或 'audio/mp3' mediaRecorder.ondataavailable = event => { audioChunks.push(event.data); }; mediaRecorder.onstop = () => { // 2. 录制结束,生成Blob const audioBlob = new Blob(audioChunks, { type: 'audio/webm' }); // 3. 创建FormData并附加文件 const formData = new FormData(); formData.append('audio', audioBlob, 'recording.webm'); // 可以附加其他信息,如用户ID formData.append('userId', '123'); // 4. 上传到服务器 fetch('/api/upload-voice', { method: 'POST', body: formData }).then(response => { console.log('Upload successful!'); }); }; }); // 开始录制 mediaRecorder.start(); // ... 用户点击停止后 // mediaRecorder.stop(); 
  • 优点

    • 实现简单,后端处理也简单(像处理普通文件上传一样)。
    • 兼容绝大多数浏览器。
  • 缺点

    • 延迟高:必须等整个录音过程结束才能上传,无法实时传输。
    • 不适用于实时场景:如语音识别、直播连麦等。
  • 适用场景:发送语音消息、录制后上传的语音笔记等非实时应用。

2. 使用 WebSocket 进行流式传输 (Streaming)

这是实现实时语音传输的首选方案。音频数据被分成小块,一旦采集到就立即通过 WebSocket 连接发送到后端,实现极低的延迟。

  • 实现步骤

    1. 建立 WebSocket 连接到后端。
    2. 获取麦克风音频流。
    3. 使用 MediaRecorder API,但设置一个很短的 timeslice 参数(例如 100ms),这会定期触发 ondataavailable 事件,输出小块的音频数据(数据块,通常是 WebM 或 OPUS 格式)。
    4. 在 ondataavailable 事件中,将收到的数据块通过 WebSocket 直接发送。
    5. 后端 WebSocket 服务持续接收这些数据块,并进行实时处理(如拼装、解码、转码或送入语音识别引擎)。
  • 代码示例

    const socket = new WebSocket('wss://your-backend.com/ws-voice'); let mediaRecorder; socket.onopen = () => { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { // 关键:设置 timeslice 为 100ms,每100ms产生一个数据块 mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm; codecs=opus' }); mediaRecorder.ondataavailable = (event) => { // 确保 WebSocket 连接是打开的 if (event.data.size > 0 && socket.readyState === WebSocket.OPEN) { // 将数据块直接发送给服务器 socket.send(event.data); } }; mediaRecorder.start(100); // 每100ms触发一次 ondataavailable }); }; // 结束时关闭连接和录制 // mediaRecorder.stop(); // socket.close(); 
  • 优点

    • 实时性极好,延迟非常低。
    • 双向通信,后端可以随时发回响应(如识别结果)。
  • 缺点

    • 后端需要实现 WebSocket 服务,处理流式数据,复杂度较高。
    • 需要处理网络不稳定和重连逻辑。
  • 适用场景:实时语音识别、语音聊天、在线会议、语音助手交互。

3. 使用 HTTP 分块传输编码 (Chunked Transfer Encoding)

类似于 WebSocket 方式,但使用 HTTP。前端将音频数据流通过一个持续的 HTTP 请求发送,后端像接收流一样读取数据。这通常需要后端框架支持流式请求体。

  • 实现步骤

    1. 与 WebSocket 方式类似,使用 MediaRecorder 和 timeslice 切割音频数据。
    2. 使用 fetch 发起一个 POST 请求,但请求体是一个 ReadableStream
    3. 将产生的音频数据块(Blob)不断写入这个流。
    4. 后端(如 Node.js with Express, Python with Flask)以流的形式读取请求体。
  • 代码示例(概念性) :

    // 这是一个高级用法,浏览器支持和使用复杂度较高 const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm; codecs=opus' }); const { readable, writable } = new TransformStream(); const writer = writable.getWriter(); mediaRecorder.ondataavailable = async (event) => { if (event.data.size > 0) { await writer.write(event.data); } }; mediaRecorder.start(100); // 发起流式Fetch请求 fetch('/api/stream-voice', { method: 'POST', headers: { 'Content-Type': 'application/octet-stream' }, body: readable // 请求体是一个流 }); 
  • 优点

    • 基于 HTTP,基础设施简单(不需要单独的 WS 服务)。
  • 缺点

    • 实现相对复杂,浏览器和後端的支持不如前两种方式通用。
    • 连接管理不如 WebSocket 灵活(例如,服务器难以主动推送消息)。
  • 适用场景:需要流式传输但又想避免 WebSocket 复杂性的场景,但通常 WebSocket 是更优选择。


总结与选择建议

方式 协议 实时性 复杂度 适用场景
文件上传 HTTP (录制完成后上传) 语音消息、邮件附件、非实时录制
WebSocket 流 WebSocket (实时流) 中高 实时语音识别、语音聊天、在线会议
HTTP 分块 HTTP 中高(准实时流) 流式传输,但更推荐 WebSocket

如何选择?

  • 如果你的应用是“对讲机”或“微信语音消息”模式:用户说一段话,松手后发送。选择方式1(文件上传)  最简单高效。
  • 如果你的应用是“语音实时转文字”或“Siri/Google Assistant”模式:用户说话的同时,屏幕上就在出文字。选择方式2(WebSocket 流) 。
  • 如果你的应用是“视频会议”或“语音聊天”模式:需要双向、持续的音频流交互。选择方式2(WebSocket 流) ,并可能需要使用 WebRTC( peer-to-peer 协议,比 WebSocket 更专门用于实时音视频,但后端处理逻辑也不同)。

额外重要考虑因素:

  • 音频格式(Codec) :

    • audio/webm; codecs=opus强烈推荐。OPUS 格式音质好、压缩率高、延迟低,是 WebRTC 和现代浏览器的标准。后端需要支持解码 OPUS(例如使用 ffmpeg)。
    • audio/mp3:兼容性好,文件小,但编码延迟高,不适合实时流
    • audio/wav:音质无损,文件巨大,主要用于需要高质量音频且不需要考虑带宽的场景。
  • 后端处理:前端选择何种方式很大程度上取决于后端的接收和处理能力。在决定前端方案前,务必与后端工程师沟通好他们期望接收的数据格式和传输协议。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐