diff --git a/.changeset/wicked-frogs-beg.md b/.changeset/wicked-frogs-beg.md new file mode 100644 index 0000000000..ebd378c0bc --- /dev/null +++ b/.changeset/wicked-frogs-beg.md @@ -0,0 +1,5 @@ +--- +"livekit-client": patch +--- + +Forward disconnect reason on leave requests and ConnectionErrors diff --git a/src/api/SignalClient.ts b/src/api/SignalClient.ts index 0bcc8a4b11..8992f3519e 100644 --- a/src/api/SignalClient.ts +++ b/src/api/SignalClient.ts @@ -394,6 +394,8 @@ export class SignalClient { new ConnectionError( 'Received leave request while trying to (re)connect', ConnectionErrorReason.LeaveRequest, + undefined, + resp.message.value.reason, ), ); } else if (!opts.reconnect) { diff --git a/src/room/Room.ts b/src/room/Room.ts index 6baa880f9d..ce9e7235c1 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -81,6 +81,7 @@ import { createDummyVideoStreamTrack, extractChatMessage, extractTranscriptionSegments, + getDisconnectReasonFromConnectionError, getEmptyAudioStreamTrack, isBrowserSupported, isCloud, @@ -562,11 +563,18 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.recreateEngine(); await connectFn(resolve, reject, nextUrl); } else { - this.handleDisconnect(this.options.stopLocalTrackOnUnpublish); + this.handleDisconnect( + this.options.stopLocalTrackOnUnpublish, + getDisconnectReasonFromConnectionError(e), + ); reject(e); } } else { - this.handleDisconnect(this.options.stopLocalTrackOnUnpublish); + let disconnectReason = DisconnectReason.UNKNOWN_REASON; + if (e instanceof ConnectionError) { + disconnectReason = getDisconnectReasonFromConnectionError(e); + } + this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, disconnectReason); reject(e); } } diff --git a/src/room/errors.ts b/src/room/errors.ts index 80f39c7f90..14bb30d92e 100644 --- a/src/room/errors.ts +++ b/src/room/errors.ts @@ -1,4 +1,4 @@ -import { RequestResponse_Reason } from '@livekit/protocol'; +import { DisconnectReason, RequestResponse_Reason } from '@livekit/protocol'; export class LivekitError extends Error { code: number; @@ -20,12 +20,20 @@ export const enum ConnectionErrorReason { export class ConnectionError extends LivekitError { status?: number; + context?: unknown | DisconnectReason; + reason: ConnectionErrorReason; - constructor(message: string, reason: ConnectionErrorReason, status?: number) { + constructor( + message: string, + reason: ConnectionErrorReason, + status?: number, + context?: unknown | DisconnectReason, + ) { super(1, message); this.status = status; this.reason = reason; + this.context = context; } } diff --git a/src/room/utils.ts b/src/room/utils.ts index 7fbb9e3246..3b8c427310 100644 --- a/src/room/utils.ts +++ b/src/room/utils.ts @@ -2,10 +2,12 @@ import { ChatMessage as ChatMessageModel, ClientInfo, ClientInfo_SDK, + DisconnectReason, Transcription as TranscriptionModel, } from '@livekit/protocol'; import { getBrowser } from '../utils/browserParser'; import { protocolVersion, version } from '../version'; +import { type ConnectionError, ConnectionErrorReason } from './errors'; import CriticalTimers from './timers'; import type LocalAudioTrack from './track/LocalAudioTrack'; import type RemoteAudioTrack from './track/RemoteAudioTrack'; @@ -531,3 +533,18 @@ export function extractChatMessage(msg: ChatMessageModel): ChatMessage { message, }; } + +export function getDisconnectReasonFromConnectionError(e: ConnectionError) { + switch (e.reason) { + case ConnectionErrorReason.LeaveRequest: + return e.context as DisconnectReason; + case ConnectionErrorReason.Cancelled: + return DisconnectReason.CLIENT_INITIATED; + case ConnectionErrorReason.NotAllowed: + return DisconnectReason.USER_REJECTED; + case ConnectionErrorReason.ServerUnreachable: + return DisconnectReason.JOIN_FAILURE; + default: + return DisconnectReason.UNKNOWN_REASON; + } +}