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,后续点切换麦克风会直接报错。
修复方法
按顺序排查修改就行:
- 先核对代码大括号配对,确保
await OT.getUserMedia这段是在audioCall函数的直接作用域里,没有被嵌套进其他普通函数内部,同时确认audioCall函数声明前的async关键字没有遗漏。 - 如果是全局调用
audioCall时加了await触发的报错,要么给script标签加type="module"属性开启模块环境支持顶层await,要么把调用逻辑包进异步立即执行函数,写法如下:(async () => { await audioCall(); })(); - 把设备列表加载、麦克风切换的逻辑改成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
相关产品推荐
相关产品推荐

