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

View File

@@ -1261,29 +1261,36 @@ export class CallViewModel extends ViewModel {
/**
* 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> =
combineLatest(
[
this.mediaDevices.audioOutput.available$,
this.mediaDevices.audioOutput.selected$,
],
(available, selected) => {
const selectionType = selected && available.get(selected.id)?.type;
if (!(selectionType === "speaker" || selectionType === "earpiece"))
return null;
public readonly audioOutputSwitcher$: Observable<{
targetOutput: "earpiece" | "speaker";
switch: () => void;
} | null> = combineLatest(
[
this.mediaDevices.audioOutput.available$,
this.mediaDevices.audioOutput.selected$,
],
(available, selected) => {
const selectionType = selected && available.get(selected.id)?.type;
const newSelectionType =
selectionType === "speaker" ? "earpiece" : "speaker";
const newSelection = [...available].find(
([, d]) => d.type === newSelectionType,
);
if (newSelection === undefined) return null;
// If we are in any output mode other than spaeker switch to speaker.
const newSelectionType =
selectionType === "speaker" ? "earpiece" : "speaker";
const newSelection = [...available].find(
([, d]) => d.type === newSelectionType,
);
if (newSelection === undefined) return null;
const [id] = newSelection;
return () => this.mediaDevices.audioOutput.select(id);
},
);
const [id] = newSelection;
return {
targetOutput: newSelectionType,
switch: () => this.mediaDevices.audioOutput.select(id),
};
},
);
public readonly reactions$ = this.reactionsSubject$.pipe(
map((v) =>