WebRTC通话播放本地音共用音频设备及短音播放失败问题咨询
WebRTC通话中本地音频强制使用指定输出设备相关问题
我正在尝试解决WebRTC通话过程中在本地耳机播放声音的问题。
原本我以为实现逻辑十分简单,示例代码如下:
function playsound() { new Audio( "data:audio/wav;base64,UklGRnIGAABXQVZFZm10IBIAAAAHAAEAQB8AAEAfAAABAAgAAABmYWN0BAAAAEAGAABkYXRhQAYAAP//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////W0k4U9s8Sbymo7D/PlNbLhwbKLCaryMZHziclq8yIDzBvDgwvpuZvB4ZJ7STncEcGi+8ods+SayuPBwdOJ6UpTgWITqcl7owJVPTRSEnyZmYuB4ZKLyTnL4eGzi+sDw8wZ6kPBodMp6UpDwWITqhnM04OLrBMBsizZiYsiAYKM2UnckhIEXT/yk2spmePBkcLqGUpT4XIDqqqU0+26m6Khkg55iYsiEXJ+eWnucoK+fnMB8urpaeSRgbLaWUpj4YIT60wTZFsJ6wKBggW5iYsCQXKFubplMwTbjnJxsrq5Wd/xkbLamUpkUdKVPJPipJpZipKBggTZiXrycXKf+itElFuKnbIRoqrJSd0xobLqyVqkUlOtP/KSJFn5amKhcgPpmWryoYK/+vWzj/pp/THhoosJSdzRobLrKatEUw07xFHx08npWmLhcgOpuXsi0dNufNLy7TnZrBHRoluJSdyRsaL7yi2z5Nrq48HBw4npWlMhYgOJ2YvDAnU9NFIifJmZm6HhgnvpScyR0bNsGyPDzJn6U6Gh0yn5SlOhcgOKKdzTg4vMkwHCLJmJi0HxgnzZWdzSEhRc3/KjaymZ48Gh0voZSlPBcgPKqpTT7bqborGiHbmJiwIRco25ae5ykt59syIC+slp5JGRwupJSlRRkiRbLBOEmwnrApGSBbmJivJBco/5umWzJNuOcoGyurlZ1bGRsuqJSmRR0pU8k8KkmlmKooGCBNmJevJxcpW6O4RUW6quchGimulJ3bGhstrJWqPiQ621spIkWflqgqFyA+mZewKRgr/69bOP+mn9MeGiiwlJ3NGhsuspq0RTDTvEUfHT6elaUuFyA8m5eyLR02580vLs2dmsEdGie0lJzJHBswuqLTRU2srjwcHTielKUyFiA6nZi6MCdT00UiJ8mZmboeGSe+lJ3JHRs2wbI8PMGfpToaHTKflKU4FiA4op7TODi8yTAcIsmYmLQfGCfNlZ3NISFFzf8qNrKZnjwaHS+hlKU8FyA8qqlNPtOpuisaIduYmLAhFyjblp7nKS3n2zIgL6yWnkkZHC6kk56rLyUgHyMnMDpb27y6srSyuLq+ydPn/1NNSUlJSUlJSU1NU1NbW1v////////n5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+f//////////////////////////////////////1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW1tbW////////////////////////////////////////////////////////+fn5+fn//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8=") .play(); } async function startaudio() { await navigator.mediaDevices.getUserMedia({audio:true}); }
First <button onclick='startaudio()'>start audio</button><br/> Then <button onclick='playsound()'>play sound</button><br/> PS. Demo doesn't work in code snippets due to security not allowed to get microphone
但实际运行时发现,WebRTC通话过程中触发播放的声音并没有从当前正在使用的耳机输出,而是被路由到了其他音频设备。
请问我该如何强制这段播放的声音使用当前正在进行的WebRTC通话所占用的音频设备?
补充说明:我后续排查发现该问题与WebRTC本身无关,是部分耳机在调用
navigator.mediaDevices.getUserMedia激活麦克风时会自动切换音频输出设备导致的。
附加问题:为什么上述代码中的极短音频经常无法正常播放,只有频繁点击按钮才能触发播放?
问题解答
1. 强制音频使用WebRTC通话对应输出设备方案
你可以通过浏览器提供的setSinkId接口绑定指定音频输出设备,操作步骤如下:
- 调用
getUserMedia获取麦克风权限后,通过enumerateDevices枚举所有音频设备,找到和当前激活麦克风同属一个groupId的音频输出设备,拿到对应的deviceId - 给需要播放的提示音音频实例绑定该
deviceId即可保证和WebRTC通话走同一输出设备
示例代码:
// 获取和当前麦克风同组的音频输出设备ID async function getMatchedSinkId() { const stream = await navigator.mediaDevices.getUserMedia({audio: true}); const micTrack = stream.getAudioTracks()[0]; const micGroupId = micTrack.getSettings().groupId; const allDevices = await navigator.mediaDevices.enumerateDevices(); const matchedOutput = allDevices.find(dev => dev.kind === 'audiooutput' && dev.groupId === micGroupId); return matchedOutput ? matchedOutput.deviceId : 'default'; } // 播放时绑定指定输出设备 async function playsound(targetSinkId) { const audio = new Audio("你的音频base64"); await audio.setSinkId(targetSinkId); audio.play(); }
2. 极短音频无法正常播放的原因和优化方案
原因
- 每次播放都重新创建
Audio实例,即使是base64资源,浏览器解析音频头、初始化解码也需要耗时,极短音频的时长可能短于解码初始化时间,解码完成时播放逻辑已经终止,就会出现无声音的情况 - 部分浏览器对时长低于100ms的极短音频有静默优化策略,避免高频短音频干扰用户,频繁点击时浏览器检测到持续交互意图才会放行播放
优化方案
提前预加载缓存音频实例,不要每次播放重复创建:
// 全局提前初始化缓存音频 const notifyAudio = new Audio("你的音频base64"); notifyAudio.load(); function playsound() { notifyAudio.currentTime = 0; notifyAudio.play().catch(err => console.log(err)); }
内容的提问来源于stack exchange,提问作者Cine
相关产品推荐
相关产品推荐

