mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-27 19:29:19 +00:00
Refactor disconnection handling
This commit is contained in:
@@ -17,7 +17,7 @@ import { act, render, type RenderResult } from "@testing-library/react";
|
|||||||
import { type MatrixClient, JoinRule, type RoomState } from "matrix-js-sdk";
|
import { type MatrixClient, JoinRule, type RoomState } from "matrix-js-sdk";
|
||||||
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
|
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
|
||||||
import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container";
|
import { type RelationsContainer } from "matrix-js-sdk/lib/models/relations-container";
|
||||||
import { ConnectionState, type LocalParticipant } from "livekit-client";
|
import { type LocalParticipant } from "livekit-client";
|
||||||
import { of } from "rxjs";
|
import { of } from "rxjs";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import { TooltipProvider } from "@vector-im/compound-web";
|
import { TooltipProvider } from "@vector-im/compound-web";
|
||||||
@@ -180,7 +180,6 @@ function createInCallView(): RenderResult & {
|
|||||||
onLeave={function (): void {
|
onLeave={function (): void {
|
||||||
throw new Error("Function not implemented.");
|
throw new Error("Function not implemented.");
|
||||||
}}
|
}}
|
||||||
connState={ConnectionState.Connected}
|
|
||||||
onShareClick={null}
|
onShareClick={null}
|
||||||
/>
|
/>
|
||||||
</RoomContext>
|
</RoomContext>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Please see LICENSE in the repository root for full details.
|
|||||||
|
|
||||||
import { RoomContext, useLocalParticipant } from "@livekit/components-react";
|
import { RoomContext, useLocalParticipant } from "@livekit/components-react";
|
||||||
import { IconButton, Text, Tooltip } from "@vector-im/compound-web";
|
import { IconButton, Text, Tooltip } from "@vector-im/compound-web";
|
||||||
import { ConnectionState, type Room as LivekitRoom } from "livekit-client";
|
import { type Room as LivekitRoom } from "livekit-client";
|
||||||
import { type MatrixClient, type Room as MatrixRoom } from "matrix-js-sdk";
|
import { type MatrixClient, type Room as MatrixRoom } from "matrix-js-sdk";
|
||||||
import {
|
import {
|
||||||
type FC,
|
type FC,
|
||||||
@@ -63,7 +63,6 @@ import { type MuteStates } from "./MuteStates";
|
|||||||
import { type MatrixInfo } from "./VideoPreview";
|
import { type MatrixInfo } from "./VideoPreview";
|
||||||
import { InviteButton } from "../button/InviteButton";
|
import { InviteButton } from "../button/InviteButton";
|
||||||
import { LayoutToggle } from "./LayoutToggle";
|
import { LayoutToggle } from "./LayoutToggle";
|
||||||
import { type ECConnectionState } from "../livekit/useECConnectionState";
|
|
||||||
import { useOpenIDSFU } from "../livekit/openIDSFU";
|
import { useOpenIDSFU } from "../livekit/openIDSFU";
|
||||||
import {
|
import {
|
||||||
CallViewModel,
|
CallViewModel,
|
||||||
@@ -212,12 +211,7 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<RoomContext value={livekitRoom}>
|
<RoomContext value={livekitRoom}>
|
||||||
<ReactionsSenderProvider vm={vm} rtcSession={props.rtcSession}>
|
<ReactionsSenderProvider vm={vm} rtcSession={props.rtcSession}>
|
||||||
<InCallView
|
<InCallView {...props} vm={vm} livekitRoom={livekitRoom} />
|
||||||
{...props}
|
|
||||||
vm={vm}
|
|
||||||
livekitRoom={livekitRoom}
|
|
||||||
connState={connState}
|
|
||||||
/>
|
|
||||||
</ReactionsSenderProvider>
|
</ReactionsSenderProvider>
|
||||||
</RoomContext>
|
</RoomContext>
|
||||||
);
|
);
|
||||||
@@ -235,7 +229,6 @@ export interface InCallViewProps {
|
|||||||
onLeave: (cause: "user", soundFile?: CallEventSounds) => void;
|
onLeave: (cause: "user", soundFile?: CallEventSounds) => void;
|
||||||
header: HeaderStyle;
|
header: HeaderStyle;
|
||||||
otelGroupCallMembership?: OTelGroupCallMembership;
|
otelGroupCallMembership?: OTelGroupCallMembership;
|
||||||
connState: ECConnectionState;
|
|
||||||
onShareClick: (() => void) | null;
|
onShareClick: (() => void) | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +242,6 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
muteStates,
|
muteStates,
|
||||||
onLeave,
|
onLeave,
|
||||||
header: headerStyle,
|
header: headerStyle,
|
||||||
connState,
|
|
||||||
onShareClick,
|
onShareClick,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -257,11 +249,11 @@ export const InCallView: FC<InCallViewProps> = ({
|
|||||||
useReactionsSender();
|
useReactionsSender();
|
||||||
|
|
||||||
useWakeLock();
|
useWakeLock();
|
||||||
|
const isDisconnected = useBehavior(vm.livekitDisconnected$);
|
||||||
|
|
||||||
// annoyingly we don't get the disconnection reason this way,
|
// annoyingly we don't get the disconnection reason this way,
|
||||||
// only by listening for the emitted event
|
// only by listening for the emitted event
|
||||||
if (connState === ConnectionState.Disconnected)
|
if (isDisconnected) throw new ConnectionLostError();
|
||||||
throw new ConnectionLostError();
|
|
||||||
|
|
||||||
const containerRef1 = useRef<HTMLDivElement | null>(null);
|
const containerRef1 = useRef<HTMLDivElement | null>(null);
|
||||||
const [containerRef2, bounds] = useMeasure();
|
const [containerRef2, bounds] = useMeasure();
|
||||||
|
|||||||
@@ -465,6 +465,14 @@ export class CallViewModel extends ViewModel {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public readonly livekitDisconnected$ = this.scope.behavior(
|
||||||
|
and$(
|
||||||
|
this.livekitConnectionState$.pipe(
|
||||||
|
map((state) => state === ConnectionState.Disconnected),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
private readonly connected$ = this.scope.behavior(
|
private readonly connected$ = this.scope.behavior(
|
||||||
and$(
|
and$(
|
||||||
this.matrixConnected$,
|
this.matrixConnected$,
|
||||||
@@ -957,15 +965,19 @@ export class CallViewModel extends ViewModel {
|
|||||||
"unknown" | "ringing" | "timeout" | "decline" | "success" | null
|
"unknown" | "ringing" | "timeout" | "decline" | "success" | null
|
||||||
> = this.options.waitForCallPickup
|
> = this.options.waitForCallPickup
|
||||||
? this.scope.behavior<
|
? this.scope.behavior<
|
||||||
"unknown" | "ringing" | "timeout" | "decline" | "success"
|
"unknown" | "ringing" | "timeout" | "decline" | "success" | null
|
||||||
>(
|
>(
|
||||||
this.someoneElseJoined$.pipe(
|
combineLatest(this.livekitDisconnected$, this.someoneElseJoined$).pipe(
|
||||||
switchMap((someoneElseJoined) =>
|
switchMap(([isDisconnected, someoneElseJoined]) => {
|
||||||
someoneElseJoined
|
if (isDisconnected) {
|
||||||
? of("success" as const)
|
// Do not ring until we're connected.
|
||||||
: // Show the ringing state of the most recent ringing attempt.
|
return of(null);
|
||||||
this.ring$.pipe(switchAll()),
|
} else if (someoneElseJoined) {
|
||||||
),
|
of("success" as const);
|
||||||
|
}
|
||||||
|
// Show the ringing state of the most recent ringing attempt.
|
||||||
|
return this.ring$.pipe(switchAll());
|
||||||
|
}),
|
||||||
// The state starts as 'unknown' because we don't know if the RTC
|
// The state starts as 'unknown' because we don't know if the RTC
|
||||||
// session will actually send a notify event yet. It will only be
|
// session will actually send a notify event yet. It will only be
|
||||||
// known once we send our own membership and see that we were the
|
// known once we send our own membership and see that we were the
|
||||||
|
|||||||
Reference in New Issue
Block a user