Make camera unavailable if using earpice mode (#3351)
This commit is contained in:
@@ -23,6 +23,14 @@ export function useMediaDevices(): MediaDevices {
|
|||||||
return mediaDevices;
|
return mediaDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useIsEarpiece = (): boolean => {
|
||||||
|
const devices = useMediaDevices();
|
||||||
|
const audioOutput = useObservableEagerState(devices.audioOutput.selected$);
|
||||||
|
const available = useObservableEagerState(devices.audioOutput.available$);
|
||||||
|
if (!audioOutput?.id) return false;
|
||||||
|
return available.get(audioOutput.id)?.type === "earpiece";
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience hook to get the audio node configuration for the earpiece.
|
* A convenience hook to get the audio node configuration for the earpiece.
|
||||||
* It will check the `useAsEarpiece` of the `audioOutput` device and return
|
* It will check the `useAsEarpiece` of the `audioOutput` device and return
|
||||||
@@ -36,17 +44,13 @@ export const useEarpieceAudioConfig = (): {
|
|||||||
} => {
|
} => {
|
||||||
const devices = useMediaDevices();
|
const devices = useMediaDevices();
|
||||||
const audioOutput = useObservableEagerState(devices.audioOutput.selected$);
|
const audioOutput = useObservableEagerState(devices.audioOutput.selected$);
|
||||||
// We use only the right speaker (pan = 1) for the earpiece.
|
const isVirtualEarpiece = audioOutput?.virtualEarpiece ?? false;
|
||||||
// This mimics the behavior of the native earpiece speaker (only the top speaker on an iPhone)
|
return {
|
||||||
const pan = useMemo(
|
// We use only the right speaker (pan = 1) for the earpiece.
|
||||||
() => (audioOutput?.virtualEarpiece ? 1 : 0),
|
// This mimics the behavior of the native earpiece speaker (only the top speaker on an iPhone)
|
||||||
[audioOutput?.virtualEarpiece],
|
pan: useMemo(() => (isVirtualEarpiece ? 1 : 0), [isVirtualEarpiece]),
|
||||||
);
|
// We also do lower the volume by a factor of 10 to optimize for the usecase where
|
||||||
// We also do lower the volume by a factor of 10 to optimize for the usecase where
|
// a user is holding the phone to their ear.
|
||||||
// a user is holding the phone to their ear.
|
volume: useMemo(() => (isVirtualEarpiece ? 0.1 : 1), [isVirtualEarpiece]),
|
||||||
const volume = useMemo(
|
};
|
||||||
() => (audioOutput?.virtualEarpiece ? 0.1 : 1),
|
|
||||||
[audioOutput?.virtualEarpiece],
|
|
||||||
);
|
|
||||||
return { pan, volume };
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
type SelectedDevice,
|
type SelectedDevice,
|
||||||
type MediaDevice,
|
type MediaDevice,
|
||||||
} from "../state/MediaDevices";
|
} from "../state/MediaDevices";
|
||||||
import { useMediaDevices } from "../MediaDevicesContext";
|
import { useIsEarpiece, useMediaDevices } from "../MediaDevicesContext";
|
||||||
import { useReactiveState } from "../useReactiveState";
|
import { useReactiveState } from "../useReactiveState";
|
||||||
import { ElementWidgetActions, widget } from "../widget";
|
import { ElementWidgetActions, widget } from "../widget";
|
||||||
import { Config } from "../config/Config";
|
import { Config } from "../config/Config";
|
||||||
@@ -58,6 +58,7 @@ export interface MuteStates {
|
|||||||
function useMuteState(
|
function useMuteState(
|
||||||
device: MediaDevice<DeviceLabel, SelectedDevice>,
|
device: MediaDevice<DeviceLabel, SelectedDevice>,
|
||||||
enabledByDefault: () => boolean,
|
enabledByDefault: () => boolean,
|
||||||
|
forceUnavailable: boolean = false,
|
||||||
): MuteState {
|
): MuteState {
|
||||||
const available = useObservableEagerState(device.available$);
|
const available = useObservableEagerState(device.available$);
|
||||||
const [enabled, setEnabled] = useReactiveState<boolean | undefined>(
|
const [enabled, setEnabled] = useReactiveState<boolean | undefined>(
|
||||||
@@ -67,13 +68,13 @@ function useMuteState(
|
|||||||
);
|
);
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
available.size === 0
|
available.size === 0 || forceUnavailable
|
||||||
? deviceUnavailable
|
? deviceUnavailable
|
||||||
: {
|
: {
|
||||||
enabled: enabled ?? false,
|
enabled: enabled ?? false,
|
||||||
setEnabled: setEnabled as Dispatch<SetStateAction<boolean>>,
|
setEnabled: setEnabled as Dispatch<SetStateAction<boolean>>,
|
||||||
},
|
},
|
||||||
[available.size, enabled, setEnabled],
|
[available.size, enabled, forceUnavailable, setEnabled],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,9 +86,11 @@ export function useMuteStates(isJoined: boolean): MuteStates {
|
|||||||
const audio = useMuteState(devices.audioInput, () => {
|
const audio = useMuteState(devices.audioInput, () => {
|
||||||
return Config.get().media_devices.enable_audio && !skipLobby && !isJoined;
|
return Config.get().media_devices.enable_audio && !skipLobby && !isJoined;
|
||||||
});
|
});
|
||||||
|
const isEarpiece = useIsEarpiece();
|
||||||
const video = useMuteState(
|
const video = useMuteState(
|
||||||
devices.videoInput,
|
devices.videoInput,
|
||||||
() => Config.get().media_devices.enable_video && !skipLobby && !isJoined,
|
() => Config.get().media_devices.enable_video && !skipLobby && !isJoined,
|
||||||
|
isEarpiece, // Force video to be unavailable if using earpiece
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user