fix logic for earpiece quick switcher to be based on switching target

(also show quick switcher if headphones are connected)
This commit is contained in:
Timo
2025-06-25 17:43:59 +02:00
parent a98ced3e5b
commit 2207e6ac21
2 changed files with 39 additions and 33 deletions

View File

@@ -312,7 +312,7 @@ export const InCallView: FC<InCallViewProps> = ({
const showHeader = useObservableEagerState(vm.showHeader$); const showHeader = useObservableEagerState(vm.showHeader$);
const showFooter = useObservableEagerState(vm.showFooter$); const showFooter = useObservableEagerState(vm.showFooter$);
const earpieceMode = useObservableEagerState(vm.earpieceMode$); const earpieceMode = useObservableEagerState(vm.earpieceMode$);
const toggleEarpieceMode = useObservableEagerState(vm.toggleEarpieceMode$); const audioOutputSwitcher = useObservableEagerState(vm.audioOutputSwitcher$);
const switchCamera = useSwitchCamera(vm.localVideo$); const switchCamera = useSwitchCamera(vm.localVideo$);
// Ideally we could detect taps by listening for click events and checking // Ideally we could detect taps by listening for click events and checking
@@ -457,27 +457,26 @@ export const InCallView: FC<InCallViewProps> = ({
useAppBarSecondaryButton( useAppBarSecondaryButton(
useMemo(() => { useMemo(() => {
if (toggleEarpieceMode === null) return null; if (audioOutputSwitcher === null) return null;
const Icon = earpieceMode ? VolumeOnSolidIcon : EarpieceIcon; const isEarpieceTarget = audioOutputSwitcher.targetOutput === "earpiece";
const Icon = isEarpieceTarget ? EarpieceIcon : VolumeOnSolidIcon;
const label = isEarpieceTarget
? t("settings.devices.earpiece")
: t("settings.devices.loudspeaker");
return ( return (
<Tooltip <Tooltip label={label}>
label={
earpieceMode
? t("settings.devices.earpiece")
: t("settings.devices.loudspeaker")
}
>
<IconButton <IconButton
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
toggleEarpieceMode(); audioOutputSwitcher.switch();
}} }}
> >
<Icon /> <Icon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
); );
}, [t, earpieceMode, toggleEarpieceMode]), }, [t, audioOutputSwitcher]),
); );
useAppBarHidden(!showHeader); useAppBarHidden(!showHeader);
@@ -789,7 +788,7 @@ export const InCallView: FC<InCallViewProps> = ({
<ReactionsAudioRenderer vm={vm} muted={muteAllAudio} /> <ReactionsAudioRenderer vm={vm} muted={muteAllAudio} />
<EarpieceOverlay <EarpieceOverlay
show={earpieceMode} show={earpieceMode}
onBackToVideoPressed={toggleEarpieceMode} onBackToVideoPressed={audioOutputSwitcher?.switch}
/> />
<ReactionsOverlay vm={vm} /> <ReactionsOverlay vm={vm} />
{footer} {footer}

View File

@@ -1261,29 +1261,36 @@ export class CallViewModel extends ViewModel {
/** /**
* Callback to toggle between the earpiece and the loudspeaker. * Callback to toggle between the earpiece and the loudspeaker.
*
* This will be `null` in case the target does not exist in the list
* of available audio outputs.
*/ */
public readonly toggleEarpieceMode$: Observable<(() => void) | null> = public readonly audioOutputSwitcher$: Observable<{
combineLatest( targetOutput: "earpiece" | "speaker";
[ switch: () => void;
this.mediaDevices.audioOutput.available$, } | null> = combineLatest(
this.mediaDevices.audioOutput.selected$, [
], this.mediaDevices.audioOutput.available$,
(available, selected) => { this.mediaDevices.audioOutput.selected$,
const selectionType = selected && available.get(selected.id)?.type; ],
if (!(selectionType === "speaker" || selectionType === "earpiece")) (available, selected) => {
return null; const selectionType = selected && available.get(selected.id)?.type;
const newSelectionType = // If we are in any output mode other than spaeker switch to speaker.
selectionType === "speaker" ? "earpiece" : "speaker"; const newSelectionType =
const newSelection = [...available].find( selectionType === "speaker" ? "earpiece" : "speaker";
([, d]) => d.type === newSelectionType, const newSelection = [...available].find(
); ([, d]) => d.type === newSelectionType,
if (newSelection === undefined) return null; );
if (newSelection === undefined) return null;
const [id] = newSelection; const [id] = newSelection;
return () => this.mediaDevices.audioOutput.select(id); return {
}, targetOutput: newSelectionType,
); switch: () => this.mediaDevices.audioOutput.select(id),
};
},
);
public readonly reactions$ = this.reactionsSubject$.pipe( public readonly reactions$ = this.reactionsSubject$.pipe(
map((v) => map((v) =>