@livekit/components-core
Version:
This package is a wrapper around the [livekit/client-sdk-js](https://github.com/livekit/client-sdk-js) package. It transforms the event based logic into simple to use observable state and component level APIs. This package is the core for all framework sp
71 lines (66 loc) • 2.69 kB
text/typescript
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,
};
}