diff --git a/src/otel/OTelCall.ts b/src/otel/OTelCall.ts new file mode 100644 index 0000000..3717abf --- /dev/null +++ b/src/otel/OTelCall.ts @@ -0,0 +1,103 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Span } from "@opentelemetry/api"; +import { MatrixCall } from "matrix-js-sdk"; +import { CallEvent } from "matrix-js-sdk/src/webrtc/call"; + +import { ObjectFlattener } from "./ObjectFlattener"; + +/** + * Tracks an individual call within a group call, either to a full-mesh peer or a focus + */ +export class OTelCall { + constructor( + public userId: string, + public deviceId: string, + public call: MatrixCall, + public span: Span + ) { + if (call.peerConn) { + this.addCallPeerConnListeners(); + } else { + this.call.once( + CallEvent.PeerConnectionCreated, + this.addCallPeerConnListeners + ); + } + } + + public dispose() { + this.call.peerConn.removeEventListener( + "iceconnectionstatechange", + this.onIceConnectionStateChanged + ); + } + + private addCallPeerConnListeners = (): void => { + this.call.peerConn.addEventListener( + "connectionstatechange", + this.onCallConnectionStateChanged + ); + this.call.peerConn.addEventListener( + "signalingstatechange", + this.onCallSignalingStateChanged + ); + this.call.peerConn.addEventListener( + "iceconnectionstatechange", + this.onIceConnectionStateChanged + ); + this.call.peerConn.addEventListener( + "icegatheringstatechange", + this.onIceGatheringStateChanged + ); + this.call.peerConn.addEventListener( + "icecandidateerror", + this.onIceCandidateError + ); + }; + + public onCallConnectionStateChanged = (): void => { + this.span.addEvent("matrix.call.callConnectionStateChange", { + callConnectionState: this.call.peerConn.connectionState, + }); + }; + + public onCallSignalingStateChanged = (): void => { + this.span.addEvent("matrix.call.callSignalingStateChange", { + callSignalingState: this.call.peerConn.signalingState, + }); + }; + + public onIceConnectionStateChanged = (): void => { + this.span.addEvent("matrix.call.iceConnectionStateChange", { + iceConnectionState: this.call.peerConn.iceConnectionState, + }); + }; + + public onIceGatheringStateChanged = (): void => { + this.span.addEvent("matrix.call.iceGatheringStateChange", { + iceGatheringState: this.call.peerConn.iceGatheringState, + }); + }; + + public onIceCandidateError = (ev: Event): void => { + const flatObject = {}; + ObjectFlattener.flattenObjectRecursive(ev, flatObject, "error.", 0); + + this.span.addEvent("matrix.call.iceCandidateError", flatObject); + }; +} diff --git a/src/otel/OTelGroupCallMembership.ts b/src/otel/OTelGroupCallMembership.ts index 45d5bfd..6d3d3b7 100644 --- a/src/otel/OTelGroupCallMembership.ts +++ b/src/otel/OTelGroupCallMembership.ts @@ -43,6 +43,7 @@ import { setSpan } from "@opentelemetry/api/build/esm/trace/context-utils"; import { ElementCallOpenTelemetry } from "./otel"; import { ObjectFlattener } from "./ObjectFlattener"; +import { OTelCall } from "./OTelCall"; /** * Flattens out an object into a single layer with components @@ -86,13 +87,6 @@ function flattenVoipEventRecursive( } } -interface CallTrackingInfo { - userId: string; - deviceId: string; - call: MatrixCall; - span: Span; -} - /** * Represent the span of time which we intend to be joined to a group call */ @@ -102,7 +96,7 @@ export class OTelGroupCallMembership { private myUserId = "unknown"; private myDeviceId: string; private myMember?: RoomMember; - private callsByCallId = new Map(); + private callsByCallId = new Map(); private statsReportSpan: { span: Span | undefined; stats: OTelStatsReportEvent[]; @@ -188,12 +182,10 @@ export class OTelGroupCallMembership { // XXX: anonymity span.setAttribute("matrix.call.target.userId", userId); span.setAttribute("matrix.call.target.deviceId", deviceId); - this.callsByCallId.set(call.callId, { - userId, - deviceId, - call, - span, - }); + this.callsByCallId.set( + call.callId, + new OTelCall(userId, deviceId, call, span) + ); } } }