From 2c1a3a03c819d308096bf061dbb297cda64df2fc Mon Sep 17 00:00:00 2001 From: winter_NaN Date: Mon, 21 Oct 2024 20:39:13 +0800 Subject: [PATCH 1/7] fix(web): obtain media device label --- webapp/components/device.tsx | 104 ++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 14 deletions(-) diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index 02ec08a..d9f5102 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -11,8 +11,47 @@ import SvgAudio from './svg/audio' import SvgVideo from './svg/video' import { SvgPresentCancel, SvgPresentToAll } from './svg/present' -export default function DeviceBar(props: { streamId: string }) { - const [permissionAudio, setPermissionAudio] = useState("") +// 1.将每个设备的 deviceId 和 label 转换为可显示的格式。如果 label 为空,会使用设备类型和 deviceId 作为显示名称。 +function deviceInfoToOption(info: MediaDeviceInfo) { + const value = info.deviceId; + let text = info.label; + if (text.length <= 0) { + text = `${info.kind} (${info.deviceId})`; + } + return { value, text }; +} + +// 2.uniqByValue 去重 +function uniqByValue(items: T[]) { + const map = new Map(); + for (const item of items) { + if (!map.has(item.value)) { + map.set(item.value, item); + } + } + return Array.from(map.values()); +} + +// 3.转换为Device格式 +// const convertToDevice = (items: { value: string; text: string }[]): Device[] => { // 箭头函数不用function关键字 +// return items.map(item => ({ +// deviceId: item.value, // 使用 value 作为 deviceId +// label: item.text // 使用 text 作为 label +// })); +// } +const convertToDevice = (items: { value: string; text: string }[], kind: MediaDeviceKind): MediaDeviceInfo[] => { + return items.map(item => ({ + deviceId: item.value, // 使用 value 作为 deviceId + kind, // 使用传入的 kind 参数,比如 "audioinput" + label: item.text, // 使用 text 作为 label + groupId: '', // groupId 可留空,或者你有对应信息可以填入 + + })as MediaDeviceInfo); +} + +export default function DeviceBar(props: { streamId: string }) { + + const [permissionAudio, setPermissionAudio] = useState("") const [permissionVideo, setPermissionVideo] = useState("") const [loadingAudio, setLoadingAudio] = useState(false) @@ -29,7 +68,7 @@ export default function DeviceBar(props: { streamId: string }) { toggleEnableVideo, } = useWhipClient(props.streamId) - const [deviceAudio, setDeviceAudio] = useState([deviceNone]) + const [deviceAudio, setAudioDevices] = useState([deviceNone]) const [deviceVideo, setDeviceVideo] = useState([deviceNone]) const permissionsQuery = async () => @@ -48,7 +87,7 @@ export default function DeviceBar(props: { streamId: string }) { // NOTE: // Chrome: audio_capture, video_capture // Safari: microphone, camera - if (status.name === "audio_capture" || "microphone") { + if (status.name === "audio_capture" || "microphone") { // "microphone"作为string不一直为ture吗? setPermissionAudio(status.state) } if (status.name === "video_capture" || "camera") { @@ -58,21 +97,58 @@ export default function DeviceBar(props: { streamId: string }) { const updateDeviceList = async () => { const devices = (await navigator.mediaDevices.enumerateDevices()).filter(i => !!i.deviceId) - const audios: Device[] = devices.filter(i => i.kind === 'audioinput') - const videos: Device[] = devices.filter(i => i.kind === 'videoinput') + + // 使用 deviceInfoToOption加载设备列表 + const audios = devices.filter(i => i.kind === 'audioinput').map(deviceInfoToOption) + + console.log('this is audios:',audios) + + const videos = devices.filter(i => i.kind === 'videoinput').map(deviceInfoToOption); + //const audios: Device[] = devices.filter(i => i.kind === 'audioinput') + //const videos: Device[] = devices.filter(i => i.kind === 'videoinput') + + // 使用 uniqByValue 去重 + const uniqueAudios = uniqByValue(audios); + console.log('this is uniqueAudios:',uniqueAudios) + const uniqueVideos = uniqByValue(videos); + console.log('this is currentDeviceAudio:',currentDeviceAudio) if (currentDeviceAudio === deviceNone.deviceId) { - let device = audios[0] - if (device) await setCurrentDeviceAudio(device.deviceId) + let device = uniqueAudios[0] + if (device) + { + try { + await setCurrentDeviceAudio(device.value) + console.log('Audio device set successfully') + } catch (error) { + console.error('Failed to set audio device:', error) + } + } + //await setCurrentDeviceAudio(device.value) } if (currentDeviceVideo === deviceNone.deviceId) { - let device = videos[0] - if (device) await setCurrentDeviceVideo(device.deviceId) + let device = uniqueVideos[0] + if (device) { + try { + await setCurrentDeviceVideo(device.value) + console.log('Video device set successfully') + } catch (error) { + console.error('Failed to set video device:', error) + } + }else{ + console.log('no video devices:') + await setCurrentDeviceVideo(deviceNone.deviceId) + + } } - setDeviceAudio([...audios]) - setDeviceVideo([...videos, deviceScreen]) + console.log('this is convertToDevice(uniqueAudios):',convertToDevice(uniqueAudios,'audioinput')) + + + setAudioDevices(convertToDevice(uniqueAudios,'audioinput')) + setDeviceVideo(convertToDevice(uniqueVideos,'videoinput')) + } const init = async () => { @@ -113,7 +189,7 @@ export default function DeviceBar(props: { streamId: string }) { setLoadingScreen(true) await onChangedDeviceVideo(userStatus.screen ? deviceNone.deviceId : deviceScreen.deviceId) setLoadingScreen(false) - } + } return (
@@ -181,7 +257,7 @@ export default function DeviceBar(props: { streamId: string }) { onChange={e => onChangedDeviceVideo(e.target.value)} > {deviceVideo.map(device => - + )} From b61ca195c5580255d26a0615d1b20a83fdf6860d Mon Sep 17 00:00:00 2001 From: winter_NaN Date: Sat, 26 Oct 2024 01:50:09 +0800 Subject: [PATCH 2/7] correct code issues Signed-off-by: winter_NaN --- .github/CLA.md | 3 +- webapp/components/device.tsx | 69 +++++++++++++----------------------- 2 files changed, 27 insertions(+), 45 deletions(-) diff --git a/.github/CLA.md b/.github/CLA.md index e47d791..7b51949 100644 --- a/.github/CLA.md +++ b/.github/CLA.md @@ -44,4 +44,5 @@ Example: --> - Metal A-wing, @a-wing, 2024/10/23 -- Hongcha Zhang, @hongcha98, 2024/10/24 \ No newline at end of file +- Hongcha Zhang, @hongcha98, 2024/10/24 +- Winter Zhang, @WinterJack002, 2024/10/26 diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index d9f5102..7c3ab95 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -11,18 +11,18 @@ import SvgAudio from './svg/audio' import SvgVideo from './svg/video' import { SvgPresentCancel, SvgPresentToAll } from './svg/present' -// 1.将每个设备的 deviceId 和 label 转换为可显示的格式。如果 label 为空,会使用设备类型和 deviceId 作为显示名称。 +// 1. Converts each device's deviceId and label into a displayable format. If label is empty, uses the device type and deviceId as the display name. function deviceInfoToOption(info: MediaDeviceInfo) { const value = info.deviceId; - let text = info.label; + let text = info.label; if (text.length <= 0) { text = `${info.kind} (${info.deviceId})`; } return { value, text }; } -// 2.uniqByValue 去重 -function uniqByValue(items: T[]) { +// 2. Removes duplicate items based on their value. +function uniqByValue(items: T[]) { const map = new Map(); for (const item of items) { if (!map.has(item.value)) { @@ -32,26 +32,20 @@ function uniqByValue(items: T[]) { return Array.from(map.values()); } -// 3.转换为Device格式 -// const convertToDevice = (items: { value: string; text: string }[]): Device[] => { // 箭头函数不用function关键字 -// return items.map(item => ({ -// deviceId: item.value, // 使用 value 作为 deviceId -// label: item.text // 使用 text 作为 label -// })); -// } +// 3. Converts items to Device format const convertToDevice = (items: { value: string; text: string }[], kind: MediaDeviceKind): MediaDeviceInfo[] => { return items.map(item => ({ - deviceId: item.value, // 使用 value 作为 deviceId - kind, // 使用传入的 kind 参数,比如 "audioinput" - label: item.text, // 使用 text 作为 label - groupId: '', // groupId 可留空,或者你有对应信息可以填入 - + deviceId: item.value, // use value as the device ID + kind, + label: item.text, // use text as the label + groupId: '', + })as MediaDeviceInfo); } -export default function DeviceBar(props: { streamId: string }) { - - const [permissionAudio, setPermissionAudio] = useState("") +export default function DeviceBar(props: { streamId: string }) { + + const [permissionAudio, setPermissionAudio] = useState("") const [permissionVideo, setPermissionVideo] = useState("") const [loadingAudio, setLoadingAudio] = useState(false) @@ -68,7 +62,7 @@ export default function DeviceBar(props: { streamId: string }) { toggleEnableVideo, } = useWhipClient(props.streamId) - const [deviceAudio, setAudioDevices] = useState([deviceNone]) + const [deviceAudio, setDeviceAudio] = useState([deviceNone]) const [deviceVideo, setDeviceVideo] = useState([deviceNone]) const permissionsQuery = async () => @@ -87,35 +81,25 @@ export default function DeviceBar(props: { streamId: string }) { // NOTE: // Chrome: audio_capture, video_capture // Safari: microphone, camera - if (status.name === "audio_capture" || "microphone") { // "microphone"作为string不一直为ture吗? + if (status.name === "audio_capture" || status.name === "microphone") { setPermissionAudio(status.state) } - if (status.name === "video_capture" || "camera") { + if (status.name === "video_capture" || status.name === "camera") { setPermissionVideo(status.state) } }) const updateDeviceList = async () => { const devices = (await navigator.mediaDevices.enumerateDevices()).filter(i => !!i.deviceId) - - // 使用 deviceInfoToOption加载设备列表 const audios = devices.filter(i => i.kind === 'audioinput').map(deviceInfoToOption) - - console.log('this is audios:',audios) - const videos = devices.filter(i => i.kind === 'videoinput').map(deviceInfoToOption); - //const audios: Device[] = devices.filter(i => i.kind === 'audioinput') - //const videos: Device[] = devices.filter(i => i.kind === 'videoinput') - // 使用 uniqByValue 去重 - const uniqueAudios = uniqByValue(audios); - console.log('this is uniqueAudios:',uniqueAudios) - const uniqueVideos = uniqByValue(videos); - console.log('this is currentDeviceAudio:',currentDeviceAudio) + const uniqueAudios = uniqByValue(audios); + const uniqueVideos = uniqByValue(videos); if (currentDeviceAudio === deviceNone.deviceId) { let device = uniqueAudios[0] - if (device) + if (device) { try { await setCurrentDeviceAudio(device.value) @@ -124,31 +108,28 @@ export default function DeviceBar(props: { streamId: string }) { console.error('Failed to set audio device:', error) } } - //await setCurrentDeviceAudio(device.value) + } if (currentDeviceVideo === deviceNone.deviceId) { let device = uniqueVideos[0] if (device) { try { - await setCurrentDeviceVideo(device.value) + await setCurrentDeviceVideo(device.value) console.log('Video device set successfully') } catch (error) { console.error('Failed to set video device:', error) } - }else{ + } else { console.log('no video devices:') await setCurrentDeviceVideo(deviceNone.deviceId) } } - console.log('this is convertToDevice(uniqueAudios):',convertToDevice(uniqueAudios,'audioinput')) - - - setAudioDevices(convertToDevice(uniqueAudios,'audioinput')) + setDeviceAudio(convertToDevice(uniqueAudios,'audioinput')) setDeviceVideo(convertToDevice(uniqueVideos,'videoinput')) - + } const init = async () => { @@ -189,7 +170,7 @@ export default function DeviceBar(props: { streamId: string }) { setLoadingScreen(true) await onChangedDeviceVideo(userStatus.screen ? deviceNone.deviceId : deviceScreen.deviceId) setLoadingScreen(false) - } + } return (
From 0889d17c1408d122f9bb2062d8144b40403d7d70 Mon Sep 17 00:00:00 2001 From: winter_NaN Date: Mon, 4 Nov 2024 09:10:46 +0800 Subject: [PATCH 3/7] fix firefox lable issues sec. --- webapp/components/device.tsx | 78 +++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index 7c3ab95..9579bfc 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -44,7 +44,6 @@ const convertToDevice = (items: { value: string; text: string }[], kind: MediaDe } export default function DeviceBar(props: { streamId: string }) { - const [permissionAudio, setPermissionAudio] = useState("") const [permissionVideo, setPermissionVideo] = useState("") @@ -65,29 +64,36 @@ export default function DeviceBar(props: { streamId: string }) { const [deviceAudio, setDeviceAudio] = useState([deviceNone]) const [deviceVideo, setDeviceVideo] = useState([deviceNone]) - const permissionsQuery = async () => - (await Promise.all(["camera", "microphone"].map( - // NOTE: - // Firefox don't have `camera` and `microphone` in permissions - // https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query#name - // https://searchfox.org/mozilla-central/source/dom/webidl/Permissions.webidl#10 - // - // NOTE: - // PermissionName - // https://w3c.github.io/permissions/ - // Reference: https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API - i => navigator.permissions.query({ name: i as PermissionName }) - ))).map(status => { - // NOTE: - // Chrome: audio_capture, video_capture - // Safari: microphone, camera - if (status.name === "audio_capture" || status.name === "microphone") { - setPermissionAudio(status.state) - } - if (status.name === "video_capture" || status.name === "camera") { - setPermissionVideo(status.state) - } - }) + const permissionsQuery = async () => { + const isFirefox = navigator.userAgent.toLowerCase().includes('firefox') + if (isFirefox) { + await navigator.mediaDevices.getUserMedia({ audio: true }).catch(() => {}) + await navigator.mediaDevices.getUserMedia({ video: true }).catch(() => {}) + } else { + (await Promise.all(["camera", "microphone"].map( + // NOTE: + // Firefox don't have `camera` and `microphone` in permissions + // https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query#name + // https://searchfox.org/mozilla-central/source/dom/webidl/Permissions.webidl#10 + // + // NOTE: + // PermissionName + // https://w3c.github.io/permissions/ + // Reference: https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API + i => navigator.permissions.query({ name: i as PermissionName }) + ))).map(status => { + // NOTE: + // Chrome: audio_capture, video_capture + // Safari: microphone, camera + if (status.name === "audio_capture" || status.name === "microphone") { + setPermissionAudio(status.state) + } + if (status.name === "video_capture" || status.name === "camera") { + setPermissionVideo(status.state) + } + }) + } + } const updateDeviceList = async () => { const devices = (await navigator.mediaDevices.enumerateDevices()).filter(i => !!i.deviceId) @@ -99,16 +105,13 @@ export default function DeviceBar(props: { streamId: string }) { if (currentDeviceAudio === deviceNone.deviceId) { let device = uniqueAudios[0] - if (device) - { + if (device){ try { await setCurrentDeviceAudio(device.value) - console.log('Audio device set successfully') } catch (error) { console.error('Failed to set audio device:', error) } } - } if (currentDeviceVideo === deviceNone.deviceId) { @@ -116,25 +119,28 @@ export default function DeviceBar(props: { streamId: string }) { if (device) { try { await setCurrentDeviceVideo(device.value) - console.log('Video device set successfully') } catch (error) { console.error('Failed to set video device:', error) } } else { - console.log('no video devices:') - await setCurrentDeviceVideo(deviceNone.deviceId) - + console.log('no video devices:') + await setCurrentDeviceVideo(deviceNone.deviceId) } } - setDeviceAudio(convertToDevice(uniqueAudios,'audioinput')) - setDeviceVideo(convertToDevice(uniqueVideos,'videoinput')) - + setDeviceAudio(...[convertToDevice(uniqueAudios,'audioinput')]) + setDeviceVideo([...convertToDevice(uniqueVideos,'videoinput'), deviceScreen]) } const init = async () => { try { - (await navigator.mediaDevices.getUserMedia({ video: true, audio: true })).getTracks().map(track => track.stop()) + await navigator.mediaDevices.getUserMedia({ audio: true }) + .then(stream => stream.getTracks().forEach(track => track.stop())) + .catch(() => console.warn("No audio device available")) + + await navigator.mediaDevices.getUserMedia({ video: true }) + .then(stream => stream.getTracks().forEach(track => track.stop())) + .catch(() => console.warn("No video device available")) // NOTE: // In some device have problem: // - Android Web Browser From be04f1bbf8478746daed44a6afcc58ad6f10e481 Mon Sep 17 00:00:00 2001 From: winter_NaN Date: Mon, 4 Nov 2024 09:31:12 +0800 Subject: [PATCH 4/7] deal with device lable and coding format --- webapp/components/device.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index 9579bfc..cd322a1 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -122,14 +122,14 @@ export default function DeviceBar(props: { streamId: string }) { } catch (error) { console.error('Failed to set video device:', error) } - } else { - console.log('no video devices:') - await setCurrentDeviceVideo(deviceNone.deviceId) - } + } else { + console.log('no video devices:') + await setCurrentDeviceVideo(deviceNone.deviceId) + } } - setDeviceAudio(...[convertToDevice(uniqueAudios,'audioinput')]) - setDeviceVideo([...convertToDevice(uniqueVideos,'videoinput'), deviceScreen]) + setDeviceAudio(...[convertToDevice(uniqueAudios, 'audioinput')]) + setDeviceVideo([...convertToDevice(uniqueVideos, 'videoinput'), deviceScreen]) } const init = async () => { From 290807d51c687d99c118b99bbddd29592331aed9 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Tue, 5 Nov 2024 20:16:44 +0800 Subject: [PATCH 5/7] refactor device and fix device change --- webapp/components/device.tsx | 91 +++++++++--------------------------- 1 file changed, 21 insertions(+), 70 deletions(-) diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index cd322a1..ea53e61 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -11,36 +11,13 @@ import SvgAudio from './svg/audio' import SvgVideo from './svg/video' import { SvgPresentCancel, SvgPresentToAll } from './svg/present' -// 1. Converts each device's deviceId and label into a displayable format. If label is empty, uses the device type and deviceId as the display name. -function deviceInfoToOption(info: MediaDeviceInfo) { - const value = info.deviceId; - let text = info.label; - if (text.length <= 0) { - text = `${info.kind} (${info.deviceId})`; +function toDevice(info: MediaDeviceInfo): Device { + const deviceId = info.deviceId; + let label = info.label; + if (label.length <= 0) { + label = `${info.kind} (${deviceId.substring(0, 8)})`; } - return { value, text }; -} - -// 2. Removes duplicate items based on their value. -function uniqByValue(items: T[]) { - const map = new Map(); - for (const item of items) { - if (!map.has(item.value)) { - map.set(item.value, item); - } - } - return Array.from(map.values()); -} - -// 3. Converts items to Device format -const convertToDevice = (items: { value: string; text: string }[], kind: MediaDeviceKind): MediaDeviceInfo[] => { - return items.map(item => ({ - deviceId: item.value, // use value as the device ID - kind, - label: item.text, // use text as the label - groupId: '', - - })as MediaDeviceInfo); + return { deviceId, label }; } export default function DeviceBar(props: { streamId: string }) { @@ -64,12 +41,7 @@ export default function DeviceBar(props: { streamId: string }) { const [deviceAudio, setDeviceAudio] = useState([deviceNone]) const [deviceVideo, setDeviceVideo] = useState([deviceNone]) - const permissionsQuery = async () => { - const isFirefox = navigator.userAgent.toLowerCase().includes('firefox') - if (isFirefox) { - await navigator.mediaDevices.getUserMedia({ audio: true }).catch(() => {}) - await navigator.mediaDevices.getUserMedia({ video: true }).catch(() => {}) - } else { + const permissionsQuery = async () => (await Promise.all(["camera", "microphone"].map( // NOTE: // Firefox don't have `camera` and `microphone` in permissions @@ -92,55 +64,34 @@ export default function DeviceBar(props: { streamId: string }) { setPermissionVideo(status.state) } }) - } - } const updateDeviceList = async () => { + // to obtain non-empty device label, there needs to be an active media stream or persistent permission + // https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo/label#value + await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); + const devices = (await navigator.mediaDevices.enumerateDevices()).filter(i => !!i.deviceId) - const audios = devices.filter(i => i.kind === 'audioinput').map(deviceInfoToOption) - const videos = devices.filter(i => i.kind === 'videoinput').map(deviceInfoToOption); - const uniqueAudios = uniqByValue(audios); - const uniqueVideos = uniqByValue(videos); + const audios = devices.filter(i => i.kind === 'audioinput').map(toDevice) + const videos = devices.filter(i => i.kind === 'videoinput').map(toDevice) if (currentDeviceAudio === deviceNone.deviceId) { - let device = uniqueAudios[0] - if (device){ - try { - await setCurrentDeviceAudio(device.value) - } catch (error) { - console.error('Failed to set audio device:', error) - } - } + let device = audios[0] + await setCurrentDeviceAudio(device ? device.deviceId : deviceNone.deviceId) } if (currentDeviceVideo === deviceNone.deviceId) { - let device = uniqueVideos[0] - if (device) { - try { - await setCurrentDeviceVideo(device.value) - } catch (error) { - console.error('Failed to set video device:', error) - } - } else { - console.log('no video devices:') - await setCurrentDeviceVideo(deviceNone.deviceId) - } + let device = videos[0] + await setCurrentDeviceVideo(device ? device.deviceId : deviceNone.deviceId) } - setDeviceAudio(...[convertToDevice(uniqueAudios, 'audioinput')]) - setDeviceVideo([...convertToDevice(uniqueVideos, 'videoinput'), deviceScreen]) + setDeviceAudio([...audios]) + setDeviceVideo([...videos, deviceScreen]) } const init = async () => { try { - await navigator.mediaDevices.getUserMedia({ audio: true }) - .then(stream => stream.getTracks().forEach(track => track.stop())) - .catch(() => console.warn("No audio device available")) - - await navigator.mediaDevices.getUserMedia({ video: true }) - .then(stream => stream.getTracks().forEach(track => track.stop())) - .catch(() => console.warn("No video device available")) + (await navigator.mediaDevices.getUserMedia({ video: true, audio: true })).getTracks().map(track => track.stop()) // NOTE: // In some device have problem: // - Android Web Browser @@ -244,7 +195,7 @@ export default function DeviceBar(props: { streamId: string }) { onChange={e => onChangedDeviceVideo(e.target.value)} > {deviceVideo.map(device => - + )} From fa269505bb8c4b78fd8480d52cb72ea245080547 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Tue, 5 Nov 2024 20:18:37 +0800 Subject: [PATCH 6/7] fix code format --- webapp/components/device.tsx | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index ea53e61..d69fec7 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -42,28 +42,28 @@ export default function DeviceBar(props: { streamId: string }) { const [deviceVideo, setDeviceVideo] = useState([deviceNone]) const permissionsQuery = async () => - (await Promise.all(["camera", "microphone"].map( - // NOTE: - // Firefox don't have `camera` and `microphone` in permissions - // https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query#name - // https://searchfox.org/mozilla-central/source/dom/webidl/Permissions.webidl#10 - // - // NOTE: - // PermissionName - // https://w3c.github.io/permissions/ - // Reference: https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API - i => navigator.permissions.query({ name: i as PermissionName }) - ))).map(status => { - // NOTE: - // Chrome: audio_capture, video_capture - // Safari: microphone, camera - if (status.name === "audio_capture" || status.name === "microphone") { - setPermissionAudio(status.state) - } - if (status.name === "video_capture" || status.name === "camera") { - setPermissionVideo(status.state) - } - }) + (await Promise.all(["camera", "microphone"].map( + // NOTE: + // Firefox don't have `camera` and `microphone` in permissions + // https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query#name + // https://searchfox.org/mozilla-central/source/dom/webidl/Permissions.webidl#10 + // + // NOTE: + // PermissionName + // https://w3c.github.io/permissions/ + // Reference: https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API + i => navigator.permissions.query({ name: i as PermissionName }) + ))).map(status => { + // NOTE: + // Chrome: audio_capture, video_capture + // Safari: microphone, camera + if (status.name === "audio_capture" || status.name === "microphone") { + setPermissionAudio(status.state) + } + if (status.name === "video_capture" || status.name === "camera") { + setPermissionVideo(status.state) + } + }) const updateDeviceList = async () => { // to obtain non-empty device label, there needs to be an active media stream or persistent permission From 380c2b6abdf20cee5fcd8c9eb58eef233c230e43 Mon Sep 17 00:00:00 2001 From: a-wing <1@233.email> Date: Tue, 5 Nov 2024 20:23:28 +0800 Subject: [PATCH 7/7] fix deviceNone --- webapp/components/device.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index d69fec7..6795ff4 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -77,12 +77,12 @@ export default function DeviceBar(props: { streamId: string }) { if (currentDeviceAudio === deviceNone.deviceId) { let device = audios[0] - await setCurrentDeviceAudio(device ? device.deviceId : deviceNone.deviceId) + if (device) await setCurrentDeviceAudio(device.deviceId) } if (currentDeviceVideo === deviceNone.deviceId) { let device = videos[0] - await setCurrentDeviceVideo(device ? device.deviceId : deviceNone.deviceId) + if (device) await setCurrentDeviceVideo(device.deviceId) } setDeviceAudio([...audios])