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

Laravel集成Vonage实现浏览器间音频调用报await语法错误

错误原因

这个是JavaScript解析阶段抛出的语法错误,本质是await关键字没有运行在合法的异步上下文里——await只能在两种场景下使用:一是被async标记的异步函数内部,二是ES模块的顶层作用域。
结合你贴的代码,问题基本出在两个地方:

  • 代码大括号错位:你贴的代码排版上看逻辑没问题,但实际运行的代码里,const stream = await OT.getUserMedia(...) 这段大概率被错放到了OT.initPublisher的回调函数里。这个回调是普通的function(error) {}形式,没有加async标记,内部直接用await就会触发这个报错。
  • 外层函数漏写async:实际运行代码里audioCall函数被定义成了普通函数,前面的async关键字丢了,导致整个函数体里的await都失去了合法的异步上下文。
    还有一种低概率情况:你在audioCall函数外面的全局作用域直接写了await audioCall()来调用函数,同时当前承载JS的script标签没加type="module",非模块环境不支持顶层await,也会报这个错。
    另外你现有代码还有个逻辑隐患:OT.getDevices是异步回调接口,你在回调外面定义的cycleMicrophone直接用audioInputs变量时,很可能设备列表还没加载完成,audioInputs是undefined,后续点切换麦克风会直接报错。
修复方法

按顺序排查修改就行:

  1. 先核对代码大括号配对,确保await OT.getUserMedia这段是在audioCall函数的直接作用域里,没有被嵌套进其他普通函数内部,同时确认audioCall函数声明前的async关键字没有遗漏。
  2. 如果是全局调用audioCall时加了await触发的报错,要么给script标签加type="module"属性开启模块环境支持顶层await,要么把调用逻辑包进异步立即执行函数,写法如下:
    (async () => {
      await audioCall();
    })();
    
  3. 把设备列表加载、麦克风切换的逻辑改成Promise写法,保证设备列表加载完成后再使用,避免异步时序问题。
修正后的完整代码
async function audioCall() {
  let publisher;
  const targetElement = 'publisher';
  const pubOptions = { publishAudio: true, publishVideo: false };

  // 等待publisher初始化完成
  publisher = await new Promise((resolve, reject) => {
    const pubInstance = OT.initPublisher(targetElement, pubOptions, (error) => {
      if (error) {
        alert("客户端无法发布流");
        reject(error);
        return;
      }
      console.log('发布端初始化完成');
      resolve(pubInstance);
    });
  });

  // 获取音频流并设置音频源
  const stream = await OT.getUserMedia({ videoSource: null });
  const [audioSource] = stream.getAudioTracks();
  await publisher.setAudioSource(audioSource);
  console.log('音频源设置完成');

  // 等待设备列表加载完成
  const audioInputs = await new Promise((resolve, reject) => {
    OT.getDevices((err, devices) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(devices.filter(device => device.kind === 'audioInput'));
    });
  });

  // 定位当前正在使用的麦克风索引
  let currentIndex = 0;
  const currentMicLabel = publisher.getAudioSource().label;
  audioInputs.forEach((device, idx) => {
    if (device.label === currentMicLabel) {
      currentIndex = idx;
    }
  });

  // 麦克风切换方法
  const cycleMicrophone = () => {
    currentIndex = (currentIndex + 1) % audioInputs.length;
    const targetDeviceId = audioInputs[currentIndex].deviceId;
    publisher.setAudioSource(targetDeviceId);
  };

  // 这里可以把cycleMicrophone绑定到切换麦克风的按钮点击事件上
  // document.querySelector('#switchMic').addEventListener('click', cycleMicrophone);
}

// 调用音频通话逻辑
(async () => {
  try {
    await audioCall();
  } catch (err) {
    console.error('音频通话初始化失败', err);
  }
})();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:24:28