fix: 拍照默认摄像头按标签精确匹配后置,不再依赖枚举顺序

之前默认摄像头是"设备列表第一个",依赖操作系统 enumerateDevices()
返回顺序,不可靠。真机测出后置摄像头(朝外拍摄那颗)的 label 是
"Hy-8M(8079)-Camera",改成按标签里的型号数字串精确匹配。

摄像头 label 在 getUserMedia 拿到权限前是空的(浏览器隐私限制),
没法一开始就按标签选,所以流程改成:先用默认设备开流拿到权限,
权限到手后 label 才是真的,这时候如果不是用户/配置显式指定的摄像头,
再检查当前是不是已经是后置、不是就切过去。

真机验证:清空之前手动切换保留下来的摄像头偏好后重新打开,稳定落在
后置摄像头(桌面/Mac mini 视角),不再随机。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ssurui 2026-09-03 16:06:28 +08:00
parent 0d19be58c3
commit b918a0c53f

View File

@ -18,6 +18,10 @@ const capturedDataUrl = ref('')
const starting = ref(false)
const errorMessage = ref('')
// 真机实测确认的后置摄像头(朝外拍摄那颗)标签是 "Hy-8M(8079)-Camera",
// 用型号里的数字串匹配,不依赖完整标签文案(避免语言环境/固件版本差异导致匹配不上)
const REAR_CAMERA_LABEL_HINT = '8079'
let stream: MediaStream | null = null
function stopStream(): void {
@ -58,6 +62,10 @@ async function refreshDevices(): Promise<void> {
}
}
function findRearCamera(): MediaDeviceInfo | undefined {
return devices.value.find((d) => d.label.includes(REAR_CAMERA_LABEL_HINT))
}
async function switchDevice(deviceId: string): Promise<void> {
selectedDeviceId.value = deviceId
emit('deviceChange', deviceId)
@ -109,8 +117,16 @@ watch(
if (val) {
capturedDataUrl.value = ''
selectedDeviceId.value = props.initialDeviceId
await refreshDevices()
// 摄像头 label 在拿到权限前是空的(浏览器隐私限制),没法在这一步就按标签
// 找后置摄像头,先随便开一个拿到权限;startStream 成功后 devices 里才有真实 label。
await startStream(selectedDeviceId.value)
// 用户/配置没有指定具体摄像头时,权限到手后尝试切到确认过的后置摄像头
if (!props.initialDeviceId) {
const rear = findRearCamera()
if (rear && rear.deviceId !== selectedDeviceId.value) {
await switchDevice(rear.deviceId)
}
}
} else {
stopStream()
}