今天测试又发现一个非常奇怪的问题,在 iOS 16 的设备上,如果 getUserMedia
申请设备权限后执行了清理设备的操作,会导致其他人说话的声音也没有了,除非手动开启一次麦克风才会“解除”这种状态。
function useFixSafariNoSound({ isPCMode }: FixSafariNoSoundProps) {
useEffect(() => {
let stream: MediaStream | undefined;
if ((isPCMode && isIpad) || isSafari) {
navigator.mediaDevices.getUserMedia({ audio: true }).then((res) => {
stream = res;
});
}
return () => {
if (stream) {
stream.getTracks().forEach((track) => {
track.stop();
});
}
};
}, []);
}
目前写了这样一个 Hooks 处理,只要是 iPhone 和 iPad 环境上的 Safari 才会执行这个操作,缺点就是在没有打开麦克风的状态下系统也会提示正在使用麦克风。这段代码只能算是填补了设备授权后清除设备导致没有声音的问题,因为正常情况下没调用申请设备权限应该是不会没声音的。
还有另外一个问题,就是任意音频有概率会使用「听筒播放」而不是「扬声器外放」。测试反馈我前面这个代码应用之后在 iOS 16 上会使用扬声器,但 iOS 15 依旧会默认使用听筒,非常小声,就比较离谱。我测试后发现线上环境也是这样的,估计已经有一段时间了。
和其他项目组的同事确认了下,他们那的设计是“被动型”申请权限,而我这边是“主动型”。简单描述就是他那边需要点击按钮调用,而我们这边是组件挂载就开始轮询调用。
我把这个挂载后的调用注释了,再使用 iOS 15 的设备测试后,发现任意音频的确是默认外放的。也就是说系统选择使用听筒还是外放,是取决于调用 getUserMedia
之前是否已经有音频在外放。
没调用 getUserMedia 的时候有 Audio 对象播放 就是正常外放
调用过 getUserMedia 之后有 Audio 对象播放 就会是听筒
题外话,前阵子买的那几件 T 恤都退货了,花了 8 块邮费,花钱买教训。但糟心感也少了,还是考虑下那些稍贵些的正版吧。