Always ask for permission and dont rerequest devices if permissions change

This commit is contained in:
Timo
2025-06-04 14:21:56 +02:00
parent a08efde3c6
commit 6000b9590e
2 changed files with 6 additions and 66 deletions

View File

@@ -66,9 +66,6 @@ export interface MediaDeviceHandle {
interface InputDevices { interface InputDevices {
audioInput: MediaDeviceHandle; audioInput: MediaDeviceHandle;
videoInput: MediaDeviceHandle; videoInput: MediaDeviceHandle;
startUsingDeviceNames: () => void;
stopUsingDeviceNames: () => void;
usingNames: boolean;
} }
export interface MediaDevices extends Omit<InputDevices, "usingNames"> { export interface MediaDevices extends Omit<InputDevices, "usingNames"> {
@@ -120,14 +117,7 @@ function useSelectedId(
function useMediaDeviceHandle( function useMediaDeviceHandle(
kind: MediaDeviceKind, kind: MediaDeviceKind,
setting: Setting<string | undefined>, setting: Setting<string | undefined>,
usingNames: boolean,
): MediaDeviceHandle { ): MediaDeviceHandle {
const hasRequestedPermissions = useRef(false);
const requestPermissions = usingNames || hasRequestedPermissions.current;
// Make sure we don't needlessly reset to a device observer without names,
// once permissions are already given
hasRequestedPermissions.current ||= usingNames;
// We use a bare device observer here rather than one of the fancy device // We use a bare device observer here rather than one of the fancy device
// selection hooks from @livekit/components-react, because // selection hooks from @livekit/components-react, because
// useMediaDeviceSelect expects a room or track, which we don't have here, and // useMediaDeviceSelect expects a room or track, which we don't have here, and
@@ -136,10 +126,8 @@ function useMediaDeviceHandle(
// kind, which then results in multiple permissions requests. // kind, which then results in multiple permissions requests.
const deviceObserver$ = useMemo( const deviceObserver$ = useMemo(
() => () =>
createMediaDeviceObserver( createMediaDeviceObserver(kind, () =>
kind, logger.error("Error creating MediaDeviceObserver"),
() => logger.error("Error creating MediaDeviceObserver"),
requestPermissions,
).pipe( ).pipe(
startWith(undefined, []), startWith(undefined, []),
// Convert to a tuple of previous and next value. // Convert to a tuple of previous and next value.
@@ -163,7 +151,7 @@ function useMediaDeviceHandle(
// Use startWith at the end to ensure that the observable // Use startWith at the end to ensure that the observable
// always emits an initial value that does not get filtered out. // always emits an initial value that does not get filtered out.
), ),
[kind, requestPermissions], [kind],
); );
const available = useObservableEagerState( const available = useObservableEagerState(
@@ -253,43 +241,19 @@ export const devicesStub: MediaDevices = {
audioInput: deviceStub, audioInput: deviceStub,
audioOutput: deviceStub, audioOutput: deviceStub,
videoInput: deviceStub, videoInput: deviceStub,
startUsingDeviceNames: () => {},
stopUsingDeviceNames: () => {},
}; };
export const MediaDevicesContext = createContext<MediaDevices>(devicesStub); export const MediaDevicesContext = createContext<MediaDevices>(devicesStub);
function useInputDevices(): InputDevices { function useInputDevices(): InputDevices {
// Counts the number of callers currently using device names. // Counts the number of callers currently using device names.
const [numCallersUsingNames, setNumCallersUsingNames] = useState(0);
const usingNames = numCallersUsingNames > 0;
const audioInput = useMediaDeviceHandle( const audioInput = useMediaDeviceHandle("audioinput", audioInputSetting);
"audioinput", const videoInput = useMediaDeviceHandle("videoinput", videoInputSetting);
audioInputSetting,
usingNames,
);
const videoInput = useMediaDeviceHandle(
"videoinput",
videoInputSetting,
usingNames,
);
const startUsingDeviceNames = useCallback(
() => setNumCallersUsingNames((n) => n + 1),
[setNumCallersUsingNames],
);
const stopUsingDeviceNames = useCallback(
() => setNumCallersUsingNames((n) => n - 1),
[setNumCallersUsingNames],
);
return { return {
audioInput, audioInput,
videoInput, videoInput,
startUsingDeviceNames,
stopUsingDeviceNames,
usingNames,
}; };
} }
@@ -298,20 +262,13 @@ interface Props {
} }
export const MediaDevicesProvider: FC<Props> = ({ children }) => { export const MediaDevicesProvider: FC<Props> = ({ children }) => {
const { const { audioInput, videoInput } = useInputDevices();
audioInput,
videoInput,
startUsingDeviceNames,
stopUsingDeviceNames,
usingNames,
} = useInputDevices();
const { controlledAudioDevices } = useUrlParams(); const { controlledAudioDevices } = useUrlParams();
const webViewAudioOutput = useMediaDeviceHandle( const webViewAudioOutput = useMediaDeviceHandle(
"audiooutput", "audiooutput",
audioOutputSetting, audioOutputSetting,
usingNames,
); );
const controlledAudioOutput = useControlledOutput(); const controlledAudioOutput = useControlledOutput();
@@ -322,8 +279,6 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
? controlledAudioOutput ? controlledAudioOutput
: webViewAudioOutput, : webViewAudioOutput,
videoInput, videoInput,
startUsingDeviceNames,
stopUsingDeviceNames,
}), }),
[ [
audioInput, audioInput,
@@ -331,8 +286,6 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
controlledAudioOutput, controlledAudioOutput,
webViewAudioOutput, webViewAudioOutput,
videoInput, videoInput,
startUsingDeviceNames,
stopUsingDeviceNames,
], ],
); );
@@ -426,17 +379,6 @@ export const useMediaDevices = (): MediaDevices =>
* default because it may involve requesting additional permissions from the * default because it may involve requesting additional permissions from the
* user. * user.
*/ */
export const useMediaDeviceNames = (
context: MediaDevices,
enabled = true,
): void =>
useEffect(() => {
// if (enabled) {
// context.startUsingDeviceNames();
// return context.stopUsingDeviceNames;
// }
}, [context, enabled]);
/** /**
* 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

View File

@@ -19,7 +19,6 @@ import { ProfileSettingsTab } from "./ProfileSettingsTab";
import { FeedbackSettingsTab } from "./FeedbackSettingsTab"; import { FeedbackSettingsTab } from "./FeedbackSettingsTab";
import { import {
useMediaDevices, useMediaDevices,
useMediaDeviceNames,
iosDeviceMenu$, iosDeviceMenu$,
} from "../livekit/MediaDevicesContext"; } from "../livekit/MediaDevicesContext";
import { widget } from "../widget"; import { widget } from "../widget";
@@ -98,7 +97,6 @@ export const SettingsModal: FC<Props> = ({
}; };
const devices = useMediaDevices(); const devices = useMediaDevices();
useMediaDeviceNames(devices, open);
const [soundVolume, setSoundVolume] = useSetting(soundEffectVolumeSetting); const [soundVolume, setSoundVolume] = useSetting(soundEffectVolumeSetting);
const [soundVolumeRaw, setSoundVolumeRaw] = useState(soundVolume); const [soundVolumeRaw, setSoundVolumeRaw] = useState(soundVolume);
const [showDeveloperSettingsTab] = useSetting(developerMode); const [showDeveloperSettingsTab] = useSetting(developerMode);