/* Copyright 2023, 2024 New Vector Ltd. SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ import opentelemetry, { Span } from "@opentelemetry/api"; import { TrackStats } from "matrix-js-sdk/src/webrtc/stats/statsReport"; import { ElementCallOpenTelemetry } from "./otel"; import { OTelCallMediaStreamTrackSpan } from "./OTelCallMediaStreamTrackSpan"; type TrackId = string; export abstract class OTelCallAbstractMediaStreamSpan { protected readonly trackSpans = new Map< TrackId, OTelCallMediaStreamTrackSpan >(); public readonly span; public constructor( protected readonly oTel: ElementCallOpenTelemetry, protected readonly callSpan: Span, protected readonly type: string, ) { const ctx = opentelemetry.trace.setSpan( opentelemetry.context.active(), callSpan, ); const options = { links: [ { context: callSpan.spanContext(), }, ], }; this.span = oTel.tracer.startSpan(this.type, options, ctx); } protected upsertTrackSpans(tracks: TrackStats[]): void { let prvTracks: TrackId[] = [...this.trackSpans.keys()]; tracks.forEach((t) => { if (!this.trackSpans.has(t.id)) { this.trackSpans.set( t.id, new OTelCallMediaStreamTrackSpan(this.oTel, this.span, t), ); } this.trackSpans.get(t.id)?.update(t); prvTracks = prvTracks.filter((prvTrackId) => prvTrackId !== t.id); }); prvTracks.forEach((prvTrackId) => { this.trackSpans.get(prvTrackId)?.end(); this.trackSpans.delete(prvTrackId); }); } public abstract update(data: object): void; public end(): void { this.trackSpans.forEach((tSpan) => { tSpan.end(); }); this.span.end(); } }