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

Twilio Voice SDK移动端浏览器触发AcquisitionFailedError(31402)报错

问题诱发原因
  • 核心原因是安卓端Chrome对麦克风媒体采集设置了严格的用户手势有效期校验:用户点击按钮产生的可信操作链路,会在遇到await异步等待时失效。你当前的代码逻辑是点击call按钮后先异步请求token,等接口返回后才初始化Twilio设备、发起麦克风采集请求,此时用户手势的可信状态已经过期,安卓系统直接拦截了媒体采集操作,最终抛出31402错误。Windows桌面版Chrome对手势链路的有效期限制更宽松,因此不会触发该问题。
  • 次要兼容性问题:你使用的Twilio Voice SDK 2.0.1版本默认的音频采集参数强制开启自动增益控制,部分安卓12设备的系统音频驱动对该配置的支持存在缺陷,即使权限校验通过也会导致媒体流初始化失败。
  • 额外逻辑缺陷:你每次发起呼叫都会新建Twilio.Device实例,且错误监听仅绑定在连接建立后的connection对象上,设备初始化阶段的媒体错误无法被正常捕获,会进一步提高问题排查难度。
修复方案
  • 调整代码执行顺序,把设备初始化、麦克风权限申请的逻辑放到用户点击call的同步执行链路最前端,在异步请求token之前就完成媒体采集权限申请,保证getUserMedia调用处于用户手势的有效周期内。
  • 显式配置音频采集约束,关闭易触发安卓兼容性问题的强制自动增益配置,指定单声道采集适配移动端音频硬件。
  • 给Twilio.Device实例绑定全局错误监听,覆盖初始化、连接全流程的错误场景,呼叫结束后主动销毁Device实例避免内存泄漏。
  • 修复后的完整代码如下:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Twilio Call Demo</title>
    <script src="https://cdn.jsdelivr.net/npm/@twilio/voice-sdk@2.0.1/dist/twilio.min.js"></script>
    <script>
      let device = null;
      let connection = null;
      
      const call = async () => {
        const errorDisplay = document.getElementById("error-display");
        errorDisplay.innerHTML = "";
        try {
          // 用户点击后同步初始化设备,处于可信手势链路内
          device = new Twilio.Device({
            audioConstraints: {
              audio: {
                echoCancellation: true,
                noiseSuppression: true,
                autoGainControl: false, // 关闭强制自动增益,兼容安卓12音频驱动
                channelCount: 1 // 强制单声道采集,适配移动端硬件
              }
            }
          });

          // 注册全局错误监听,覆盖全流程错误
          device.on("error", (err) => {
            errorDisplay.innerHTML = err.message;
          });

          // 同步触发麦克风权限申请,在手势有效期内完成媒体获取
          await device.register();
          
          // 媒体权限校验通过后,再异步请求token建立连接
          const response = await fetch("https://my.token.endpoint/token");
          const data = await response.json();
          device.updateToken(data.token);
          connection = await device.connect();
        } catch (err) {
          errorDisplay.innerHTML = err.message;
        }
      };

      const stop = () => {
        connection?.disconnect();
        connection = null;
        device?.destroy();
        device = null;
      };
    </script>
  </head>
  <body>
    <button onclick="call()">call</button>
    <button onclick="stop()">stop</button>
    <p id="error-display"></p>
  </body>
</html>
  • 额外校验项:确保访问页面使用的是https://协议或本地localhost地址,安卓Chrome在非安全上下文的http页面下会直接禁止麦克风权限申请,同样会触发该类媒体获取错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:24:34