From b380532d3080275388810ec124d578dd57a787b5 Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 10 Dec 2025 21:14:13 +0100 Subject: [PATCH] lots of error logging and fixing playwright --- src/room/GroupCallView.tsx | 1 + src/room/InCallView.tsx | 7 ++++++- src/room/LobbyView.tsx | 4 ++-- src/state/CallViewModel/CallViewModel.ts | 15 +++++++++++++- .../CallViewModel/localMember/LocalMember.ts | 20 +++++++++++++------ .../localMember/LocalTransport.ts | 2 +- .../CallViewModel/remoteMembers/Connection.ts | 14 +++++++++---- 7 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index dfd11ff3..1542678e 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -446,6 +446,7 @@ export const GroupCallView: FC = ({ let body: ReactNode; if (externalError) { + logger.debug("External error occurred:", externalError); // If an error was recorded within this component but outside // GroupCallErrorBoundary, create a component that rethrows the error from // within the error boundary, so it can be handled uniformly diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 7ae3700c..18acf843 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -127,6 +127,7 @@ export const ActiveCall: FC = (props) => { const mediaDevices = useMediaDevices(); const trackProcessorState$ = useTrackProcessorObservable$(); useEffect(() => { + logger.info("START CALL VIEW SCOPE"); const scope = new ObservableScope(); const reactionsReader = new ReactionsReader(scope, props.rtcSession); const { autoLeaveWhenOthersLeft, waitForCallPickup, sendNotificationType } = @@ -153,6 +154,7 @@ export const ActiveCall: FC = (props) => { vm.leave$.pipe(scope.bind()).subscribe(props.onLeft); return (): void => { + logger.info("END CALL VIEW SCOPE"); scope.end(); }; }, [ @@ -271,7 +273,10 @@ export const InCallView: FC = ({ const ringOverlay = useBehavior(vm.ringOverlay$); const fatalCallError = useBehavior(vm.fatalError$); // Stop the rendering and throw for the error boundary - if (fatalCallError) throw fatalCallError; + if (fatalCallError) { + logger.debug("fatalCallError stop rendering", fatalCallError); + throw fatalCallError; + } // We need to set the proper timings on the animation based upon the sound length. const ringDuration = pickupPhaseAudio?.soundDuration["waiting"] ?? 1; diff --git a/src/room/LobbyView.tsx b/src/room/LobbyView.tsx index ad4f30b3..10e098f1 100644 --- a/src/room/LobbyView.tsx +++ b/src/room/LobbyView.tsx @@ -79,9 +79,9 @@ export const LobbyView: FC = ({ waitingForInvite, }) => { useEffect(() => { - logger.info("[Lifecycle] GroupCallView Component mounted"); + logger.info("[Lifecycle] LobbyView Component mounted"); return (): void => { - logger.info("[Lifecycle] GroupCallView Component unmounted"); + logger.info("[Lifecycle] LobbyView Component unmounted"); }; }, []); diff --git a/src/state/CallViewModel/CallViewModel.ts b/src/state/CallViewModel/CallViewModel.ts index 35ab658b..6a9eadea 100644 --- a/src/state/CallViewModel/CallViewModel.ts +++ b/src/state/CallViewModel/CallViewModel.ts @@ -15,6 +15,7 @@ import { } from "livekit-client"; import { type Room as MatrixRoom } from "matrix-js-sdk"; import { + catchError, combineLatest, distinctUntilChanged, filter, @@ -425,7 +426,18 @@ export function createCallViewModel$( connectionFactory: connectionFactory, inputTransports$: scope.behavior( combineLatest( - [localTransport$, membershipsAndTransports.transports$], + [ + localTransport$.pipe( + catchError((e) => { + logger.info( + "dont pass local transport to createConnectionManager$. localTransport$ threw an error", + e, + ); + return of(null); + }), + ), + membershipsAndTransports.transports$, + ], (localTransport, transports) => { const localTransportAsArray = localTransport ? [localTransport] : []; return transports.mapInner((transports) => [ @@ -1461,6 +1473,7 @@ export function createCallViewModel$( fatalError$: scope.behavior( errors$.pipe( map((errors) => { + logger.debug("errors$ to compute any fatal errors:", errors); return ( errors?.transportError ?? errors?.matrixError ?? diff --git a/src/state/CallViewModel/localMember/LocalMember.ts b/src/state/CallViewModel/localMember/LocalMember.ts index 73908fcb..40fb62d6 100644 --- a/src/state/CallViewModel/localMember/LocalMember.ts +++ b/src/state/CallViewModel/localMember/LocalMember.ts @@ -324,17 +324,23 @@ export const createLocalMembership$ = ({ // These are non fatal since we can join a room and concume media even though publishing failed. const publishError$ = new BehaviorSubject(null); const setPublishError = (e: ElementCallError): void => { - if (publishError$.value !== null) logger.error("Multiple Media Errors:", e); - else publishError$.next(e); + if (publishError$.value !== null) { + logger.error("Multiple Media Errors:", e); + } else { + publishError$.next(e); + } }; const fatalTransportError$ = new BehaviorSubject( null, ); + const setTransportError = (e: ElementCallError): void => { - if (fatalTransportError$.value !== null) + if (fatalTransportError$.value !== null) { logger.error("Multiple Transport Errors:", e); - else fatalTransportError$.next(e); + } else { + fatalTransportError$.next(e); + } }; const localConnectionState$ = localConnection$.pipe( @@ -386,9 +392,11 @@ export const createLocalMembership$ = ({ ); const fatalMatrixError$ = new BehaviorSubject(null); const setMatrixError = (e: ElementCallError): void => { - if (fatalMatrixError$.value !== null) + if (fatalMatrixError$.value !== null) { logger.error("Multiple Matrix Errors:", e); - else fatalMatrixError$.next(e); + } else { + fatalMatrixError$.next(e); + } }; const localMemberState$ = scope.behavior( diff --git a/src/state/CallViewModel/localMember/LocalTransport.ts b/src/state/CallViewModel/localMember/LocalTransport.ts index 0a85bbc1..1320b8c4 100644 --- a/src/state/CallViewModel/localMember/LocalTransport.ts +++ b/src/state/CallViewModel/localMember/LocalTransport.ts @@ -85,7 +85,7 @@ export const createLocalTransport$ = ({ * The transport that we would personally prefer to publish on (if not for the * transport preferences of others, perhaps). * - * @throws + * @throws MatrixRTCTransportMissingError | FailToGetOpenIdToken */ const preferredTransport$: Behavior = scope.behavior( customLivekitUrl.value$.pipe( diff --git a/src/state/CallViewModel/remoteMembers/Connection.ts b/src/state/CallViewModel/remoteMembers/Connection.ts index 2fd9eaa8..c801b3ae 100644 --- a/src/state/CallViewModel/remoteMembers/Connection.ts +++ b/src/state/CallViewModel/remoteMembers/Connection.ts @@ -29,8 +29,10 @@ import { import { type Behavior } from "../../Behavior.ts"; import { type ObservableScope } from "../../ObservableScope.ts"; import { + ElementCallError, InsufficientCapacityError, SFURoomCreationRestrictedError, + UnknownCallError, } from "../../../utils/errors.ts"; export type PublishingParticipant = LocalParticipant | RemoteParticipant; @@ -79,9 +81,9 @@ export enum ConnectionState { */ export class Connection { // Private Behavior - private readonly _state$ = new BehaviorSubject( - ConnectionState.Initialized, - ); + private readonly _state$ = new BehaviorSubject< + ConnectionState | ElementCallError + >(ConnectionState.Initialized); /** * The current state of the connection to the media transport. @@ -131,6 +133,8 @@ export class Connection { this.stopped = false; try { this._state$.next(ConnectionState.FetchingConfig); + // We should already have this information after creating the localTransport. + // It would probably be better to forward this here. const { url, jwt } = await this.getSFUConfigWithOpenID(); // If we were stopped while fetching the config, don't proceed to connect if (this.stopped) return; @@ -172,7 +176,9 @@ export class Connection { }); } catch (error) { this.logger.debug(`Failed to connect to LiveKit room: ${error}`); - this._state$.next(error instanceof Error ? error : new Error(`${error}`)); + this._state$.next( + error instanceof ElementCallError ? error : new UnknownCallError(error), + ); // Its okay to ignore the throw. The error is part of the state. throw error; }