自 v4.6.2 版本开始,SDK 会基于 浏览器原生 devicechange 事件 检测摄像头、麦克风的插拔行为,并在恰当时机,自动恢复采集推流。具体逻辑如下:
- 若当前正在推流的摄像头/麦克风被拔出,SDK 会尝试使用剩余可用的媒体设备,恢复采集并推流。
- 若摄像头/麦克风被拔出后,没有可用的媒体设备。SDK 会检测设备插入行为,若插入了新的可用的媒体设备,SDK 会尝试使用新插入的媒体设备,恢复采集并推流。
- 若恢复失败,则会抛出错误 DEVICE_AUTO_RECOVER_FAILED
本文主要介绍如何基于 浏览器原生 devicechange 事件 检测设备插拔行为,并在恰当时机提醒用户检查设备。
获取新增、移除的设备列表
当设备发生变更时,会触发 devicechange 事件。通过比对 devicechange 事件触发前后的设备列表,可以检测出设备新增和设备移除。
// 1. 保存一份设备列表
let prevDevices = await TRTC.getDevices();
// 2. 监听设备变更事件
navigator.mediaDevices.addEventListener('devicechange', async () => {
// 3. 设备变更时,获取变更后的设备列表,用于和 prevDevices 比对
const devices = await TRTC.getDevices();
// 4. 新增的设备列表
const devicesAdded = devices.filter(device => prevDevices.findIndex(({ deviceId }) => device.deviceId === deviceId) < 0);
// 5. 移除的设备列表
const devicesRemoved = prevDevices.filter(prevDevice => devices.findIndex(({ deviceId }) => prevDevice.deviceId === deviceId) < 0);
if (devicesAdded.length > 0) {
handleDevicesAdded(devicesAdded);
}
if (devicesRemoved.length > 0) {
handleDevicesRemoved(devicesRemoved);
}
prevDevices = devices;
});
处理设备新增、移除的设备列表
function handleDevicesAdded(devicesAdded) {
devicesAdded.forEach(device => {
if (device.kind === 'audioinput') {
// 提示用户检测到新麦克风插入。若用户需要切换到新设备,可以调用 localStream.switchDevice 接口切换设备
} else if (device.kind === 'videoinput') {
// 提示用户检测到新摄像头插入。若用户需要切换到新设备,可以调用 localStream.switchDevice 接口切换设备
}
});
}
function handleDevicesRemoved(devicesRemoved) {
devicesRemoved.forEach(device => {
if (device.kind === 'audioinput') {
// 提示用户检测到麦克风拔出。
if (isCurrentMicrophoneRemoved(device.deviceId)) {
// 当前正在使用的麦克风被拔出
}
} else if (device.kind === 'videoinput') {
// 提示用户检测到摄像头拔出。
if (isCurrentCameraRemoved(device.deviceId)) {
// 当前正在使用的摄像头被拔出
}
}
});
}
判断是否当前正在使用的设备被拔出
通过 MediaStreamTrack.getSettings() 方法,获取当前 LocalStream 正在使用的 deviceId,将其与 devicesRemoved 列表中的 deviceId 比对,可以检测出是否当前正在使用的设备被拔出。
// 检测是否当前正在使用的麦克风设备被拔出
// microphoneIdRemoved 是被移除的麦克风 deviceId
function isCurrentMicrophoneRemoved(microphoneIdRemoved) {
const audioTrack = localStream.getAudioTrack();
if (audioTrack && audioTrack.getSettings().deviceId === microphoneIdRemoved) {
return true;
} else {
return false;
}
}
// 检测是否当前正在使用的摄像头设备被拔出
// cameraIdRemoved 是被移除的摄像头 deviceId
function isCurrentCameraRemoved(cameraIdRemoved) {
const videoTrack = localStream.getVideoTrack();
if (videoTrack && videoTrack.getSettings().deviceId === cameraIdRemoved) {
return true;
} else {
return false;
}
}