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

Unity WebGL下用纯JavaScript调用Google Cloud Speech-to-Text API遇400错误求助

解决方案:Unity WebGL + 纯JS调用Google Cloud Speech-to-Text API

核心错误原因

400 Bad Request基本都来自以下几个硬伤,先逐一核对:

  • 音频格式不匹配:API要求必须是16kHz采样率、单声道、16位PCM(LINEAR16编码),格式不对直接拒绝
  • API Key使用错误:API Key应放在URL参数key=xxx或请求头X-Goog-Api-Key: xxx,而非Authorization: Bearer xxx(Bearer是OAuth令牌的用法)
  • 请求JSON结构错误:必须包含config和audio两个顶级字段,缺一不可

完整实现代码(jslib + Unity C#)

1. WebGL麦克风采集与API请求的jslib

创建SpeechToText.jslib,放入Unity项目的Plugins/WebGL目录:

mergeInto(LibraryManager.library, {
    // 初始化麦克风,强制匹配API要求的音频格式
    InitMicrophone: function() {
        navigator.mediaDevices.getUserMedia({ 
            audio: { 
                sampleRate: 16000, 
                channelCount: 1, 
                sampleSize: 16,
                echoCancellation: true
            } 
        })
        .then(stream => {
            const audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 });
            const source = audioContext.createMediaStreamSource(stream);
            const processor = audioContext.createScriptProcessor(4096, 1, 1);

            source.connect(processor);
            processor.connect(audioContext.destination);

            processor.onaudioprocess = function(e) {
                const inputBuffer = e.inputBuffer;
                const channelData = inputBuffer.getChannelData(0);
                // 把浏览器返回的32位浮点音频转成API要求的16位PCM
                const pcmData = new Int16Array(channelData.length);
                for (let i = 0; i < channelData.length; i++) {
                    const normalized = Math.max(-1, Math.min(1, channelData[i]));
                    pcmData[i] = normalized < 0 ? normalized * 0x8000 : normalized * 0x7FFF;
                }
                // 转成base64编码
                const base64 = btoa(String.fromCharCode(...new Uint8Array(pcmData.buffer)));
                // 发送识别请求
                _SendSpeechRequest(base64);
            };
        })
        .catch(err => console.error("麦克风初始化失败:", err));
    },

    // 发送POST请求到Speech-to-Text API
    SendSpeechRequest: function(audioBase64Ptr) {
        const audioBase64 = UTF8ToString(audioBase64Ptr);
        const apiKey = "YOUR_API_KEY"; // 替换成你的API Key
        const url = `https://speech.googleapis.com/v1/speech:recognize?key=${apiKey}`;

        const payload = JSON.stringify({
            config: {
                encoding: "LINEAR16",
                sampleRateHertz: 16000,
                languageCode: "zh-CN", // 替换成目标语言,比如en-US
                enableAutomaticPunctuation: true
            },
            audio: {
                content: audioBase64
            }
        });

        fetch(url, {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: payload
        })
        .then(response => {
            if (!response.ok) throw new Error(`HTTP错误码: ${response.status}`);
            return response.json();
        })
        .then(data => {
            // 提取识别结果,传回Unity
            const transcript = data.results[0]?.alternatives[0]?.transcript || "无识别结果";
            const transcriptPtr = allocateUTF8(transcript);
            _OnSpeechRecognitionResult(transcriptPtr);
            free(transcriptPtr);
        })
        .catch(err => console.error("API请求失败:", err));
    }
});

// 辅助函数:将字符串转为Unity可读取的UTF8指针
function allocateUTF8(str) {
    const buffer = new TextEncoder().encode(str + "\0");
    const ptr = _malloc(buffer.length);
    writeArrayToMemory(buffer, ptr);
    return ptr;
}

2. Unity C#调用脚本

创建C#脚本挂载到任意GameObject:

using UnityEngine;
using System.Runtime.InteropServices;

public class SpeechRecognitionManager : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void InitMicrophone();

    [DllImport("__Internal")]
    private static extern void SendSpeechRequest(string audioBase64);

    // 接收jslib传回的识别结果
    [MonoPInvokeCallback(typeof(System.Action<string>))]
    private static void OnSpeechRecognitionResult(string result)
    {
        Debug.Log("识别结果: " + result);
        // 这里添加结果处理逻辑,比如显示到UI
    }

    void Start()
    {
#if UNITY_WEBGL && !UNITY_EDITOR
        InitMicrophone();
#endif
    }
}

关键注意事项

  • API权限检查:确保Google Cloud控制台中已启用Cloud Speech-to-Text API,且API Key未被限制IP或调用次数
  • CORS配置:如果部署到自有服务器,需确保服务器允许跨域请求speech.googleapis.com;Unity编辑器中可在Player Settings > WebGL > Publishing Settings开启Enable CORS
  • 音频长度限制:单次POST请求最多处理1分钟音频,如需更长音频需改用流式识别(WebSocket协议)

错误排查步骤

  1. 打开浏览器开发者工具(F12),查看Network标签:
    • 核对Request URL是否包含正确的API Key
    • 检查Request Payload的JSON结构是否与示例一致
    • 查看Response的详细错误信息(Google API会返回具体原因,比如invalid encoding或API key not valid)
  2. 用Postman单独测试API Key:发送一个符合格式的测试请求,确认Key本身有效

内容的提问来源于stack exchange,提问作者Niv.R.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 04:57:34