mirror of
https://github.com/vector-im/element-call.git
synced 2026-03-31 07:00:26 +00:00
Add support for playing a sound when the user exits a call.
This commit is contained in:
@@ -42,6 +42,9 @@ import { useUrlParams } from "../UrlParams";
|
||||
import { E2eeType } from "../e2ee/e2eeType";
|
||||
import { Link } from "../button/Link";
|
||||
|
||||
import leftCallSoundMp3 from "../sound/left_call.mp3";
|
||||
import leftCallSoundOgg from "../sound/left_call.ogg";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
rtcSession?: MatrixRTCSession;
|
||||
@@ -72,6 +75,22 @@ export const GroupCallView: FC<Props> = ({
|
||||
const memberships = useMatrixRTCSessionMemberships(rtcSession);
|
||||
const isJoined = useMatrixRTCSessionJoinState(rtcSession);
|
||||
|
||||
// Only used in widget mode.
|
||||
const leaveSound = useRef<HTMLAudioElement|null>(null);
|
||||
const playLeaveSound = useCallback(async () => {
|
||||
if (!leaveSound.current) {
|
||||
return;
|
||||
}
|
||||
const ended = new Promise<void>(r => {
|
||||
leaveSound.current?.addEventListener("ended", () => r());
|
||||
});
|
||||
console.log('Playing');
|
||||
await leaveSound.current.play();
|
||||
console.log('started playing');
|
||||
await ended;
|
||||
console.log('ended');
|
||||
}, [leaveSound]);
|
||||
|
||||
// This should use `useEffectEvent` (only available in experimental versions)
|
||||
useEffect(() => {
|
||||
if (memberships.length >= MUTE_PARTICIPANT_COUNT)
|
||||
@@ -214,12 +233,11 @@ export const GroupCallView: FC<Props> = ({
|
||||
|
||||
const onLeave = useCallback(
|
||||
(leaveError?: Error): void => {
|
||||
setLeaveError(leaveError);
|
||||
setLeft(true);
|
||||
|
||||
// In embedded/widget mode the iFrame will be killed right after the call ended prohibiting the posthog event from getting sent,
|
||||
// therefore we want the event to be sent instantly without getting queued/batched.
|
||||
const sendInstantly = !!widget;
|
||||
console.log('hangup!', sendInstantly);
|
||||
setLeaveError(leaveError);
|
||||
PosthogAnalytics.instance.eventCallEnded.track(
|
||||
rtcSession.room.roomId,
|
||||
rtcSession.memberships.length,
|
||||
@@ -227,20 +245,22 @@ export const GroupCallView: FC<Props> = ({
|
||||
rtcSession,
|
||||
);
|
||||
|
||||
// Wait for the sound in widget mode (it's not long)
|
||||
leaveRTCSession(rtcSession, sendInstantly ? playLeaveSound() : undefined)
|
||||
// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts.
|
||||
leaveRTCSession(rtcSession)
|
||||
.then(() => {
|
||||
if (
|
||||
!isPasswordlessUser &&
|
||||
!confineToRoom &&
|
||||
!PosthogAnalytics.instance.isEnabled()
|
||||
) {
|
||||
history.push("/");
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
logger.error("Error leaving RTC session", e);
|
||||
});
|
||||
.then(() => {
|
||||
setLeft(true);
|
||||
if (
|
||||
!isPasswordlessUser &&
|
||||
!confineToRoom &&
|
||||
!PosthogAnalytics.instance.isEnabled()
|
||||
) {
|
||||
history.push("/");
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
logger.error("Error leaving RTC session", e);
|
||||
});
|
||||
},
|
||||
[rtcSession, isPasswordlessUser, confineToRoom, history],
|
||||
);
|
||||
@@ -308,6 +328,14 @@ export const GroupCallView: FC<Props> = ({
|
||||
onDismiss={onDismissInviteModal}
|
||||
/>
|
||||
);
|
||||
const callEndedAudio = <audio
|
||||
ref={leaveSound}
|
||||
preload="auto"
|
||||
hidden
|
||||
>
|
||||
<source src={leftCallSoundOgg} type="audio/ogg; codecs=vorbis" />
|
||||
<source src={leftCallSoundMp3} type="audio/mpeg" />
|
||||
</audio>;
|
||||
const lobbyView = (
|
||||
<>
|
||||
{shareModal}
|
||||
@@ -321,6 +349,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
participantCount={participantCount}
|
||||
onShareClick={onShareClick}
|
||||
/>
|
||||
{callEndedAudio}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -340,6 +369,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
//otelGroupCallMembership={otelGroupCallMembership}
|
||||
onShareClick={onShareClick}
|
||||
/>
|
||||
{callEndedAudio}
|
||||
</>
|
||||
);
|
||||
} else if (left && widget === null) {
|
||||
@@ -357,14 +387,22 @@ export const GroupCallView: FC<Props> = ({
|
||||
leaveError
|
||||
) {
|
||||
return (
|
||||
<CallEndedView
|
||||
endedCallId={rtcSession.room.roomId}
|
||||
client={client}
|
||||
isPasswordlessUser={isPasswordlessUser}
|
||||
confineToRoom={confineToRoom}
|
||||
leaveError={leaveError}
|
||||
reconnect={onReconnect}
|
||||
/>
|
||||
<>
|
||||
<CallEndedView
|
||||
endedCallId={rtcSession.room.roomId}
|
||||
client={client}
|
||||
isPasswordlessUser={isPasswordlessUser}
|
||||
confineToRoom={confineToRoom}
|
||||
leaveError={leaveError}
|
||||
reconnect={onReconnect}
|
||||
/><audio
|
||||
autoPlay
|
||||
hidden
|
||||
>
|
||||
<source src={leftCallSoundOgg} type="audio/ogg; codecs=vorbis" />
|
||||
<source src={leftCallSoundMp3} type="audio/mpeg" />
|
||||
</audio>;
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
// If the user is a regular user, we'll have sent them back to the homepage,
|
||||
@@ -375,7 +413,7 @@ export const GroupCallView: FC<Props> = ({
|
||||
} else if (left && widget !== null) {
|
||||
// Left in widget mode:
|
||||
if (!returnToLobby) {
|
||||
return null;
|
||||
return callEndedAudio;
|
||||
}
|
||||
} else if (preload || skipLobby) {
|
||||
return null;
|
||||
|
||||
@@ -120,6 +120,7 @@ export async function enterRTCSession(
|
||||
|
||||
const widgetPostHangupProcedure = async (
|
||||
widget: WidgetHelpers,
|
||||
promiseBeforeHangup?: Promise<unknown>,
|
||||
): Promise<void> => {
|
||||
// we need to wait until the callEnded event is tracked on posthog.
|
||||
// Otherwise the iFrame gets killed before the callEnded event got tracked.
|
||||
@@ -132,6 +133,8 @@ const widgetPostHangupProcedure = async (
|
||||
logger.error("Failed to set call widget `alwaysOnScreen` to false", e);
|
||||
}
|
||||
|
||||
// Wait for any last bits before hanging up.
|
||||
await promiseBeforeHangup;
|
||||
// We send the hangup event after the memberships have been updated
|
||||
// calling leaveRTCSession.
|
||||
// We need to wait because this makes the client hosting this widget killing the IFrame.
|
||||
@@ -140,9 +143,12 @@ const widgetPostHangupProcedure = async (
|
||||
|
||||
export async function leaveRTCSession(
|
||||
rtcSession: MatrixRTCSession,
|
||||
promiseBeforeHangup?: Promise<unknown>,
|
||||
): Promise<void> {
|
||||
await rtcSession.leaveRoomSession();
|
||||
if (widget) {
|
||||
await widgetPostHangupProcedure(widget);
|
||||
await widgetPostHangupProcedure(widget, promiseBeforeHangup);
|
||||
} else {
|
||||
await promiseBeforeHangup;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user