review
This commit is contained in:
@@ -32,17 +32,13 @@ export interface OutputDevice {
|
||||
*/
|
||||
export const setPipEnabled$ = new Subject<boolean>();
|
||||
// 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<OutputDevice[]>(
|
||||
[],
|
||||
);
|
||||
// We want the devices that have been set during loading to be available immediately once loaded.
|
||||
export const availableOutputDevices$ = new BehaviorSubject<OutputDevice[]>([]);
|
||||
// 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<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
// We want the device that has been set during loading to be available immediately once loaded.
|
||||
export const outputDevice$ = new BehaviorSubject<string | undefined>(undefined);
|
||||
/**
|
||||
* This is currently unused. It might be possible to allow the os to mute the call this way if the user
|
||||
* This allows the os to mute the call 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.
|
||||
@@ -62,16 +58,16 @@ window.controls = {
|
||||
setPipEnabled$.next(false);
|
||||
},
|
||||
setAvailableOutputDevices(devices: OutputDevice[]): void {
|
||||
setAvailableOutputDevices$.next(devices);
|
||||
availableOutputDevices$.next(devices);
|
||||
},
|
||||
setOutputDevice(id: string): void {
|
||||
setOutputDevice$.next(id);
|
||||
outputDevice$.next(id);
|
||||
},
|
||||
setOutputEnabled(enabled: boolean): void {
|
||||
if (!setOutputEnabled$.observed)
|
||||
throw new Error(
|
||||
"Output controls are disabled. No setOutputEnabled$ observer",
|
||||
);
|
||||
setOutputEnabled$.next(!enabled);
|
||||
setOutputEnabled$.next(enabled);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
alwaysShowIphoneEarpiece as alwaysShowIphoneEarpieceSetting,
|
||||
type Setting,
|
||||
} from "../settings/settings";
|
||||
import { setAvailableOutputDevices$, setOutputDevice$ } from "../controls";
|
||||
import { outputDevice$, availableOutputDevices$ } from "../controls";
|
||||
import { useUrlParams } from "../UrlParams";
|
||||
|
||||
// This hardcoded id is used in EX ios! It can only be changed in coordination with
|
||||
@@ -81,13 +81,9 @@ export interface MediaDevices extends Omit<InputDevices, "usingNames"> {
|
||||
* - hide any input devices (they do not work anyhow on ios)
|
||||
* - Show a button to show the native output picker instead.
|
||||
* - Only show the earpiece toggle option if the earpiece is available:
|
||||
* `setAvailableOutputDevices$.includes((d)=>d.forEarpiece)`
|
||||
* `availableOutputDevices$.includes((d)=>d.forEarpiece)`
|
||||
*/
|
||||
export const iosDeviceMenu$ = alwaysShowIphoneEarpieceSetting.value$.pipe(
|
||||
startWith(
|
||||
alwaysShowIphoneEarpieceSetting.getValue() ||
|
||||
navigator.userAgent.includes("iPhone"),
|
||||
),
|
||||
map((v) => v || navigator.userAgent.includes("iPhone")),
|
||||
);
|
||||
|
||||
@@ -115,8 +111,8 @@ function useSelectedId(
|
||||
/**
|
||||
* Hook to get access to a mediaDevice handle for a kind. This allows to list
|
||||
* the available devices, read and set the selected device.
|
||||
* @param kind audio input, output or video output.
|
||||
* @param setting The setting this handles selection should be synced with.
|
||||
* @param kind Audio input, output or video output.
|
||||
* @param setting The setting this handle's selection should be synced with.
|
||||
* @param usingNames If the hook should query device names for the associated
|
||||
* list.
|
||||
* @returns A handle for the chosen kind.
|
||||
@@ -320,7 +316,7 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
|
||||
function useControlledOutput(): MediaDeviceHandle {
|
||||
const { available } = useObservableEagerState(
|
||||
useObservable(() => {
|
||||
const outputDeviceData$ = setAvailableOutputDevices$.pipe(
|
||||
const outputDeviceData$ = availableOutputDevices$.pipe(
|
||||
map((devices) => {
|
||||
const deviceForEarpiece = devices.find((d) => d.forEarpiece);
|
||||
const deviceMapTuple: [string, DeviceLabel][] = devices.map(
|
||||
@@ -339,8 +335,9 @@ function useControlledOutput(): MediaDeviceHandle {
|
||||
}),
|
||||
);
|
||||
|
||||
return combineLatest([outputDeviceData$, iosDeviceMenu$]).pipe(
|
||||
map(([{ devicesMap, deviceForEarpiece }, iosShowEarpiece]) => {
|
||||
return combineLatest(
|
||||
[outputDeviceData$, iosDeviceMenu$],
|
||||
({ devicesMap, deviceForEarpiece }, iosShowEarpiece) => {
|
||||
let available = devicesMap;
|
||||
if (iosShowEarpiece && !!deviceForEarpiece) {
|
||||
available = new Map([
|
||||
@@ -349,15 +346,16 @@ function useControlledOutput(): MediaDeviceHandle {
|
||||
]);
|
||||
}
|
||||
return { available, deviceForEarpiece };
|
||||
}),
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
const [preferredId, setPreferredId] = useSetting(audioOutputSetting);
|
||||
useEffect(() => {
|
||||
setOutputDevice$.subscribe((id) => {
|
||||
const subscription = outputDevice$.subscribe((id) => {
|
||||
if (id) setPreferredId(id);
|
||||
});
|
||||
return (): void => subscription.unsubscribe();
|
||||
}, [setPreferredId]);
|
||||
|
||||
const selectedId = useSelectedId(available, preferredId);
|
||||
@@ -365,9 +363,10 @@ function useControlledOutput(): MediaDeviceHandle {
|
||||
const [asEarpiece, setAsEarpiece] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// In earpiece mode we just sent the EARPIECE_CONFIG_ID to the native code
|
||||
// This only happens on ios where we use the native picker.
|
||||
// So this only is needed so that ios can know if the proximity sensor should be used or not.
|
||||
// Let the hosting application know which output device has been selected.
|
||||
// This information is probably only of interest if the earpiece mode has been
|
||||
// selected - for example, Element X iOS listens to this to determine whether it
|
||||
// should enable the proximity sensor.
|
||||
if (selectedId) window.controls.onOutputDeviceSelect?.(selectedId);
|
||||
setAsEarpiece(selectedId === EARPIECE_CONFIG_ID);
|
||||
}, [selectedId]);
|
||||
|
||||
@@ -104,7 +104,7 @@ export const SettingsModal: FC<Props> = ({
|
||||
const [showDeveloperSettingsTab] = useSetting(developerMode);
|
||||
|
||||
const { available: isRageshakeAvailable } = useSubmitRageshake();
|
||||
// If we are on ios we will show a button to open the native picker.
|
||||
// If we are on iOS we will show a button to open the native audio device picker.
|
||||
const iosDeviceMenu = useObservableEagerState(iosDeviceMenu$);
|
||||
// In controlled devices we will not show the input section
|
||||
const { controlledMediaDevices } = useUrlParams();
|
||||
|
||||
@@ -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 { combineLatest, map, startWith } from "rxjs";
|
||||
import { combineLatest, startWith } from "rxjs";
|
||||
|
||||
import { setOutputEnabled$ } from "../controls";
|
||||
import { muteAllAudio as muteAllAudioSetting } from "../settings/settings";
|
||||
@@ -13,10 +13,7 @@ import { muteAllAudio as muteAllAudioSetting } from "../settings/settings";
|
||||
/**
|
||||
* This can transition into sth more complete: `GroupCallViewModel.ts`
|
||||
*/
|
||||
export const muteAllAudio$ = combineLatest([
|
||||
setOutputEnabled$,
|
||||
muteAllAudioSetting.value$,
|
||||
]).pipe(
|
||||
startWith([true, muteAllAudioSetting.getValue()]),
|
||||
map(([outputEnabled, settingsMute]) => !outputEnabled || settingsMute),
|
||||
export const muteAllAudio$ = combineLatest(
|
||||
[setOutputEnabled$.pipe(startWith(true)), muteAllAudioSetting.value$],
|
||||
(outputEnabled, settingsMute) => !outputEnabled || settingsMute,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user