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

如何将MediaRecorder流编码为PCM格式适配AWS Transcribe Medical

解决AWS Transcribe Medical实时PCM音频流问题的工具包与代码方案

你的核心问题是MediaRecorder无法直接输出AWS要求的原始PCM格式,以下是两种可行方案:

1. 原生Web Audio API实现(无额外依赖)

直接通过浏览器原生API捕获原始音频样本,转换为AWS要求的16位PCM格式后实时发送,无需安装工具包。修改后的完整代码如下:

import React, { useState, useRef } from "react";
import {
  TranscribeStreamingClient,
  StartMedicalStreamTranscriptionCommand,
} from "@aws-sdk/client-transcribe-streaming";
import logo from "./logo.svg";
import "./App.css";

function App() {
  const [isRecording, setIsRecording] = useState(false);
  const audioContextRef = useRef(null);
  const scriptProcessorRef = useRef(null);
  const mediaStreamRef = useRef(null);
  const transcribeQueueRef = useRef([]);
  const client = new TranscribeStreamingClient({
    region: "your-region",
    credentials: {
      accessKeyId: "your-access-key",
      secretAccessKey: "your-secret-key",
    },
  });

  const handleMicClick = () => {
    isRecording ? stopRecording() : startRecording();
  };

  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: { sampleRate: 44100 } });
      mediaStreamRef.current = stream;
      
      audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 44100 });
      const source = audioContextRef.current.createMediaStreamSource(stream);
      
      // 创建音频处理器,每次处理4096个样本(可根据需求调整)
      scriptProcessorRef.current = audioContextRef.current.createScriptProcessor(4096, 1, 1);
      
      source.connect(scriptProcessorRef.current);
      scriptProcessorRef.current.connect(audioContextRef.current.destination);

      // 初始化AWS转录流
      initTranscribeStream();

      // 实时处理音频样本
      scriptProcessorRef.current.onaudioprocess = (event) => {
        const floatPcm = event.inputBuffer.getChannelData(0);
        // 转换为AWS要求的16位有符号整数PCM
        const int16Pcm = new Int16Array(floatPcm.length);
        for (let i = 0; i < floatPcm.length; i++) {
          const sample = Math.max(-1, Math.min(1, floatPcm[i]));
          int16Pcm[i] = sample < 0 ? sample * 0x8000 : sample * 0x7FFF;
        }
        
        // 加入发送队列
        if (transcribeQueueRef.current.length > 0) {
          const resolve = transcribeQueueRef.current.shift();
          resolve(int16Pcm);
        }
      };

      setIsRecording(true);
    } catch (error) {
      console.error("启动录制失败: ", error);
    }
  };

  const initTranscribeStream = async () => {
    const input = {
      LanguageCode: "en-US",
      MediaSampleRateHertz: 44100,
      MediaEncoding: "pcm",
      Specialty: "PRIMARYCARE",
      Type: "CONVERSATION",
      AudioStream: (async function* () {
        while (true) {
          yield await new Promise(resolve => transcribeQueueRef.current.push(resolve));
        }
      })()
    };

    const command = new StartMedicalStreamTranscriptionCommand(input);
    const response = await client.send(command);
    
    // 处理转录结果
    (async () => {
      for await (const event of response.TranscriptResultStream) {
        if (event.TranscriptEvent) {
          event.TranscriptEvent.Transcript.Results.forEach(result => {
            result.Alternatives?.forEach(alternative => {
              const transcript = alternative.Items?.map(item => item.Content).join(" ") || "";
              console.log("转录内容:", transcript);
            });
          });
        }
      }
    })();
  };

  const stopRecording = () => {
    // 清理所有资源
    scriptProcessorRef.current?.disconnect();
    audioContextRef.current?.close();
    mediaStreamRef.current?.getTracks().forEach(track => track.stop());
    transcribeQueueRef.current = [];
    
    setIsRecording(false);
  };

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <button onClick={handleMicClick}>
          {isRecording ? "停止录制" : "开始录制"}
        </button>
      </header>
    </div>
  );
}

export default App;

2. 使用audio-recorder-polyfill简化开发

这个库可以让MediaRecorder支持输出WAV格式(包含PCM数据),只需简单配置即可适配现有代码,之后提取WAV中的PCM数据发送给AWS。

安装命令:

npm install audio-recorder-polyfill

代码修改:
在文件顶部添加配置:

import AudioRecorder from 'audio-recorder-polyfill';
// 强制MediaRecorder输出WAV格式
AudioRecorder.prototype.mimeType = 'audio/wav';
window.MediaRecorder = AudioRecorder;

修改handleDataAvailable函数提取PCM数据:

const handleDataAvailable = async (event) => {
  const arrayBuffer = await event.data.arrayBuffer();
  // WAV文件前44字节是头部,后面为原始PCM数据
  const pcmData = new Uint8Array(arrayBuffer.slice(44));
  sendAudioChunk(pcmData);
};

同时需要调整sendAudioChunk函数,用异步迭代器向AWS发送流式数据(逻辑参考原生方案中的initTranscribeStream部分)。

关键注意事项

  • AWS Transcribe要求PCM为16位有符号整数、单声道、采样率与配置的44100Hz一致,转换时需确保格式正确。
  • 实时流式发送必须用async generator实现AWS要求的AudioStream异步迭代器,不能直接传递单个Blob。
  • 停止录制时需完整清理音频上下文、媒体流等资源,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Shubham Ambastha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:48:16