diff --git a/src/api/SignalClient.ts b/src/api/SignalClient.ts index 13b9a4c000..93f1995faa 100644 --- a/src/api/SignalClient.ts +++ b/src/api/SignalClient.ts @@ -1,6 +1,9 @@ import { AddTrackRequest, ClientInfo, + ClientMetrics, + ClientMetrics_ConnectionError, + ClientMetrics_ConnectionTime, ConnectionQualityUpdate, DisconnectReason, JoinResponse, @@ -566,6 +569,42 @@ export class SignalClient { }); } + sendConnectionError(error: ConnectionError) { + return this.sendRequest({ + case: 'clientMetrics', + value: new ClientMetrics({ + message: { + case: 'connectionError', + value: new ClientMetrics_ConnectionError({ + message: error.message, + timestamp: protoInt64.parse(Date.now()), + code: error.code, + }), + }, + }), + }); + } + + sendConnectionTimes({ + signal, + publisher, + subscriber, + }: { + signal?: number; + publisher?: number; + subscriber?: number; + }) { + return this.sendRequest({ + case: 'clientMetrics', + value: new ClientMetrics({ + message: { + case: 'connectionTime', + value: new ClientMetrics_ConnectionTime({ signal, publisher, subscriber }), + }, + }), + }); + } + sendPing() { /** send both of ping and pingReq for compatibility to old and new server */ return Promise.all([ diff --git a/src/room/Room.ts b/src/room/Room.ts index 8ac45dd4dd..d52ed2a313 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -440,7 +440,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) unlockDisconnect(); return this.connectFuture.promise; } - + const connectStartTime = performance.now(); this.setAndEmitConnectionState(ConnectionState.Connecting); if (this.regionUrlProvider?.getServerUrl().toString() !== url) { this.regionUrl = undefined; @@ -643,6 +643,8 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.engine.peerConnectionTimeout = this.connOptions.peerConnectionTimeout; } + const connectStart = performance.now(); + try { const joinResponse = await this.connectSignal( url, @@ -681,17 +683,25 @@ class Room extends (EventEmitter as new () => TypedEmitter) throw new ConnectionError(`Connection attempt aborted`); } + const signalConnectTime = performance.now() - connectStart; + try { await this.engine.waitForPCInitialConnection( this.connOptions.peerConnectionTimeout, abortController, ); } catch (e) { + if (e instanceof Error) { + await this.engine.client.sendConnectionError(new ConnectionError(e.message)); + } + await this.engine.close(); this.recreateEngine(); throw e; } + const pcConnectTime = performance.now() - signalConnectTime; + // also hook unload event if (isWeb() && this.options.disconnectOnPageLeave) { // capturing both 'pagehide' and 'beforeunload' to capture broadest set of browser behaviors @@ -705,6 +715,10 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.setAndEmitConnectionState(ConnectionState.Connected); this.emit(RoomEvent.Connected); this.registerConnectionReconcile(); + await this.engine.client.sendConnectionTimes({ + signal: signalConnectTime, + subscriber: pcConnectTime, + }); }; /**