diff --git a/src/controls.ts b/src/controls.ts index b6dec6d1..79ba075f 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ -import { Subject } from "rxjs"; +import { BehaviorSubject, Subject } from "rxjs"; export interface Controls { canEnterPip(): boolean; @@ -27,9 +27,26 @@ export interface OutputDevice { isExternalHeadset?: boolean; } +/** + * If pipMode is enabled, EC will render a adapted call view layout. + */ export const setPipEnabled$ = new Subject(); -export const setAvailableOutputDevices$ = new Subject(); -export const setOutputDevice$ = new Subject(); +// BehaviorSubject since the client might set this before we have subscribed (GroupCallView still in "loading" state) +// We want the that has been set during loading to be be available immediately once loaded. +export const setAvailableOutputDevices$ = new BehaviorSubject( + [], +); +// BehaviorSubject since the client might set this before we have subscribed (GroupCallView still in "loading" state) +// We want the that has been set during loading to be be available immediately once loaded. +export const setOutputDevice$ = new BehaviorSubject( + undefined, +); +/** + * This is currently unused. It might be possible to allow the os to mute the call this way if the user + * presses the volume down button when it is at the minimum volume. + * + * This should also be used to display a darkened overlay screen letting the user know that audio is muted. + */ export const setOutputEnabled$ = new Subject(); window.controls = { @@ -45,18 +62,16 @@ window.controls = { setPipEnabled$.next(false); }, setAvailableOutputDevices(devices: OutputDevice[]): void { - if (!setAvailableOutputDevices$.observed) - throw new Error("Output controls are disabled. No setAvailableOutputDevices$ observer"); setAvailableOutputDevices$.next(devices); }, setOutputDevice(id: string): void { - if (!setOutputDevice$.observed) - throw new Error("Output controls are disabled. No setOutputDevice$ observer"); setOutputDevice$.next(id); }, setOutputEnabled(enabled: boolean): void { if (!setOutputEnabled$.observed) - throw new Error("Output controls are disabled. No setOutputEnabled$ observer"); + throw new Error( + "Output controls are disabled. No setOutputEnabled$ observer", + ); setOutputEnabled$.next(!enabled); }, }; diff --git a/src/livekit/MediaDevicesContext.tsx b/src/livekit/MediaDevicesContext.tsx index 506f069f..165ba6ca 100644 --- a/src/livekit/MediaDevicesContext.tsx +++ b/src/livekit/MediaDevicesContext.tsx @@ -359,7 +359,9 @@ function useControlledOutput(): MediaDeviceHandle { ); const [preferredId, setPreferredId] = useSetting(audioOutputSetting); useEffect(() => { - setOutputDevice$.subscribe((id) => setPreferredId(id)); + setOutputDevice$.subscribe((id) => { + if (id) setPreferredId(id); + }); }, [setPreferredId]); const selectedId = useSelectedId(available, preferredId);