UNPKG

@livekit/components-core

Version:
71 lines (66 loc) 2.69 kB
import { Track, type LocalAudioTrack, type LocalVideoTrack, type Room, type LocalTrack, getBrowser, } from 'livekit-client'; import { BehaviorSubject } from 'rxjs'; import { log } from '../logger'; import { prefixClass } from '../styles-interface'; import { createActiveDeviceObservable } from '../observables/room'; export type SetMediaDeviceOptions = { /** * If true, adds an `exact` constraint to the getUserMedia request. * The request will fail if this option is true and the device specified is not actually available */ exact?: boolean; }; export function setupDeviceSelector( kind: MediaDeviceKind, room: Room, localTrack?: LocalAudioTrack | LocalVideoTrack, ) { const activeDeviceSubject = new BehaviorSubject<string | undefined>(undefined); const activeDeviceObservable = createActiveDeviceObservable(room, kind); const setActiveMediaDevice = async (id: string, options: SetMediaDeviceOptions = {}) => { if (localTrack) { await localTrack.setDeviceId(options.exact ? { exact: id } : id); const actualId = await localTrack.getDeviceId(false); activeDeviceSubject.next( id === 'default' && localTrack.mediaStreamTrack.label.startsWith('Default') ? id : actualId, ); } else if (room) { const browser = getBrowser(); if (kind === 'audiooutput' && (browser?.name === 'Safari' || browser?.os === 'iOS')) { log.warn(`Switching audio output device is not supported on Safari and iOS.`); return; } log.debug(`Switching active device of kind "${kind}" with id ${id}.`); await room.switchActiveDevice(kind, id, options.exact); const actualDeviceId: string | undefined = room.getActiveDevice(kind) ?? id; if (actualDeviceId !== id && id !== 'default') { log.info( `We tried to select the device with id (${id}), but the browser decided to select the device with id (${actualDeviceId}) instead.`, ); } let targetTrack: LocalTrack | undefined = undefined; if (kind === 'audioinput') targetTrack = room.localParticipant.getTrackPublication(Track.Source.Microphone)?.track; else if (kind === 'videoinput') { targetTrack = room.localParticipant.getTrackPublication(Track.Source.Camera)?.track; } const useDefault = (id === 'default' && !targetTrack) || (id === 'default' && targetTrack?.mediaStreamTrack.label.startsWith('Default')); activeDeviceSubject.next(useDefault ? id : actualDeviceId); } }; const className: string = prefixClass('media-device-select'); return { className, activeDeviceObservable, setActiveMediaDevice, }; }