Третий селект в DeviceSettingsDialog (динамики/наушники/bluetooth) рядом с уже существующими микрофоном и камерой — на useMediaDeviceSelect(kind: 'audiooutput'). Выбор персистится отдельно от usePersistentUserChoices (LocalUserChoices LiveKit про аудиовыход не знает) и применяется заново при следующем подключении через RoomOptions.audioOutput. Поддержка определяется по наличию setSinkId в рантайме, не по User-Agent: там, где браузер не умеет переключать вывод (iOS Safari), список скрыт, вместо него — подсказка, что маршрутизация звука на стороне системы.
34 lines
1.5 KiB
TypeScript
34 lines
1.5 KiB
TypeScript
const STORAGE_KEY = 'vidconf-audio-output-device'
|
||
|
||
/**
|
||
* Поддержка выбора устройства аудиовывода — определяем по наличию
|
||
* `setSinkId` в рантайме, НЕ по User-Agent: в iOS Safari метода нет вообще
|
||
* (маршрутизация звука там целиком на стороне ОС), в Android Chrome есть.
|
||
*/
|
||
export function isAudioOutputSelectable(): boolean {
|
||
return typeof HTMLMediaElement !== 'undefined' && 'setSinkId' in HTMLMediaElement.prototype
|
||
}
|
||
|
||
/**
|
||
* Персист выбранного устройства вывода — отдельно от `usePersistentUserChoices`
|
||
* LiveKit: их `LocalUserChoices` знает только про вход (микрофон/камера),
|
||
* поля для аудиовыхода там нет.
|
||
*/
|
||
export function loadAudioOutputDeviceId(): string {
|
||
try {
|
||
return localStorage.getItem(STORAGE_KEY) ?? ''
|
||
} catch {
|
||
// localStorage недоступен (приватный режим/политики браузера) — без
|
||
// сохранённого выбора, устройство по умолчанию.
|
||
return ''
|
||
}
|
||
}
|
||
|
||
export function saveAudioOutputDeviceId(deviceId: string): void {
|
||
try {
|
||
localStorage.setItem(STORAGE_KEY, deviceId)
|
||
} catch {
|
||
// Сохранение недоступно — выбор продержится до конца сессии в комнате.
|
||
}
|
||
}
|