@observertc/observer-js 1.0.0-beta.13 → 1.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/common/logger.ts","../src/ObservedCall.ts","../src/ObservedClient.ts","../src/ObservedPeerConnection.ts","../src/ObservedInboundRtp.ts","../src/ObservedOutboundRtp.ts","../src/ObservedCertificate.ts","../src/ObservedCodec.ts","../src/ObservedDataChannel.ts","../src/ObservedIceCandidate.ts","../src/ObservedIceCandidatePair.ts","../src/ObservedIceTransport.ts","../src/ObservedMediaSource.ts","../src/ObservedPeerConnectionTransport.ts","../src/ObservedMediaPlayout.ts","../src/ObservedRemoteInboundRtp.ts","../src/ObservedRemoteOutboundRtp.ts","../src/ObservedInboundTrack.ts","../src/ObservedOutboundTrack.ts","../src/common/utils.ts","../src/schema/ClientEventTypes.ts","../src/schema/ClientMetaTypes.ts","../src/scores/DefaultCallScoreCalculator.ts","../src/updaters/OnAllClientCallUpdater.ts","../src/updaters/OnAnyClientCallUpdater.ts","../src/detectors/Detectors.ts","../src/Observer.ts","../src/ObservedTURN.ts","../src/ObservedTurnServer.ts","../src/updaters/OnAllCallObserverUpdater.ts","../src/updaters/OnAnyCallObserverUpdater.ts","../src/common/Middleware.ts","../src/ObservedMediasoupRouter.ts","../src/sinks/ClientSampleSink.ts","../src/sinks/JsonlFileSink.ts","../src/sinks/InMemorySink.ts","../src/utils/RemoteTrackResolver.ts","../src/utils/RemoteTrackResolverFactories.ts"],"sourcesContent":["export type { ObserverEvents, SampleRejectedReason, AcceptContext, CallAppDataFactory, ClientAppDataFactory, AcceptMiddleware, AcceptMiddlewarePayload } from './Observer';\nexport type {\n\tObserverEventBase,\n\tObservedCallScope,\n\tObservedClientScope,\n\tObservedPeerConnectionScope,\n\tObservedMediasoupRouterScope,\n} from './ObserverEvents';\nexport type { ObservedMediasoupRouterSettings, ObservedMediasoupRouterEvents } from './ObservedMediasoupRouter';\nexport type {\n\tMediasoupRouterSample,\n\tMediasoupTransportSample,\n\tMediasoupProducerSample,\n\tMediasoupConsumerSample,\n\tMediasoupDataProducerSample,\n\tMediasoupDataConsumerSample,\n\tMediasoupWebRtcTransportSample,\n\tMediasoupPlainTransportSample,\n\tMediasoupPipeTransportSample,\n\tMediasoupDirectTransportSample,\n\tMediasoupWebRtcTransportSampleEventMap,\n\tMediasoupPlainTransportSampleEventMap,\n\tMediasoupPipeTransportSampleEventMap,\n\tMediasoupDirectTransportSampleEventMap,\n\tMediasoupProducerSampleEvent,\n\tMediasoupConsumerSampleEvent,\n} from './schema/MediasoupRouter';\n\nexport { Observer } from './Observer';\nexport { ObservedCall } from './ObservedCall';\nexport { ObservedInboundTrack } from './ObservedInboundTrack';\nexport { ObservedOutboundTrack } from './ObservedOutboundTrack';\nexport { ObservedClient } from './ObservedClient';\nexport { ObservedPeerConnection } from './ObservedPeerConnection';\nexport { ObservedMediaSource } from './ObservedMediaSource';\nexport { ObservedMediaPlayout } from './ObservedMediaPlayout';\nexport { ObservedCodec } from './ObservedCodec';\nexport { ObservedCertificate } from './ObservedCertificate';\nexport { ObservedDataChannel } from './ObservedDataChannel';\nexport { ObservedInboundRtp } from './ObservedInboundRtp';\nexport { ObservedOutboundRtp } from './ObservedOutboundRtp';\nexport { ObservedRemoteInboundRtp } from './ObservedRemoteInboundRtp';\nexport { ObservedRemoteOutboundRtp } from './ObservedRemoteOutboundRtp';\nexport { ObservedMediasoupRouter } from './ObservedMediasoupRouter';\nexport { ObservedIceCandidatePair } from './ObservedIceCandidatePair';\nexport { ObservedIceCandidate } from './ObservedIceCandidate';\nexport { ObservedIceTransport } from './ObservedIceTransport';\nexport { ObservedPeerConnectionTransport } from './ObservedPeerConnectionTransport';\nexport { ClientEventTypes } from './schema/ClientEventTypes';\nexport { ClientMetaTypes } from './schema/ClientMetaTypes';\nexport { ClientSample, ClientIssue, ClientEvent, ClientMetaData } from './schema/ClientSample';\nexport { ScoreCalculator } from './scores/ScoreCalculator';\nexport { Detectors } from './detectors/Detectors';\nexport type { Detector } from './detectors/Detector';\nexport { createLogger, setObserverLogger } from './common/logger';\nexport type { Logger, ObserverLogger } from './common/logger';\n// Per-client sample sinks. `ClientSampleSink` is the base class to subclass for a custom\n// destination; `JsonlFileSink` / `InMemorySink` are the built-ins.\nexport {\n\tClientSampleSink,\n\tJsonlFileSink,\n\tcreateJsonlFileSink,\n\tcreateJsonlFileSinkFactory,\n\tInMemorySink,\n\tcreateInMemorySink,\n} from './sinks';\nexport type {\n\tClientSampleSinkEvents,\n\tClientSampleSinkFactory,\n\tJsonlFileSinkOptions,\n\tJsonlFileSinkFactoryOptions,\n} from './sinks';\nexport { Middleware } from './common/Middleware';\n// Remote track correlation: the generic resolver + built-in strategy factories.\nexport { RemoteTrackResolver } from './utils/RemoteTrackResolver';\nexport type { RemoteTrackResolvers, RemoteTrackResolverFactory } from './utils/RemoteTrackResolver';\nexport {\n\tcreateDefaultMediasoupRemoteTrackResolverFactory,\n\tcreateP2pRemoteTrackResolverFactory,\n} from './utils/RemoteTrackResolverFactories';\n","export interface Logger {\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\ttrace(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tdebug(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tinfo(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\twarn(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\terror(...args: any[]): void;\n}\n\nexport interface ObserverLogger {\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\ttrace(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tdebug(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tinfo(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\twarn(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\terror(module: string, ...args: any[]): void;\n}\n\nlet mainLogger: ObserverLogger = new class implements ObserverLogger {\n\ttrace = () => void 0;\n\t// trace(module: string, ...args: any[]) {\n\t// \t// eslint-disable-next-line no-console\n\t// \tconsole.log(`[TRACE] ${module}`, ...args);\n\t// }\n\n\tdebug(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(`[DEBUG] ${module}`, ...args);\n\t}\n\n\tinfo(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.info(`[INFO] ${module}`, ...args);\n\t}\n\n\twarn(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(`[WARN] ${module}`, ...args);\n\t}\n\n\terror(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(`[ERROR] ${module}`, ...args);\n\t}\n}();\n\nexport function createLogger(moduleName: string): Logger {\n\treturn new class implements Logger {\n\t\ttrace(...args: any[]) {\n\t\t\tmainLogger.trace(moduleName, ...args);\n\t\t}\n\n\t\tdebug(...args: any[]) {\n\t\t\tmainLogger.debug(moduleName, ...args);\n\t\t}\n\n\t\tinfo(...args: any[]) {\n\t\t\tmainLogger.info(moduleName, ...args);\n\t\t}\n\n\t\twarn(...args: any[]) {\n\t\t\tmainLogger.warn(moduleName, ...args);\n\t\t}\n\n\t\terror(...args: any[]) {\n\t\t\tmainLogger.error(moduleName, ...args);\n\t\t}\n\n\t}();\n}\n\nexport function setObserverLogger(logger: ObserverLogger) {\n\tmainLogger = logger;\n}\n","import { EventEmitter } from 'events';\nimport { createLogger } from './common/logger';\nimport { ObservedClient, ObservedClientSettings } from './ObservedClient';\nimport { Observer } from './Observer';\nimport { ScoreCalculator } from './scores/ScoreCalculator';\nimport { CalculatedScore } from './scores/CalculatedScore';\nimport { DefaultCallScoreCalculator } from './scores/DefaultCallScoreCalculator';\nimport { RemoteTrackResolver } from './utils/RemoteTrackResolver';\nimport { OnAllClientCallUpdater } from './updaters/OnAllClientCallUpdater';\nimport { Updater } from './updaters/Updater';\nimport { OnAnyClientCallUpdater } from './updaters/OnAnyClientCallUpdater';\nimport { Detectors } from './detectors/Detectors';\nimport { ClientIssue } from './schema/ClientSample';\nimport type { AcceptContext } from './Observer';\nimport type { ObserverEvents, ObservedCallScope } from './ObserverEvents';\n\nconst logger = createLogger('ObservedCall');\n\n// Updates are event-driven: triggered when any/all clients in the call have updated. `'none'`\n// disables the automatic trigger — the application must call `call.update()` itself.\n// (Apps wanting a fixed cadence can call `call.update()` on their own timer.)\ntype ObservedCallUpdateConfig = {\n\tupdatePolicy?: 'update-on-any-client-updated' | 'update-when-all-client-updated' | 'none',\n};\n\nexport type ObservedCallSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = ObservedCallUpdateConfig & {\n\tcallId: string;\n\tappData?: AppData;\n\tcloseCallIfEmptyForMs?: number,\n};\n\nexport type ObservedCallEvents = {\n\tupdate: [],\n\tnewclient: [ObservedClient],\n\tempty: [],\n\t'not-empty': [],\n\tclose: [],\n}\n\nexport declare interface ObservedCall {\n\ton<U extends keyof ObservedCallEvents>(event: U, listener: (...args: ObservedCallEvents[U]) => void): this;\n\toff<U extends keyof ObservedCallEvents>(event: U, listener: (...args: ObservedCallEvents[U]) => void): this;\n\tonce<U extends keyof ObservedCallEvents>(event: U, listener: (...args: ObservedCallEvents[U]) => void): this;\n\temit<U extends keyof ObservedCallEvents>(event: U, ...args: ObservedCallEvents[U]): boolean;\n}\n\nexport class ObservedCall<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic updater?: Updater;\n\tpublic scoreCalculator: ScoreCalculator;\n\tpublic readonly detectors: Detectors;\n\tpublic readonly callId: string;\n\tpublic readonly observedClients = new Map<string, ObservedClient>();\n\tpublic readonly clientsUsedTurn = new Set<string>();\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\tpublic remoteTrackResolver?: RemoteTrackResolver;\n\n\tpublic totalAddedClients = 0;\n\tpublic totalRemovedClients = 0;\n\n\tpublic numberOfIssues = 0;\n\tpublic numberOfPeerConnections = 0;\n\tpublic numberOfInboundRtpStreams = 0;\n\tpublic numberOfOutboundRtpStreams = 0;\n\tpublic numberOfDataChannels = 0;\n\n\tpublic maxNumberOfClients = 0;\n\tpublic deltaNumberOfIssues = 0;\n\n\t// public deltaRttLt50Measurements = 0;\n\t// public deltaRttLt150Measurements = 0;\n\t// public deltaRttLt300Measurements = 0;\n\t// public deltaRttGtOrEq300Measurements = 0;\n\n\tpublic appData: AppData;\n\tpublic closed = false;\n\tpublic startedAt?: number;\n\tpublic endedAt?: number;\n\tpublic closedAt?: number;\n\n\tpublic readonly settings: Pick<ObservedCallSettings, 'closeCallIfEmptyForMs'>;\n\n\t/** Ancestry base shared by all Observer-bus events originating at this call. */\n\tpublic readonly eventScope: ObservedCallScope;\n\tprivate closeTimer?: ReturnType<typeof setTimeout>;\n\n\tpublic constructor(\n\t\tsettings: ObservedCallSettings<AppData>,\n\t\tpublic readonly observer: Observer,\n\t) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\n\t\tthis.eventScope = { observer: this.observer, observedCall: this };\n\t\tthis.callId = settings.callId;\n\t\tthis.appData = (settings.appData ?? {}) as AppData;\n\t\tthis.scoreCalculator = new DefaultCallScoreCalculator(this);\n\t\t// No built-in detectors ship yet. The registry is a server-side extension point:\n\t\t// add custom call-level Detectors via `call.detectors.add(...)` and surface findings\n\t\t// with `call.addIssue(...)` (emitted on the Observer bus as `call-issue`).\n\t\tthis.detectors = new Detectors();\n\n\t\tswitch (settings.updatePolicy) {\n\t\t\tcase 'update-on-any-client-updated':\n\t\t\t\tthis.updater = new OnAnyClientCallUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'update-when-all-client-updated':\n\t\t\t\tthis.updater = new OnAllClientCallUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'none':\n\t\t\t\t// No automatic updater: `call.update()` only runs when the app calls it.\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis.settings = {\n\t\t\tcloseCallIfEmptyForMs: settings.closeCallIfEmptyForMs,\n\t\t};\n\t}\n\n\tpublic get numberOfClients() {\n\t\treturn this.observedClients.size;\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\t/** Raise a call-level (server-side) issue; surfaced on the Observer bus as `call-issue`. */\n\tpublic addIssue(issue: ClientIssue) {\n\t\tif (this.closed) return;\n\n\t\tthis._notify('call-issue', { ...this.eventScope, issue });\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\t\tthis.update(); // last update before closing\n\t\tthis.closed = true;\n\n\t\tthis.updater?.close();\n\n\t\tlet minSampleTimestamps: number | undefined;\n\t\tlet maxSampleTimestamps: number | undefined;\n\n\t\tfor (const client of this.observedClients.values()) {\n\t\t\tclient.close();\n\n\t\t\tif (client.joinedAt) minSampleTimestamps = Math.min(minSampleTimestamps ?? client.joinedAt, client.joinedAt);\n\t\t\tif (client.leftAt) maxSampleTimestamps = Math.max(maxSampleTimestamps ?? client.leftAt, client.leftAt);\n\t\t}\n\n\t\tif (this.startedAt === undefined) this.startedAt = minSampleTimestamps;\n\t\tif (this.endedAt === undefined) this.endedAt = maxSampleTimestamps;\n\n\t\tthis.closedAt = Date.now();\n\t\tthis.emit('close');\n\t\tthis._notify('call-closed', { ...this.eventScope });\n\t}\n\n\tpublic getObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(clientId: string): ObservedClient<ClientAppData> | undefined {\n\t\tif (this.closed || !this.observedClients.has(clientId)) return;\n\n\t\treturn this.observedClients.get(clientId) as ObservedClient<ClientAppData>;\n\t}\n\n\tpublic createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>): ObservedClient<ClientAppData> | undefined {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to create a client (clientId: %s) on a closed call %s', settings.clientId, this.callId);\n\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this.observedClients.has(settings.clientId)) {\n\t\t\tlogger.warn('Client with id %s already exists in call %s; returning the existing instance', settings.clientId, this.callId);\n\n\t\t\treturn this.observedClients.get(settings.clientId) as ObservedClient<ClientAppData>;\n\t\t}\n\n\t\tif (!settings.closeClientIfIdleForMs) {\n\t\t\tsettings.closeClientIfIdleForMs = this.observer.config.closeClientIfIdleForMs;\n\t\t}\n\t\tif (settings.appData === undefined) {\n\t\t\tsettings.appData = this.observer.config.createClientAppData?.({ clientId: settings.clientId, observedCall: this }) as ClientAppData;\n\t\t}\n\n\t\tconst result = new ObservedClient<ClientAppData>(settings, this);\n\t\tconst wasEmpty = this.observedClients.size === 0;\n\t\tconst onUpdate = () => this._onClientUpdate(result);\n\t\tconst joined = () => this._clientJoined(result);\n\t\tconst left = () => this._clientLeft(result);\n\n\t\tresult.once('close', () => {\n\t\t\tresult.off('update', onUpdate);\n\t\t\tresult.off('joined', joined);\n\t\t\tresult.off('left', left);\n\t\t\tthis.observedClients.delete(settings.clientId);\n\n\t\t\tif (this.observedClients.size === 0) {\n\t\t\t\tthis.emit('empty');\n\t\t\t\tthis._notify('call-empty', { ...this.eventScope });\n\n\t\t\t\tif (this.settings.closeCallIfEmptyForMs) {\n\t\t\t\t\tthis.closeTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.close();\n\t\t\t\t\t}, this.settings.closeCallIfEmptyForMs);\n\t\t\t\t}\n\t\t\t}\n\t\t\t++this.totalRemovedClients;\n\t\t});\n\t\tresult.on('update', onUpdate);\n\t\tresult.on('joined', joined);\n\t\tresult.on('left', left);\n\t\t++this.totalAddedClients;\n\n\t\tthis.observedClients.set(settings.clientId, result);\n\t\tthis.maxNumberOfClients = Math.max(this.maxNumberOfClients, this.observedClients.size);\n\n\t\tif (this.closeTimer) {\n\t\t\tclearTimeout(this.closeTimer);\n\t\t\tthis.closeTimer = undefined;\n\t\t}\n\n\t\tthis.emit('newclient', result);\n\t\tthis._notify('client-added', { ...this.eventScope, observedClient: result });\n\n\t\tif (result.sink) {\n\t\t\tthis._notify('client-sink-created', { ...this.eventScope, observedClient: result, sink: result.sink });\n\t\t}\n\n\t\tif (wasEmpty) {\n\t\t\tthis.emit('not-empty');\n\t\t\tthis._notify('call-not-empty', { ...this.eventScope });\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic getOrCreateObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedClientSettings<ClientAppData>\n\t): ObservedClient<ClientAppData> | undefined {\n\t\treturn this.getObservedClient<ClientAppData>(settings.clientId) ?? this.createObservedClient<ClientAppData>(settings);\n\t}\n\n\tpublic update(context?: AcceptContext) {\n\t\tif (this.closed) return;\n\n\t\tthis.numberOfInboundRtpStreams = 0;\n\t\tthis.numberOfOutboundRtpStreams = 0;\n\t\tthis.numberOfPeerConnections = 0;\n\t\tthis.numberOfDataChannels = 0;\n\n\t\tfor (const client of this.observedClients.values()) {\n\t\t\tthis.numberOfInboundRtpStreams += client.numberOfInboundRtpStreams;\n\t\t\tthis.numberOfOutboundRtpStreams += client.numberOfOutboundRtpStreams;\n\t\t\tthis.numberOfPeerConnections += client.numberOfPeerConnections;\n\t\t\tthis.numberOfDataChannels += client.numberOfDataChannels;\n\t\t}\n\n\t\tthis.scoreCalculator.update();\n\t\tthis.detectors.update();\n\n\t\tthis.emit('update');\n\t\tthis._notify('call-updated', { ...this.eventScope, context });\n\n\t\tthis.deltaNumberOfIssues = 0;\n\t}\n\n\tprivate _onClientUpdate(client: ObservedClient) {\n\t\tthis.deltaNumberOfIssues += client.deltaNumberOfIssues;\n\t\tthis.numberOfIssues += client.deltaNumberOfIssues;\n\n\t\tif (client.usingTURN) {\n\t\t\tthis.clientsUsedTurn.add(client.clientId);\n\t\t}\n\t}\n\n\tprivate _clientJoined(client: ObservedClient) {\n\t\tif (!client.joinedAt) return;\n\n\t\tthis.startedAt = Math.min(this.startedAt ?? client.joinedAt, client.joinedAt);\n\t}\n\n\tprivate _clientLeft(client: ObservedClient) {\n\t\tif (!client.leftAt) return;\n\n\t\tthis.endedAt = Math.max(this.endedAt ?? client.leftAt, client.leftAt);\n\t}\n\n\t/** Emit an Observer-bus event scoped to this call. */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.observer.emit(type, ...args);\n\t}\n}","import { EventEmitter } from 'events';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { createLogger } from './common/logger';\n// eslint-disable-next-line camelcase\nimport { ClientEvent, ClientMetaData, ClientSample, PeerConnectionSample, ClientIssue, ExtensionStat } from './schema/ClientSample';\nimport * as MetaData from './schema/ClientMetaTypes';\nimport { ClientEventTypes } from './schema/ClientEventTypes';\nimport { ObservedCall } from './ObservedCall';\nimport { ClientMetaTypes } from './schema/ClientMetaTypes';\nimport { parseJsonAs } from './common/utils';\nimport { CalculatedScore } from './scores/CalculatedScore';\nimport type { AcceptContext } from './Observer';\nimport type { ObserverEvents, ObservedClientScope } from './ObserverEvents';\nimport type { ClientSampleSink } from './sinks/ClientSampleSink';\n\nconst logger = createLogger('ObservedClient');\n\nexport type ObservedClientSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {\n\tclientId: string;\n\tappData?: AppData;\n\tcloseClientIfIdleForMs?: number;\n};\n\n// Local lifecycle/coordination events only. Everything worth subscribing to is\n// emitted on the Observer bus (see ObserverEvents). These remain local so the\n// parent ObservedCall and the updaters can wire to them for teardown/aggregation.\nexport type ObservedClientEvents = {\n\tupdate: [sample: ClientSample, elapsedTimeInMs: number, context?: AcceptContext];\n\tclose: [];\n\tjoined: [];\n\tleft: [];\n};\n\nexport declare interface ObservedClient {\n\ton<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;\n\toff<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;\n\tonce<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;\n\temit<U extends keyof ObservedClientEvents>(event: U, ...args: ObservedClientEvents[U]): boolean;\n}\n\nexport class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic readonly clientId: string;\n\tpublic readonly observedPeerConnections = new Map<string, ObservedPeerConnection>();\n\n\t/** Per-client sink (from `ObserverConfig.createClientSink`), if any. */\n\tpublic readonly sink?: ClientSampleSink;\n\n\t/** Ancestry base shared by all Observer-bus events originating at this client. */\n\tpublic readonly eventScope: ObservedClientScope;\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\n\tpublic readonly settings: Pick<ObservedClientSettings, 'closeClientIfIdleForMs'>;\n\n\tpublic appData: AppData;\n\tpublic attachments?: Record<string, unknown>;\n\n\tpublic updated = Date.now();\n\tpublic acceptedSamples = 0;\n\tpublic closed = false;\n\n\tpublic joinedAt?: number;\n\tpublic leftAt?: number;\n\tpublic closedAt?: number;\n\tpublic lastSampleTimestamp?: number;\n\t// the timestamp of the CLIENT_JOINED event\n\tpublic operationSystem?: MetaData.OperationSystem;\n\tpublic engine?: MetaData.Engine;\n\tpublic platform?: MetaData.Platform;\n\tpublic browser?: MetaData.Browser;\n\tpublic mediaConstraints: string[] = [];\n\n\tpublic usingTURN = false;\n\tpublic usingTCP = false;\n\tpublic availableOutgoingBitrate = 0;\n\tpublic availableIncomingBitrate = 0;\n\n\tpublic deltaReceivedAudioBytes = 0;\n\tpublic deltaReceivedVideoBytes = 0;\n\tpublic deltaSentAudioBytes = 0;\n\tpublic deltaSentVideoBytes = 0;\n\tpublic deltaDataChannelBytesSent = 0;\n\tpublic deltaDataChannelBytesReceived = 0;\n\tpublic deltaDataChannelMessagesSent = 0;\n\tpublic deltaDataChannelMessagesReceived = 0;\n\tpublic deltaInboundPacketsLost = 0;\n\tpublic deltaInboundPacketsReceived = 0;\n\tpublic deltaOutboundPacketsSent = 0;\n\tpublic deltaTransportSentBytes = 0;\n\tpublic deltaTransportReceivedBytes = 0;\n\tpublic deltaRttLt50Measurements = 0;\n\tpublic deltaRttLt150Measurements = 0;\n\tpublic deltaRttLt300Measurements = 0;\n\tpublic deltaRttGtOrEq300Measurements = 0;\n\n\tpublic currentMaxRttInMs?: number;\n\tpublic currentMinRttInMs?: number;\n\tpublic currentAvgRttInMs?: number;\n\n\tpublic sendingAudioBitrate = 0;\n\tpublic sendingVideoBitrate = 0;\n\tpublic receivingAudioBitrate = 0;\n\tpublic receivingVideoBitrate = 0;\n\n\tpublic numberOfInboundRtpStreams = 0;\n\tpublic numberOfInbundTracks = 0;\n\tpublic numberOfOutboundRtpStreams = 0;\n\tpublic numberOfOutboundTracks = 0;\n\tpublic numberOfDataChannels = 0;\n\n\tpublic deltaNumberOfIssues = 0;\n\n\tpublic totalScoreSum = 0;\n\tpublic numberOfScoreMeasurements = 0;\n\t// public totalNumberOfIssues = 0;\n\n\tpublic readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];\n\tpublic issues: ClientIssue[] = [];\n\n\tprivate _pendingInjections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};\n\tprivate _activeSample?: ClientSample;\n\n\tprivate closeTimer?: ReturnType<typeof setTimeout>;\n\n\tpublic constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\n\t\tthis.eventScope = { observer: call.observer, observedCall: call, observedClient: this };\n\t\tthis.sink = call.observer.config.createClientSink?.({ clientId: settings.clientId, observedCall: call });\n\t\tthis.clientId = settings.clientId;\n\t\tthis.appData = (settings.appData ?? {}) as AppData;\n\n\t\tthis.settings = {\n\t\t\tcloseClientIfIdleForMs: settings.closeClientIfIdleForMs,\n\t\t};\n\n\t\tif (this.sink) {\n\t\t\tconst onError = (err: Error) => logger.warn('ClientSampleSink error for client %s: %o', this.clientId, err);\n\n\t\t\tthis.sink.once('close', () => this.sink?.off('error', onError));\n\t\t\tthis.sink.on('error', onError);\n\t\t}\n\t}\n\n\tpublic get numberOfPeerConnections() {\n\t\treturn this.observedPeerConnections.size;\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\n\t\tthis._flushPendingInjections();\n\n\t\tthis.closed = true;\n\n\t\tArray.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());\n\t\tif (!this.leftAt) {\n\t\t\tthis.leftAt = this.lastSampleTimestamp;\n\n\t\t\tif (this.leftAt) {\n\t\t\t\tthis.emit('left');\n\t\t\t\tthis._notify('client-left', { ...this.eventScope });\n\t\t\t}\n\t\t}\n\t\tthis.closedAt = Date.now();\n\n\t\tthis.emit('close');\n\t\tthis._notify('client-closed', { ...this.eventScope });\n\n\t\ttry {\n\t\t\tthis.sink?.end();\n\t\t} catch (err) {\n\t\t\tlogger.warn('ClientSampleSink.end failed for client %s: %o', this.clientId, err);\n\t\t}\n\t}\n\n\tpublic accept(sample: ClientSample, context?: AcceptContext): void {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to accept a sample on a closed client %s', this.clientId);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.closeTimer) {\n\t\t\tclearTimeout(this.closeTimer);\n\t\t\tthis.closeTimer = undefined;\n\t\t}\n\n\t\tconst now = Date.now();\n\t\tconst elapsedInMs = now - this.updated;\n\t\tconst elapsedInSeconds = elapsedInMs / 1000;\n\t\tlet sumOfRtts = 0;\n\t\tlet numberOfRttMeasurements = 0;\n\n\t\t++this.acceptedSamples;\n\n\t\tthis.availableIncomingBitrate = 0;\n\t\tthis.availableOutgoingBitrate = 0;\n\t\tthis.deltaDataChannelBytesReceived = 0;\n\t\tthis.deltaDataChannelBytesSent = 0;\n\t\tthis.deltaDataChannelMessagesReceived = 0;\n\t\tthis.deltaDataChannelMessagesSent = 0;\n\t\tthis.deltaInboundPacketsLost = 0;\n\t\tthis.deltaInboundPacketsReceived = 0;\n\t\tthis.deltaOutboundPacketsSent = 0;\n\t\tthis.deltaReceivedAudioBytes = 0;\n\t\tthis.deltaReceivedVideoBytes = 0;\n\t\tthis.deltaSentAudioBytes = 0;\n\t\tthis.deltaSentVideoBytes = 0;\n\t\tthis.deltaTransportReceivedBytes = 0;\n\t\tthis.deltaTransportSentBytes = 0;\n\t\tthis.deltaRttLt50Measurements = 0;\n\t\tthis.deltaRttLt150Measurements = 0;\n\t\tthis.deltaRttLt300Measurements = 0;\n\t\tthis.deltaRttGtOrEq300Measurements = 0;\n\t\tthis.deltaNumberOfIssues = 0;\n\n\t\tthis.numberOfDataChannels = 0;\n\t\tthis.numberOfInboundRtpStreams = 0;\n\t\tthis.numberOfInbundTracks = 0;\n\t\tthis.numberOfOutboundRtpStreams = 0;\n\t\tthis.numberOfOutboundTracks = 0;\n\t\tthis.usingTURN = false;\n\t\tthis.usingTCP = false;\n\t\tthis.currentMinRttInMs = undefined;\n\t\tthis.currentMaxRttInMs = undefined;\n\n\t\tthis._mergePendingInjections(sample);\n\n\t\t// From here until the end of accept, `inject*` targets this sample directly (see `_activeSample`).\n\t\tthis._activeSample = sample;\n\n\t\tconst clientEventsPostBuffer: ClientEvent[] = [];\n\n\t\tfor (const clientEvent of sample.clientEvents ?? []) {\n\t\t\tthis._processClientEvent(clientEvent, clientEventsPostBuffer);\n\t\t}\n\n\t\tfor (const metaData of sample.clientMetaItems ?? []) {\n\t\t\tthis.addMetadata(metaData);\n\t\t}\n\n\t\tfor (const issue of sample.clientIssues ?? []) {\n\t\t\tthis.addIssue(issue);\n\n\t\t\t++this.deltaNumberOfIssues;\n\t\t}\n\n\t\tfor (const extensionStat of sample.extensionStats ?? []) {\n\t\t\tthis.addExtensionStats(extensionStat);\n\t\t}\n\n\t\tfor (const pcSample of sample.peerConnections ?? []) {\n\t\t\tconst observedPeerConnection = this._updatePeerConnection(pcSample, context);\n\n\t\t\tif (!observedPeerConnection) continue;\n\n\t\t\tthis.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;\n\t\t\tthis.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;\n\t\t\tthis.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;\n\t\t\tthis.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;\n\t\t\tthis.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;\n\t\t\tthis.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;\n\t\t\tthis.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;\n\t\t\tthis.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;\n\t\t\tthis.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;\n\t\t\tthis.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;\n\t\t\tthis.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;\n\t\t\tthis.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;\n\t\t\tthis.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;\n\n\t\t\tthis.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;\n\t\t\tthis.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;\n\n\t\t\tthis.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;\n\t\t\tthis.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;\n\t\t\tthis.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;\n\t\t\tthis.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;\n\t\t\tthis.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;\n\n\t\t\tif (observedPeerConnection.usingTURN) {\n\t\t\t\tthis.usingTURN = true;\n\t\t\t}\n\t\t\tif (observedPeerConnection.usingTCP) {\n\t\t\t\tthis.usingTCP = true;\n\t\t\t}\n\n\t\t\tif (observedPeerConnection.currentRttInMs) {\n\t\t\t\tif (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {\n\t\t\t\t\tthis.currentMinRttInMs = observedPeerConnection.currentRttInMs;\n\t\t\t\t}\n\t\t\t\tif (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {\n\t\t\t\t\tthis.currentMaxRttInMs = observedPeerConnection.currentRttInMs;\n\t\t\t\t}\n\t\t\t\tif (observedPeerConnection.currentRttInMs < 50) {\n\t\t\t\t\tthis.deltaRttLt50Measurements += 1;\n\t\t\t\t} else if (observedPeerConnection.currentRttInMs < 150) {\n\t\t\t\t\tthis.deltaRttLt150Measurements += 1;\n\t\t\t\t} else if (observedPeerConnection.currentRttInMs < 300) {\n\t\t\t\t\tthis.deltaRttLt300Measurements += 1;\n\t\t\t\t} else if (300 <= observedPeerConnection.currentRttInMs) {\n\t\t\t\t\tthis.deltaRttGtOrEq300Measurements += 1;\n\t\t\t\t}\n\n\t\t\t\tsumOfRtts += observedPeerConnection.currentRttInMs;\n\t\t\t\t++numberOfRttMeasurements;\n\t\t\t}\n\t\t}\n\n\t\tfor (const clientEvent of clientEventsPostBuffer) {\n\t\t\tthis._processClientEvent(clientEvent);\n\t\t}\n\n\t\t// emit new attachments?\n\t\tthis.attachments = sample.attachments;\n\n\t\tthis.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);\n\t\tthis.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / (elapsedInSeconds);\n\t\tthis.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);\n\t\tthis.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);\n\t\tthis.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;\n\n\t\tthis.calculatedScore.value = sample.score;\n\n\t\tthis.lastSampleTimestamp = sample.timestamp;\n\t\t// emit update\n\t\tconst elapsedTimeInMs = now - this.updated;\n\n\t\tthis.emit('update', sample, elapsedTimeInMs, context);\n\t\tthis._notify('client-updated', { ...this.eventScope, sample, elapsedTimeInMs, context });\n\t\tthis.updated = now;\n\n\t\t// if result changed after update\n\t\tif (this.calculatedScore.value) {\n\t\t\tthis.totalScoreSum += this.calculatedScore.value;\n\t\t\t++this.numberOfScoreMeasurements;\n\t\t}\n\n\t\tif (this.settings.closeClientIfIdleForMs !== undefined) {\n\t\t\tthis.closeTimer = setTimeout(() => {\n\t\t\t\tthis.close();\n\t\t\t}, this.settings.closeClientIfIdleForMs);\n\t\t}\n\n\t\t// Done processing this sample. Stop directing injections at it, then persist the FINAL,\n\t\t// injection-merged sample to the sink (this is why the sink write is here, not at the top).\n\t\tthis._activeSample = undefined;\n\t\ttry {\n\t\t\tthis.sink?.write(sample);\n\t\t} catch (err) {\n\t\t\tlogger.warn('ClientSampleSink.write failed for client %s: %o', this.clientId, err);\n\t\t}\n\t}\n\n\tpublic injectMetaData(metaData: ClientMetaData) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.clientMetaItems) this._activeSample.clientMetaItems = [];\n\t\t\tthis._activeSample.clientMetaItems.push(metaData);\n\t\t\tthis.addMetadata(metaData);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.clientMetaItems) this._pendingInjections.clientMetaItems = [];\n\t\tthis._pendingInjections.clientMetaItems.push(metaData);\n\t}\n\n\tpublic injectEvent(event: ClientEvent) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.clientEvents) this._activeSample.clientEvents = [];\n\t\t\tthis._activeSample.clientEvents.push(event);\n\t\t\tthis._processClientEvent(event);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.clientEvents) this._pendingInjections.clientEvents = [];\n\t\tthis._pendingInjections.clientEvents.push(event);\n\t}\n\n\tpublic injectIssue(issue: ClientIssue) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.clientIssues) this._activeSample.clientIssues = [];\n\t\t\tthis._activeSample.clientIssues.push(issue);\n\t\t\tthis.addIssue(issue);\n\t\t\t++this.deltaNumberOfIssues;\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.clientIssues) this._pendingInjections.clientIssues = [];\n\t\tthis._pendingInjections.clientIssues.push(issue);\n\t}\n\n\tpublic injectExtensionStat(stat: ExtensionStat) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.extensionStats) this._activeSample.extensionStats = [];\n\t\t\tthis._activeSample.extensionStats.push(stat);\n\t\t\tthis.addExtensionStats(stat);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.extensionStats) this._pendingInjections.extensionStats = [];\n\t\tthis._pendingInjections.extensionStats.push(stat);\n\t}\n\n\tpublic injectAttachment(attachments: Record<string, unknown>) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.attachments) this._activeSample.attachments = {};\n\t\t\tObject.assign(this._activeSample.attachments, attachments);\n\t\t\tthis.attachments = this._activeSample.attachments;\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.attachments) this._pendingInjections.attachments = {};\n\t\tObject.assign(this._pendingInjections.attachments, attachments);\n\t}\n\n\tpublic addMetadata(metadata: ClientMetaData) {\n\t\tif (this.closed) return;\n\n\t\tswitch (metadata.type) {\n\t\t\tcase ClientMetaTypes.BROWSER: {\n\t\t\t\tthis.browser = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientMetaTypes.ENGINE: {\n\t\t\t\tthis.engine = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientMetaTypes.PLATFORM: {\n\t\t\t\tthis.platform = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientMetaTypes.OPERATION_SYSTEM: {\n\t\t\t\tthis.operationSystem = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis._notify('client-metadata', { ...this.eventScope, metaData: metadata });\n\t}\n\n\tpublic addIssue(issue: ClientIssue) {\n\t\tif (this.closed) return;\n\n\t\tthis._notify('client-issue', { ...this.eventScope, issue });\n\t}\n\n\tpublic addExtensionStats(stats: ExtensionStat) {\n\t\tthis._notify('client-extension-stats', { ...this.eventScope, extensionStats: stats });\n\t}\n\n\tprivate _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {\n\t\t// eslint-disable-next-line no-console\n\t\t// console.warn('ClientEvent', event);\n\t\tswitch (event.type) {\n\t\t\tcase ClientEventTypes.CLIENT_JOINED: {\n\t\t\t\tif (event.timestamp) {\n\t\t\t\t\tif (!this.joinedAt) {\n\t\t\t\t\t\tthis.joinedAt = event.timestamp;\n\t\t\t\t\t\tthis.emit('joined');\n\t\t\t\t\t\tthis._notify('client-joined', { ...this.eventScope });\n\t\t\t\t\t} else if (this.joinedAt < event.timestamp) {\n\t\t\t\t\t\tthis._notify('client-rejoined', { ...this.eventScope, timestamp: event.timestamp });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.joinedAt = event.timestamp;\n\t\t\t\t\t\tlogger.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlogger.debug('Client %s joined at %o', this.clientId, event);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.CLIENT_LEFT: {\n\t\t\t\tif (event.timestamp) {\n\t\t\t\t\tif (!this.leftAt) {\n\t\t\t\t\t\tthis.leftAt = event.timestamp;\n\t\t\t\t\t\tthis.emit('left');\n\t\t\t\t\t\tthis._notify('client-left', { ...this.eventScope });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn(`Client ${this.clientId} leftAt timestamp was already set`);\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\tlogger.debug('Client %s left at %o', this.clientId, event);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.PEER_CONNECTION_OPENED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.openedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.PEER_CONNECTION_CLOSED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.closedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_ADDED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedTrack) {\n\t\t\t\t\t\tobservedTrack.addedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_REMOVED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedTrack) {\n\t\t\t\t\t\tobservedTrack.removedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.DATA_CHANNEL_OPEN: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);\n\n\t\t\t\t\tif (observedDataChannel) {\n\t\t\t\t\t\tobservedDataChannel.addedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.DATA_CHANNEL_CLOSED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);\n\n\t\t\t\t\tif (observedDataChannel) {\n\t\t\t\t\t\tobservedDataChannel.removedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_MUTED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);\n\t\t\t\t\tconst observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tif (observedInboundTrack) {\n\t\t\t\t\t\t\tobservedInboundTrack.muted = true;\n\t\t\t\t\t\t\tthis._notify('inbound-track-muted', { ...this.eventScope, observedPeerConnection, observedInboundTrack });\n\t\t\t\t\t\t} else if (observedOutboundTrack) {\n\t\t\t\t\t\t\tobservedOutboundTrack.muted = true;\n\t\t\t\t\t\t\tthis._notify('outbound-track-muted', { ...this.eventScope, observedPeerConnection, observedOutboundTrack });\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_MUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_UNMUTED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);\n\t\t\t\t\tconst observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tif (observedInboundTrack) {\n\t\t\t\t\t\t\tobservedInboundTrack.muted = false;\n\t\t\t\t\t\t\tthis._notify('inbound-track-unmuted', { ...this.eventScope, observedPeerConnection, observedInboundTrack });\n\t\t\t\t\t\t} else if (observedOutboundTrack) {\n\t\t\t\t\t\t\tobservedOutboundTrack.muted = false;\n\t\t\t\t\t\t\tthis._notify('outbound-track-unmuted', { ...this.eventScope, observedPeerConnection, observedOutboundTrack });\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_UNMUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.ICE_CONNECTION_STATE_CHANGED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceConnectionState && typeof payload.iceConnectionState === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.iceConnectionState = payload.iceConnectionState as 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';\n\t\t\t\t\t\tthis._notify('ice-connection-state-changed', { ...this.eventScope, observedPeerConnection, state: payload.iceConnectionState });\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received ICE_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.ICE_GATHERING_STATE_CHANGED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceGatheringState && typeof payload.iceGatheringState === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.iceGatheringState = payload.iceGatheringState as 'new' | 'gathering' | 'complete';\n\t\t\t\t\t\tthis._notify('ice-gathering-state-changed', { ...this.eventScope, observedPeerConnection, state: payload.iceGatheringState });\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received ICE_GATHERING_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.PEER_CONNECTION_STATE_CHANGED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.peerConnectionState && typeof payload.peerConnectionState === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.connectionState = payload.peerConnectionState as 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';\n\t\t\t\t\t\tthis._notify('connection-state-changed', { ...this.eventScope, observedPeerConnection, state: payload.peerConnectionState });\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received PEER_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis._notify('client-event', { ...this.eventScope, event });\n\t}\n\n\tprivate _updatePeerConnection(sample: PeerConnectionSample, context?: AcceptContext): ObservedPeerConnection | undefined {\n\t\tlet observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);\n\n\t\tif (!observedPeerConnection) {\n\t\t\tif (!sample.peerConnectionId) {\n\t\t\t\treturn (logger.warn(\n\t\t\t\t\t`ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,\n\t\t\t\t\tsample\n\t\t\t\t), void 0);\n\t\t\t}\n\n\t\t\tconst newObservedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);\n\n\t\t\tnewObservedPeerConnection.once('close', () => {\n\t\t\t\tthis.observedPeerConnections.delete(sample.peerConnectionId);\n\t\t\t});\n\t\t\tthis.observedPeerConnections.set(sample.peerConnectionId, newObservedPeerConnection);\n\n\t\t\tthis._notify('peer-connection-added', { ...this.eventScope, observedPeerConnection: newObservedPeerConnection });\n\n\t\t\tobservedPeerConnection = newObservedPeerConnection;\n\t\t}\n\n\t\tobservedPeerConnection.accept(sample, context);\n\n\t\treturn observedPeerConnection;\n\t}\n\n\tprivate _mergePendingInjections(sample: ClientSample): ClientSample {\n\t\tif (this.closed) return sample;\n\n\t\tif (this._pendingInjections.clientEvents) {\n\t\t\tif (!sample.clientEvents) sample.clientEvents = [];\n\t\t\tsample.clientEvents.push(...this._pendingInjections.clientEvents);\n\n\t\t\tthis._pendingInjections.clientEvents = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.clientIssues) {\n\t\t\tif (!sample.clientIssues) sample.clientIssues = [];\n\t\t\tsample.clientIssues.push(...this._pendingInjections.clientIssues);\n\n\t\t\tthis._pendingInjections.clientIssues = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.extensionStats) {\n\t\t\tif (!sample.extensionStats) sample.extensionStats = [];\n\t\t\tsample.extensionStats.push(...this._pendingInjections.extensionStats);\n\n\t\t\tthis._pendingInjections.extensionStats = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.attachments) {\n\t\t\tif (!sample.attachments) sample.attachments = {};\n\t\t\tObject.assign(sample.attachments, this._pendingInjections.attachments);\n\n\t\t\tthis._pendingInjections.attachments = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.clientMetaItems) {\n\t\t\tif (!sample.clientMetaItems) sample.clientMetaItems = [];\n\t\t\tsample.clientMetaItems.push(...this._pendingInjections.clientMetaItems);\n\n\t\t\tthis._pendingInjections.clientMetaItems = undefined;\n\t\t}\n\n\t\treturn sample;\n\t}\n\n\tprivate _flushPendingInjections() {\n\t\tconst hasPending = Boolean(\n\t\t\tthis._pendingInjections.clientEvents ||\n\t\t\tthis._pendingInjections.clientIssues ||\n\t\t\tthis._pendingInjections.extensionStats ||\n\t\t\tthis._pendingInjections.clientMetaItems ||\n\t\t\tthis._pendingInjections.attachments,\n\t\t);\n\n\t\tif (!hasPending) return;\n\n\t\tconst finalSample: ClientSample = { timestamp: Date.now() };\n\n\t\tthis._mergePendingInjections(finalSample);\n\n\t\tfor (const clientEvent of finalSample.clientEvents ?? []) this._processClientEvent(clientEvent);\n\t\tfor (const metaData of finalSample.clientMetaItems ?? []) this.addMetadata(metaData);\n\t\tfor (const issue of finalSample.clientIssues ?? []) this.addIssue(issue);\n\t\tfor (const extensionStat of finalSample.extensionStats ?? []) this.addExtensionStats(extensionStat);\n\t\tif (finalSample.attachments) this.attachments = { ...this.attachments, ...finalSample.attachments };\n\n\t\ttry {\n\t\t\tthis.sink?.write(finalSample);\n\t\t} catch (err) {\n\t\t\tlogger.warn('ClientSampleSink.write failed during injection flush for client %s: %o', this.clientId, err);\n\t\t}\n\t}\n\n\t/** Emit an Observer-bus event scoped to this client (or a peer connection under it). */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.call.observer.emit(type, ...args);\n\t}\n}\n","import { EventEmitter } from 'events';\nimport { ObservedClient } from './ObservedClient';\nimport { CertificateStats, CodecStats, DataChannelStats, IceCandidateStats, InboundRtpStats, InboundTrackSample, MediaPlayoutStats, MediaSourceStats, OutboundRtpStats, OutboundTrackSample, PeerConnectionSample, PeerConnectionTransportStats, RemoteInboundRtpStats, RemoteOutboundRtpStats } from './schema/ClientSample';\nimport { ObservedInboundRtp } from './ObservedInboundRtp';\nimport { createLogger } from './common/logger';\nimport { MediaKind } from './common/types';\nimport { ObservedOutboundRtp } from './ObservedOutboundRtp';\nimport { ObservedCertificate } from './ObservedCertificate';\nimport { ObservedCodec } from './ObservedCodec';\nimport { ObservedDataChannel } from './ObservedDataChannel';\nimport { ObservedIceCandidate } from './ObservedIceCandidate';\nimport { ObservedIceCandidatePair } from './ObservedIceCandidatePair';\nimport { ObservedIceTransport } from './ObservedIceTransport';\nimport { ObservedMediaSource } from './ObservedMediaSource';\nimport { ObservedPeerConnectionTransport } from './ObservedPeerConnectionTransport';\nimport { ObservedMediaPlayout } from './ObservedMediaPlayout';\nimport { ObservedRemoteInboundRtp } from './ObservedRemoteInboundRtp';\nimport { ObservedRemoteOutboundRtp } from './ObservedRemoteOutboundRtp';\nimport { ObservedInboundTrack } from './ObservedInboundTrack';\nimport { ObservedOutboundTrack } from './ObservedOutboundTrack';\nimport { CalculatedScore } from './scores/CalculatedScore';\nimport { ObservedTurnServer } from './ObservedTurnServer';\nimport { getMedian } from './common/utils';\nimport type { AcceptContext } from './Observer';\nimport type { ObserverEvents, ObservedPeerConnectionScope } from './ObserverEvents';\n\nconst logger = createLogger('ObservedPeerConnection');\n\n// Local lifecycle/coordination events only. All consumer-facing events are\n// emitted on the Observer bus (see ObserverEvents). `close` and the two track\n// `removed-*` events stay local because the parent ObservedClient wires to them\n// for teardown and track-report emission.\nexport type ObservedPeerConnectionEvents = {\n\t'removed-inbound-track': [ObservedInboundTrack];\n\t'removed-outbound-track': [ObservedOutboundTrack];\n\tclose: [];\n};\n\nexport declare interface ObservedPeerConnection {\n\ton<U extends keyof ObservedPeerConnectionEvents>(\n\t\tevent: U,\n\t\tlistener: (...args: ObservedPeerConnectionEvents[U]) => void\n\t): this;\n\toff<U extends keyof ObservedPeerConnectionEvents>(\n\t\tevent: U,\n\t\tlistener: (...args: ObservedPeerConnectionEvents[U]) => void\n\t): this;\n\tonce<U extends keyof ObservedPeerConnectionEvents>(\n\t\tevent: U,\n\t\tlistener: (...args: ObservedPeerConnectionEvents[U]) => void\n\t): this;\n\temit<U extends keyof ObservedPeerConnectionEvents>(event: U, ...args: ObservedPeerConnectionEvents[U]): boolean;\n}\n\nexport class ObservedPeerConnection extends EventEmitter {\n\tprivate _visited = true;\n\n\tpublic appData?: Record<string, unknown>;\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\n\tpublic closed = false;\n\t// timestamp of the PEER_CONNECTION_OPENED event\n\tpublic openedAt?: number;\n\t// timestamp of the PEER_CONNECTION_CLOSED event\n\tpublic closedAt?: number;\n\tpublic updated = Date.now();\n\n\tpublic connectionState?: 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';\n\tpublic iceConnectionState?: 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';\n\tpublic iceGatheringState?: 'new' | 'gathering' | 'complete';\n\n\tpublic availableIncomingBitrate = 0;\n\tpublic availableOutgoingBitrate = 0;\n\tpublic totalInboundPacketsLost = 0;\n\tpublic totalInboundPacketsReceived = 0;\n\tpublic totalOutboundPacketsSent = 0;\n\tpublic totalDataChannelBytesSent = 0;\n\tpublic totalDataChannelBytesReceived = 0;\n\tpublic totalDataChannelMessagesSent = 0;\n\tpublic totalDataChannelMessagesReceived = 0;\n\n\tpublic totalSentAudioBytes = 0;\n\tpublic totalSentVideoBytes = 0;\n\tpublic totalSentAudioPackets = 0;\n\tpublic totalSentVideoPackets = 0;\n\tpublic totalReceivedAudioPacktes = 0;\n\tpublic totalReceivedVideoPackets = 0;\n\tpublic totalReceivedAudioBytes = 0;\n\tpublic totalReceivedVideoBytes = 0;\n\n\tpublic deltaInboundPacketsLost = 0;\n\tpublic deltaInboundPacketsReceived = 0;\n\tpublic deltaOutboundPacketsSent = 0;\n\tpublic deltaDataChannelBytesSent = 0;\n\tpublic deltaDataChannelBytesReceived = 0;\n\tpublic deltaDataChannelMessagesSent = 0;\n\tpublic deltaDataChannelMessagesReceived = 0;\n\tpublic deltaInboundReceivedBytes = 0;\n\tpublic deltaOutboundSentBytes = 0;\n\n\tpublic deltaReceivedAudioBytes = 0;\n\tpublic deltaReceivedVideoBytes = 0;\n\tpublic deltaReceivedAudioPackets = 0;\n\tpublic deltaReceivedVideoPackets = 0;\n\tpublic deltaSentAudioBytes = 0;\n\tpublic deltaSentVideoBytes = 0;\n\tpublic deltaSentAudioPackets = 0;\n\tpublic deltaSentVideoPackets = 0;\n\tpublic deltaTransportSentBytes = 0;\n\tpublic deltaTransportReceivedBytes = 0;\n\n\tpublic receivingPacketsPerSecond = 0;\n\tpublic sendingPacketsPerSecond = 0;\n\tpublic sendingAudioBitrate = 0;\n\tpublic sendingVideoBitrate = 0;\n\tpublic receivingAudioBitrate = 0;\n\tpublic receivingVideoBitrate = 0;\n\n\tpublic currentRttInMs?: number;\n\tpublic currentJitter?: number;\n\n\tpublic usingTCP = false;\n\tpublic usingTURN = false;\n\n\tpublic observedTurnServer?: ObservedTurnServer;\n\tpublic readonly observedCertificates = new Map<string, ObservedCertificate>();\n\tpublic readonly observedCodecs = new Map<string, ObservedCodec>();\n\tpublic readonly observedDataChannels = new Map<string, ObservedDataChannel>();\n\tpublic readonly observedIceCandidates = new Map<string, ObservedIceCandidate>();\n\tpublic readonly observedIceCandidatesPair = new Map<string, ObservedIceCandidatePair>();\n\tpublic readonly observedIceTransports = new Map<string, ObservedIceTransport>();\n\tpublic readonly observedInboundRtps = new Map<number, ObservedInboundRtp>();\n\tpublic readonly observedInboundTracks = new Map<string, ObservedInboundTrack>();\n\tpublic readonly observedMediaPlayouts = new Map<string, ObservedMediaPlayout>();\n\tpublic readonly observedMediaSources = new Map<string, ObservedMediaSource>();\n\tpublic readonly observedOutboundRtps = new Map<number, ObservedOutboundRtp>();\n\tpublic readonly observedOutboundTracks = new Map<string, ObservedOutboundTrack>();\n\tpublic readonly observedPeerConnectionTransports = new Map<string, ObservedPeerConnectionTransport>();\n\tpublic readonly observedRemoteInboundRtps = new Map<number, ObservedRemoteInboundRtp>();\n\tpublic readonly observedRemoteOutboundRtps = new Map<number, ObservedRemoteOutboundRtp>();\n\n\tprivate readonly eventScope: ObservedPeerConnectionScope;\n\n\tpublic constructor(public readonly peerConnectionId: string, public readonly client: ObservedClient) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\t\tthis.eventScope = {\n\t\t\tobserver: client.call.observer,\n\t\t\tobservedCall: client.call,\n\t\t\tobservedClient: client,\n\t\t\tobservedPeerConnection: this,\n\t\t};\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic get codecs() {\n\t\treturn [ ...this.observedCodecs.values() ];\n\t}\n\n\tpublic get inboundRtps() {\n\t\treturn [ ...this.observedInboundRtps.values() ];\n\t}\n\n\tpublic get remoteOutboundRtps() {\n\t\treturn [ ...this.observedRemoteOutboundRtps.values() ];\n\t}\n\n\tpublic get outboundRtps() {\n\t\treturn [ ...this.observedOutboundRtps.values() ];\n\t}\n\n\tpublic get remoteInboundRtps() {\n\t\treturn [ ...this.observedRemoteInboundRtps.values() ];\n\t}\n\n\tpublic get mediaSources() {\n\t\treturn [ ...this.observedMediaSources.values() ];\n\t}\n\n\tpublic get mediaPlayouts() {\n\t\treturn [ ...this.observedMediaPlayouts.values() ];\n\t}\n\n\tpublic get dataChannels() {\n\t\treturn [ ...this.observedDataChannels.values() ];\n\t}\n\n\tpublic get peerConnectionTransports() {\n\t\treturn [ ...this.observedPeerConnectionTransports.values() ];\n\t}\n\n\tpublic get iceTransports() {\n\t\treturn [ ...this.observedIceTransports.values() ];\n\t}\n\n\tpublic get iceCandidates() {\n\t\treturn [ ...this.observedIceCandidates.values() ];\n\t}\n\n\tpublic get iceCandidatePairs() {\n\t\treturn [ ...this.observedIceCandidatesPair.values() ];\n\t}\n\n\tpublic get certificates() {\n\t\treturn [ ...this.observedCertificates.values() ];\n\t}\n\n\tpublic get selectedIceCandidatePairs() {\n\t\treturn this.iceTransports.map((iceTransport) => iceTransport.getSelectedCandidatePair())\n\t\t\t.filter((pair) => pair !== undefined) as ObservedIceCandidatePair[];\n\t}\n\n\tpublic get selectedIceCandiadtePairForTurn() {\n\t\treturn this.selectedIceCandidatePairs\n\t\t\t.filter((pair) =>\n\t\t\t\tpair.getLocalCandidate()?.candidateType === 'relay' &&\n\t\t\t\tpair.getRemoteCandidate()?.url?.startsWith('turn:')\n\t\t\t);\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\n\t\tthis.observedCertificates.forEach((observedCertificate) => this._notify('certificate-removed', { ...this.eventScope, observedCertificate }));\n\t\tthis.observedCodecs.forEach((observedCodec) => this._notify('codec-removed', { ...this.eventScope, observedCodec }));\n\t\tthis.observedDataChannels.forEach((observedDataChannel) => this._notify('data-channel-removed', { ...this.eventScope, observedDataChannel }));\n\t\tthis.observedIceCandidates.forEach((observedIceCandidate) => this._notify('ice-candidate-removed', { ...this.eventScope, observedIceCandidate }));\n\t\tthis.observedIceCandidatesPair.forEach((pair) => this._notify('ice-candidate-pair-removed', { ...this.eventScope, observedIceCandidatePair: pair }));\n\t\tthis.observedIceTransports.forEach((transport) => this._notify('ice-transport-removed', { ...this.eventScope, observedIceTransport: transport }));\n\t\tthis.observedInboundRtps.forEach((rtp) => this._notify('inbound-rtp-removed', { ...this.eventScope, observedInboundRtp: rtp }));\n\t\tthis.observedInboundTracks.forEach((track) => { this.emit('removed-inbound-track', track); this._notify('inbound-track-removed', { ...this.eventScope, observedInboundTrack: track }); });\n\t\tthis.observedMediaPlayouts.forEach((playout) => this._notify('media-playout-removed', { ...this.eventScope, observedMediaPlayout: playout }));\n\t\tthis.observedMediaSources.forEach((source) => this._notify('media-source-removed', { ...this.eventScope, observedMediaSource: source }));\n\t\tthis.observedOutboundRtps.forEach((rtp) => this._notify('outbound-rtp-removed', { ...this.eventScope, observedOutboundRtp: rtp }));\n\t\tthis.observedOutboundTracks.forEach((track) => { this.emit('removed-outbound-track', track); this._notify('outbound-track-removed', { ...this.eventScope, observedOutboundTrack: track }); });\n\t\tthis.observedPeerConnectionTransports.forEach((transport) => this._notify('peer-connection-transport-removed', { ...this.eventScope, observedPeerConnectionTransport: transport }));\n\t\tthis.observedRemoteInboundRtps.forEach((rtp) => this._notify('remote-inbound-rtp-removed', { ...this.eventScope, observedRemoteInboundRtp: rtp }));\n\t\tthis.observedRemoteOutboundRtps.forEach((rtp) => this._notify('remote-outbound-rtp-removed', { ...this.eventScope, observedRemoteOutboundRtp: rtp }));\n\n\t\tthis.observedCertificates.clear();\n\t\tthis.observedCodecs.clear();\n\t\tthis.observedDataChannels.clear();\n\t\tthis.observedIceCandidates.clear();\n\t\tthis.observedIceCandidatesPair.clear();\n\t\tthis.observedIceTransports.clear();\n\t\tthis.observedInboundRtps.clear();\n\t\tthis.observedInboundTracks.clear();\n\t\tthis.observedMediaPlayouts.clear();\n\t\tthis.observedMediaSources.clear();\n\t\tthis.observedOutboundRtps.clear();\n\t\tthis.observedOutboundTracks.clear();\n\t\tthis.observedPeerConnectionTransports.clear();\n\t\tthis.observedRemoteInboundRtps.clear();\n\t\tthis.observedRemoteOutboundRtps.clear();\n\n\t\tthis.client.call.observer.observedTURN.removePeerConnection(this);\n\n\t\tif (!this.closedAt) this.closedAt = Date.now();\n\n\t\tthis.emit('close');\n\t\tthis._notify('peer-connection-closed', { ...this.eventScope });\n\t}\n\n\tpublic accept(sample: PeerConnectionSample, context?: AcceptContext) {\n\t\tif (this.closed) return;\n\t\tthis._visited = true;\n\n\t\tif (context) this.appData = { ...this.appData, ...context };\n\n\t\tthis.availableIncomingBitrate = 0;\n\t\tthis.availableOutgoingBitrate = 0;\n\t\tthis.deltaInboundPacketsLost = 0;\n\t\tthis.deltaInboundPacketsReceived = 0;\n\t\tthis.deltaOutboundPacketsSent = 0;\n\t\tthis.deltaDataChannelBytesSent = 0;\n\t\tthis.deltaDataChannelBytesReceived = 0;\n\t\tthis.deltaInboundReceivedBytes = 0;\n\t\tthis.deltaOutboundSentBytes = 0;\n\t\tthis.deltaReceivedAudioBytes = 0;\n\t\tthis.deltaReceivedVideoBytes = 0;\n\t\tthis.deltaReceivedAudioPackets = 0;\n\t\tthis.deltaReceivedVideoPackets = 0;\n\t\tthis.deltaSentAudioBytes = 0;\n\t\tthis.deltaSentVideoBytes = 0;\n\t\tthis.deltaSentAudioPackets = 0;\n\t\tthis.deltaSentVideoPackets = 0;\n\t\tthis.deltaTransportReceivedBytes = 0;\n\t\tthis.deltaTransportSentBytes = 0;\n\n\t\tthis.sendingAudioBitrate = 0;\n\t\tthis.sendingVideoBitrate = 0;\n\t\tthis.receivingAudioBitrate = 0;\n\t\tthis.receivingVideoBitrate = 0;\n\n\t\tconst now = Date.now();\n\t\tconst elapsedTimeInMs = now - this.updated;\n\t\tconst elapsedTimeInSec = elapsedTimeInMs / 1000;\n\t\tconst rttMeasurementsInSec: number[] = [];\n\t\tconst jitterMeasurements: number[] = [];\n\n\t\tif (sample.certificates) {\n\t\t\tfor (const certificate of sample.certificates) {\n\t\t\t\tthis._updateCertificateStats(certificate);\n\t\t\t}\n\t\t}\n\t\tif (sample.codecs) {\n\t\t\tfor (const codec of sample.codecs) {\n\t\t\t\tthis._updateCodecStats(codec);\n\t\t\t}\n\t\t}\n\t\tif (sample.dataChannels) {\n\t\t\tfor (const dataChannel of sample.dataChannels) {\n\t\t\t\tconst observedDataChannel = this._updateDataChannelStats(dataChannel);\n\n\t\t\t\tif (!observedDataChannel) continue;\n\n\t\t\t\tthis.deltaDataChannelBytesSent += observedDataChannel.deltaBytesSent;\n\t\t\t\tthis.deltaDataChannelBytesReceived += observedDataChannel.deltaBytesReceived;\n\t\t\t\tthis.deltaDataChannelMessagesSent += observedDataChannel.deltaMessagesSent;\n\t\t\t\tthis.deltaDataChannelMessagesReceived += observedDataChannel.deltaMessagesReceived;\n\t\t\t}\n\t\t}\n\t\tif (sample.iceCandidates) {\n\t\t\tfor (const iceCandidate of sample.iceCandidates) {\n\t\t\t\tthis._updateIceCandidateStats(iceCandidate);\n\t\t\t}\n\t\t}\n\t\tif (sample.iceCandidatePairs) {\n\t\t\tfor (const iceCandidatePair of sample.iceCandidatePairs) {\n\t\t\t\tconst observedCandidatePair = this._updateIceCandidatePairStats(iceCandidatePair);\n\n\t\t\t\tif (!observedCandidatePair) continue;\n\n\t\t\t\tif (observedCandidatePair.currentRoundTripTime) {\n\t\t\t\t\trttMeasurementsInSec.push(observedCandidatePair.currentRoundTripTime);\n\t\t\t\t}\n\t\t\t\tif (observedCandidatePair.availableIncomingBitrate) {\n\t\t\t\t\tthis.availableIncomingBitrate += observedCandidatePair.availableIncomingBitrate;\n\t\t\t\t}\n\t\t\t\tif (observedCandidatePair.availableOutgoingBitrate) {\n\t\t\t\t\tthis.availableOutgoingBitrate += observedCandidatePair.availableOutgoingBitrate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (sample.iceTransports) {\n\t\t\tfor (const iceTransport of sample.iceTransports) {\n\t\t\t\tconst observedIceTransport = this._updateIceTransportStats(iceTransport);\n\n\t\t\t\tif (!observedIceTransport) continue;\n\t\t\t}\n\t\t}\n\t\tif (sample.inboundRtps) {\n\t\t\tfor (const inboundRtp of sample.inboundRtps) {\n\t\t\t\tconst observedInboundRtp = this._updateInboundRtpStats(inboundRtp);\n\n\t\t\t\tif (!observedInboundRtp) continue;\n\n\t\t\t\tthis.deltaInboundPacketsLost += observedInboundRtp.deltaLostPackets;\n\t\t\t\tthis.deltaInboundPacketsReceived += observedInboundRtp.deltaReceivedPackets;\n\t\t\t\tthis.deltaInboundReceivedBytes += observedInboundRtp.deltaBytesReceived;\n\n\t\t\t\tswitch (inboundRtp.kind) {\n\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tthis.deltaReceivedAudioBytes += observedInboundRtp.deltaBytesReceived;\n\t\t\t\t\t\tthis.deltaReceivedAudioPackets += observedInboundRtp.deltaReceivedPackets;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'video':\n\t\t\t\t\t\tthis.deltaReceivedVideoBytes += observedInboundRtp.deltaBytesReceived;\n\t\t\t\t\t\tthis.deltaReceivedVideoPackets += observedInboundRtp.deltaReceivedPackets;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (observedInboundRtp.jitter) {\n\t\t\t\t\tjitterMeasurements.push(observedInboundRtp.jitter);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (sample.mediaPlayouts) {\n\t\t\tfor (const mediaPlayout of sample.mediaPlayouts) {\n\t\t\t\tthis._updateMediaPlayoutStats(mediaPlayout);\n\t\t\t}\n\t\t}\n\t\tif (sample.mediaSources) {\n\t\t\tfor (const mediaSource of sample.mediaSources) {\n\t\t\t\tthis._updateMediaSourceStats(mediaSource);\n\t\t\t}\n\t\t}\n\t\tif (sample.outboundRtps) {\n\t\t\tfor (const outboundRtp of sample.outboundRtps) {\n\t\t\t\tconst observedOutboundRtp = this._updateOutboundRtpStats(outboundRtp);\n\n\t\t\t\tif (!observedOutboundRtp) continue;\n\n\t\t\t\tthis.deltaOutboundPacketsSent += observedOutboundRtp.deltaPacketsSent ?? 0;\n\t\t\t\tthis.deltaOutboundSentBytes += observedOutboundRtp.deltaBytesSent ?? 0;\n\n\t\t\t\tswitch (outboundRtp.kind) {\n\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tthis.deltaSentAudioBytes += observedOutboundRtp.deltaBytesSent;\n\t\t\t\t\t\tthis.deltaSentAudioPackets += observedOutboundRtp.deltaPacketsSent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'video':\n\t\t\t\t\t\tthis.deltaSentVideoBytes += observedOutboundRtp.deltaBytesSent;\n\t\t\t\t\t\tthis.deltaSentVideoPackets += observedOutboundRtp.deltaPacketsSent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\tif (sample.peerConnectionTransports) {\n\t\t\tfor (const peerConnectionTransport of sample.peerConnectionTransports) {\n\t\t\t\tconst observedTransport = this._updatePeerConnectionTransportStats(peerConnectionTransport);\n\n\t\t\t\tif (!observedTransport) continue;\n\n\t\t\t}\n\t\t}\n\t\tif (sample.remoteInboundRtps) {\n\t\t\tfor (const remoteInboundRtp of sample.remoteInboundRtps) {\n\t\t\t\tconst observedRemoteInboundRtp = this._updateRemoteInboundRtpStats(remoteInboundRtp);\n\n\t\t\t\tif (!observedRemoteInboundRtp) continue;\n\n\t\t\t\tif (observedRemoteInboundRtp.roundTripTime) {\n\t\t\t\t\trttMeasurementsInSec.push(observedRemoteInboundRtp.roundTripTime);\n\t\t\t\t}\n\n\t\t\t\t// Surface receiver-report-derived metrics on the corresponding local outbound-rtp.\n\t\t\t\tconst observedOutboundRtp = observedRemoteInboundRtp.getOutboundRtp();\n\n\t\t\t\tif (observedOutboundRtp) {\n\t\t\t\t\tif (observedRemoteInboundRtp.roundTripTime !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remoteRttInMs = observedRemoteInboundRtp.roundTripTime * 1000;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteInboundRtp.fractionLost !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remoteFractionLost = observedRemoteInboundRtp.fractionLost;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteInboundRtp.jitter !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remoteJitter = observedRemoteInboundRtp.jitter;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteInboundRtp.packetsLost !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remotePacketsLost = observedRemoteInboundRtp.packetsLost;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (sample.remoteOutboundRtps) {\n\t\t\tfor (const remoteOutboundRtp of sample.remoteOutboundRtps) {\n\t\t\t\tconst observedRemoteOutboundRtp = this._updateRemoteOutboundRtpStats(remoteOutboundRtp);\n\n\t\t\t\tif (!observedRemoteOutboundRtp) continue;\n\n\t\t\t\t// Surface sender-report-derived metrics on the corresponding local inbound-rtp.\n\t\t\t\tconst observedInboundRtp = observedRemoteOutboundRtp.getInboundRtp();\n\n\t\t\t\tif (observedInboundRtp) {\n\t\t\t\t\tif (observedRemoteOutboundRtp.roundTripTime !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remoteRttInMs = observedRemoteOutboundRtp.roundTripTime * 1000;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteOutboundRtp.bytesSent !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remoteBytesSent = observedRemoteOutboundRtp.bytesSent;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteOutboundRtp.packetsSent !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remotePacketsSent = observedRemoteOutboundRtp.packetsSent;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteOutboundRtp.remoteTimestamp !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remoteTimestamp = observedRemoteOutboundRtp.remoteTimestamp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// tracks should be updated last as they are derived stats\n\t\t// and depends on base stats but they all received in the sample sample\n\t\tif (sample.inboundTracks) {\n\t\t\tfor (const inboundTrack of sample.inboundTracks) {\n\t\t\t\tthis._updateInboundTrackSample(inboundTrack);\n\t\t\t}\n\t\t}\n\t\tif (sample.outboundTracks) {\n\t\t\tfor (const outboundTrack of sample.outboundTracks) {\n\t\t\t\tthis._updateOutboundTrackSample(outboundTrack);\n\t\t\t}\n\t\t}\n\n\t\tthis.totalInboundPacketsLost += this.deltaInboundPacketsLost;\n\t\tthis.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;\n\t\tthis.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;\n\t\tthis.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;\n\t\tthis.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;\n\t\tthis.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;\n\t\tthis.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;\n\t\tthis.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;\n\t\tthis.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;\n\t\tthis.totalSentAudioBytes += this.deltaSentAudioBytes;\n\t\tthis.totalSentVideoBytes += this.deltaSentVideoBytes;\n\t\tthis.totalReceivedAudioPacktes += this.deltaReceivedAudioPackets;\n\t\tthis.totalReceivedVideoPackets += this.deltaReceivedVideoPackets;\n\t\tthis.totalSentAudioPackets += this.deltaSentAudioPackets;\n\t\tthis.totalSentVideoPackets += this.deltaSentVideoPackets;\n\n\t\tthis.receivingPacketsPerSecond = this.deltaInboundPacketsReceived / elapsedTimeInSec;\n\t\tthis.sendingPacketsPerSecond = this.deltaOutboundPacketsSent / elapsedTimeInSec;\n\t\tthis.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / elapsedTimeInSec;\n\t\tthis.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / elapsedTimeInSec;\n\t\tthis.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / elapsedTimeInSec;\n\t\tthis.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / elapsedTimeInSec;\n\n\t\tif (rttMeasurementsInSec.length > 0) {\n\t\t\tthis.currentRttInMs = getMedian(rttMeasurementsInSec, false) * 1000;\n\t\t} else {\n\t\t\tthis.currentRttInMs = undefined;\n\t\t}\n\t\tif (jitterMeasurements.length > 0) {\n\t\t\tthis.currentJitter = getMedian(jitterMeasurements, false);\n\t\t} else {\n\t\t\tthis.currentJitter = undefined;\n\t\t}\n\t\tconst wasUsingTURN = this.usingTURN;\n\t\tconst selectedIceCandidatePairs = this.selectedIceCandidatePairs;\n\t\tconst selectedCandidatePairForTurn: ObservedIceCandidatePair[] = [];\n\n\t\tthis.usingTCP = false;\n\t\tthis.usingTURN = false;\n\n\t\tfor (const selectedCandidatePair of selectedIceCandidatePairs) {\n\t\t\tif (selectedCandidatePair.getLocalCandidate()?.protocol === 'tcp') {\n\t\t\t\tthis.usingTCP = true;\n\t\t\t}\n\t\t\tif (selectedCandidatePair.getLocalCandidate()?.candidateType === 'relay' && selectedCandidatePair.getRemoteCandidate()?.url?.startsWith('turn:')) {\n\t\t\t\tselectedCandidatePairForTurn.push(selectedCandidatePair);\n\t\t\t\tthis.usingTURN = true;\n\t\t\t}\n\t\t\tthis.deltaTransportReceivedBytes += selectedCandidatePair.deltaBytesReceived;\n\t\t\tthis.deltaTransportSentBytes += selectedCandidatePair.deltaBytesSent;\n\t\t}\n\n\t\tif (this.usingTURN) {\n\t\t\tif (!this.observedTurnServer) {\n\t\t\t\tthis.observedTurnServer = this.client.call.observer.observedTURN.addPeerConnection(this);\n\t\t\t}\n\t\t\tthis.observedTurnServer?.updateTurnUsage(...selectedCandidatePairForTurn);\n\t\t} else if (wasUsingTURN) {\n\t\t\tif (!this.usingTURN) {\n\t\t\t\tthis.client.call.observer.observedTURN.removePeerConnection(this);\n\t\t\t}\n\t\t}\n\t\tthis.calculatedScore.value = sample.score;\n\t\tthis.updated = now;\n\t\tthis._checkVisited();\n\n\t\tthis._notify('peer-connection-updated', { ...this.eventScope, context });\n\t}\n\n\tprivate _checkVisited() {\n\t\tfor (const certificate of [ ...this.observedCertificates.values() ]) {\n\t\t\tif (certificate.visited) continue;\n\n\t\t\tthis.observedCertificates.delete(certificate.id);\n\t\t}\n\t\tfor (const observedCodec of [ ...this.observedCodecs.values() ]) {\n\t\t\tif (observedCodec.visited) continue;\n\n\t\t\tthis.observedCodecs.delete(observedCodec.id);\n\t\t\tthis._notify('codec-removed', { ...this.eventScope, observedCodec });\n\t\t}\n\t\tfor (const observedDataChannel of [ ...this.observedDataChannels.values() ]) {\n\t\t\tif (observedDataChannel.visited) continue;\n\n\t\t\tthis.observedDataChannels.delete(observedDataChannel.id);\n\t\t\tthis._notify('data-channel-removed', { ...this.eventScope, observedDataChannel });\n\t\t}\n\t\tfor (const observedIceCandidate of [ ...this.observedIceCandidates.values() ]) {\n\t\t\tif (observedIceCandidate.visited) continue;\n\n\t\t\tthis.observedIceCandidates.delete(observedIceCandidate.id);\n\t\t\tthis._notify('ice-candidate-removed', { ...this.eventScope, observedIceCandidate });\n\t\t}\n\t\tfor (const observedIceCandidatePair of [ ...this.observedIceCandidatesPair.values() ]) {\n\t\t\tif (observedIceCandidatePair.visited) continue;\n\n\t\t\tthis.observedIceCandidatesPair.delete(observedIceCandidatePair.id);\n\t\t\tthis._notify('ice-candidate-pair-removed', { ...this.eventScope, observedIceCandidatePair });\n\t\t}\n\t\tfor (const observedIceTransport of [ ...this.observedIceTransports.values() ]) {\n\t\t\tif (observedIceTransport.visited) continue;\n\n\t\t\tthis.observedIceTransports.delete(observedIceTransport.id);\n\t\t\tthis._notify('ice-transport-removed', { ...this.eventScope, observedIceTransport });\n\t\t}\n\t\tfor (const observedInboundRtp of [ ...this.observedInboundRtps.values() ]) {\n\t\t\tif (observedInboundRtp.visited) continue;\n\n\t\t\tthis.observedInboundRtps.delete(observedInboundRtp.ssrc);\n\t\t\tthis._notify('inbound-rtp-removed', { ...this.eventScope, observedInboundRtp });\n\t\t}\n\t\tfor (const observedInboundTrack of [ ...this.observedInboundTracks.values() ]) {\n\t\t\tif (observedInboundTrack.visited) continue;\n\n\t\t\tthis.observedInboundTracks.delete(observedInboundTrack.id);\n\t\t\tthis.emit('removed-inbound-track', observedInboundTrack);\n\t\t\tthis._notify('inbound-track-removed', { ...this.eventScope, observedInboundTrack });\n\t\t}\n\t\tfor (const observedMediaPlayout of [ ...this.observedMediaPlayouts.values() ]) {\n\t\t\tif (observedMediaPlayout.visited) continue;\n\n\t\t\tthis.observedMediaPlayouts.delete(observedMediaPlayout.id);\n\t\t\tthis._notify('media-playout-removed', { ...this.eventScope, observedMediaPlayout });\n\t\t}\n\t\tfor (const observedMediaSource of [ ...this.observedMediaSources.values() ]) {\n\t\t\tif (observedMediaSource.visited) continue;\n\n\t\t\tthis.observedMediaSources.delete(observedMediaSource.id);\n\t\t\tthis._notify('media-source-removed', { ...this.eventScope, observedMediaSource });\n\t\t}\n\t\tfor (const observedOutboundRtp of [ ...this.observedOutboundRtps.values() ]) {\n\t\t\tif (observedOutboundRtp.visited) continue;\n\n\t\t\tthis.observedOutboundRtps.delete(observedOutboundRtp.ssrc);\n\t\t\tthis._notify('outbound-rtp-removed', { ...this.eventScope, observedOutboundRtp });\n\t\t}\n\t\tfor (const observedOutboundTrack of [ ...this.observedOutboundTracks.values() ]) {\n\t\t\tif (observedOutboundTrack.visited) continue;\n\n\t\t\tthis.observedOutboundTracks.delete(observedOutboundTrack.id);\n\t\t\tthis.emit('removed-outbound-track', observedOutboundTrack);\n\t\t\tthis._notify('outbound-track-removed', { ...this.eventScope, observedOutboundTrack });\n\t\t}\n\t\tfor (const observedPeerConnectionTransport of [ ...this.observedPeerConnectionTransports.values() ]) {\n\t\t\tif (observedPeerConnectionTransport.visited) continue;\n\n\t\t\tthis.observedPeerConnectionTransports.delete(observedPeerConnectionTransport.id);\n\t\t\tthis._notify('peer-connection-transport-removed', { ...this.eventScope, observedPeerConnectionTransport });\n\t\t}\n\t\tfor (const observedRemoteInboundRtp of [ ...this.observedRemoteInboundRtps.values() ]) {\n\t\t\tif (observedRemoteInboundRtp.visited) continue;\n\n\t\t\tthis.observedRemoteInboundRtps.delete(observedRemoteInboundRtp.ssrc);\n\t\t\tthis._notify('remote-inbound-rtp-removed', { ...this.eventScope, observedRemoteInboundRtp });\n\t\t}\n\t\tfor (const observedRemoteOutboundRtp of [ ...this.observedRemoteOutboundRtps.values() ]) {\n\t\t\tif (observedRemoteOutboundRtp.visited) continue;\n\n\t\t\tthis.observedRemoteOutboundRtps.delete(observedRemoteOutboundRtp.ssrc);\n\t\t\tthis._notify('remote-outbound-rtp-removed', { ...this.eventScope, observedRemoteOutboundRtp });\n\t\t}\n\t}\n\n\tprivate _updateCertificateStats(stats: CertificateStats) {\n\t\tlet observedCertificate = this.observedCertificates.get(stats.id);\n\n\t\tif (!observedCertificate) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.fingerprint) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid CertificateStats (missing timestamp OR id OR fingerprint field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedCertificate = new ObservedCertificate(stats.timestamp, stats.id, this);\n\n\t\t\tobservedCertificate.update(stats);\n\n\t\t\tthis.observedCertificates.set(stats.id, observedCertificate);\n\t\t\tthis._notify('certificate-added', { ...this.eventScope, observedCertificate });\n\t\t} else {\n\t\t\tobservedCertificate.update(stats);\n\t\t\tthis._notify('certificate-updated', { ...this.eventScope, observedCertificate });\n\t\t}\n\n\t\treturn observedCertificate;\n\t}\n\n\tprivate _updateCodecStats(stats: CodecStats) {\n\t\tlet observedCodec = this.observedCodecs.get(stats.id);\n\n\t\tif (!observedCodec) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.mimeType) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid CodecStats (missing timestamp OR id OR mimeType field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedCodec = new ObservedCodec(stats.timestamp, stats.id, stats.mimeType, this);\n\n\t\t\tobservedCodec.update(stats);\n\n\t\t\tthis.observedCodecs.set(stats.id, observedCodec);\n\t\t\tthis._notify('codec-added', { ...this.eventScope, observedCodec });\n\t\t} else {\n\t\t\tobservedCodec.update(stats);\n\t\t}\n\t\tthis._notify('codec-updated', { ...this.eventScope, observedCodec });\n\n\t\treturn observedCodec;\n\t}\n\n\tprivate _updateDataChannelStats(stats: DataChannelStats) {\n\t\tlet observedDataChannel = this.observedDataChannels.get(stats.id);\n\n\t\tif (!observedDataChannel) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid DataChannelStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedDataChannel = new ObservedDataChannel(stats.timestamp, stats.id, this);\n\n\t\t\tobservedDataChannel.update(stats);\n\n\t\t\tthis.observedDataChannels.set(stats.id, observedDataChannel);\n\t\t\tthis._notify('data-channel-added', { ...this.eventScope, observedDataChannel });\n\t\t} else {\n\t\t\tobservedDataChannel.update(stats);\n\t\t}\n\t\tthis._notify('data-channel-updated', { ...this.eventScope, observedDataChannel });\n\n\t\treturn observedDataChannel;\n\t}\n\n\tprivate _updateIceCandidateStats(stats: IceCandidateStats) {\n\t\tlet observedIceCandidate = this.observedIceCandidates.get(stats.id);\n\n\t\tif (!observedIceCandidate) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedIceCandidate = new ObservedIceCandidate(stats.timestamp, stats.id, this);\n\n\t\t\tobservedIceCandidate.update(stats);\n\n\t\t\tthis.observedIceCandidates.set(stats.id, observedIceCandidate);\n\t\t\tthis._notify('ice-candidate-added', { ...this.eventScope, observedIceCandidate });\n\t\t} else {\n\t\t\tobservedIceCandidate.update(stats);\n\t\t}\n\t\tthis._notify('ice-candidate-updated', { ...this.eventScope, observedIceCandidate });\n\n\t\treturn observedIceCandidate;\n\t}\n\n\tprivate _updateIceCandidatePairStats(stats: IceCandidateStats) {\n\t\tlet observedIceCandidatePair = this.observedIceCandidatesPair.get(stats.id);\n\n\t\tif (!observedIceCandidatePair) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedIceCandidatePair = new ObservedIceCandidatePair(stats.timestamp, stats.id, this);\n\n\t\t\tobservedIceCandidatePair.update(stats);\n\n\t\t\tthis.observedIceCandidatesPair.set(stats.id, observedIceCandidatePair);\n\t\t\tthis._notify('ice-candidate-pair-added', { ...this.eventScope, observedIceCandidatePair });\n\t\t} else {\n\t\t\tobservedIceCandidatePair.update(stats);\n\t\t}\n\t\tthis._notify('ice-candidate-pair-updated', { ...this.eventScope, observedIceCandidatePair });\n\n\t\treturn observedIceCandidatePair;\n\t}\n\n\tprivate _updateIceTransportStats(stats: IceCandidateStats) {\n\t\tlet observedIceTransport = this.observedIceTransports.get(stats.id);\n\n\t\tif (!observedIceTransport) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedIceTransport = new ObservedIceTransport(stats.timestamp, stats.id, this);\n\n\t\t\tobservedIceTransport.update(stats);\n\n\t\t\tthis.observedIceTransports.set(stats.id, observedIceTransport);\n\t\t\tthis._notify('ice-transport-added', { ...this.eventScope, observedIceTransport });\n\t\t} else {\n\t\t\tobservedIceTransport.update(stats);\n\t\t}\n\t\tthis._notify('ice-transport-updated', { ...this.eventScope, observedIceTransport });\n\n\t\treturn observedIceTransport;\n\t}\n\n\tprivate _updateInboundRtpStats(stats: InboundRtpStats) {\n\t\tlet observedInboundRtp = this.observedInboundRtps.get(stats.ssrc);\n\n\t\tif (!observedInboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind || !stats.trackIdentifier) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR ssrc OR kind OR trackIdentifier field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedInboundRtp = new ObservedInboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tstats.trackIdentifier,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedInboundRtp.update(stats);\n\n\t\t\tthis.observedInboundRtps.set(stats.ssrc, observedInboundRtp);\n\t\t\tthis._notify('inbound-rtp-added', { ...this.eventScope, observedInboundRtp });\n\t\t} else {\n\t\t\tobservedInboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('inbound-rtp-updated', { ...this.eventScope, observedInboundRtp });\n\n\t\treturn observedInboundRtp;\n\t}\n\n\tprivate _updateInboundTrackSample(stats: InboundTrackSample) {\n\t\tlet observedInboundTrack = this.observedInboundTracks.get(stats.id);\n\n\t\tif (!observedInboundTrack) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst inboundRtp = [ ...this.observedInboundRtps.values() ].find((inbRtp) => inbRtp.trackIdentifier === stats.id);\n\t\t\tconst mediaPlayout = inboundRtp ?\n\t\t\t\t[ ...this.observedMediaPlayouts.values() ].find((mp) => mp.id === inboundRtp.playoutId) : undefined;\n\n\t\t\tobservedInboundTrack = new ObservedInboundTrack(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis,\n\t\t\t\tinboundRtp,\n\t\t\t\tmediaPlayout,\n\t\t\t);\n\n\t\t\tobservedInboundTrack.update(stats);\n\n\t\t\tthis.observedInboundTracks.set(stats.id, observedInboundTrack);\n\t\t\tthis._notify('inbound-track-added', { ...this.eventScope, observedInboundTrack });\n\t\t} else {\n\t\t\tobservedInboundTrack.update(stats);\n\t\t}\n\t\tthis._notify('inbound-track-updated', { ...this.eventScope, observedInboundTrack });\n\n\t\treturn observedInboundTrack;\n\t}\n\n\tprivate _updateMediaPlayoutStats(stats: MediaPlayoutStats) {\n\t\tlet observedMediaPlayout = this.observedMediaPlayouts.get(stats.id);\n\n\t\tif (!observedMediaPlayout) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind OR trackIdentifier field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedMediaPlayout = new ObservedMediaPlayout(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedMediaPlayout.update(stats);\n\n\t\t\tthis.observedMediaPlayouts.set(stats.id, observedMediaPlayout);\n\t\t\tthis._notify('media-playout-added', { ...this.eventScope, observedMediaPlayout });\n\t\t} else {\n\t\t\tobservedMediaPlayout.update(stats);\n\t\t}\n\t\tthis._notify('media-playout-updated', { ...this.eventScope, observedMediaPlayout });\n\n\t\treturn observedMediaPlayout;\n\t}\n\n\tprivate _updateMediaSourceStats(stats: MediaSourceStats) {\n\t\tlet observedMediaSource = this.observedMediaSources.get(stats.id);\n\n\t\tif (!observedMediaSource) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedMediaSource = new ObservedMediaSource(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedMediaSource.update(stats);\n\n\t\t\tthis.observedMediaSources.set(stats.id, observedMediaSource);\n\t\t\tthis._notify('media-source-added', { ...this.eventScope, observedMediaSource });\n\t\t} else {\n\t\t\tobservedMediaSource.update(stats);\n\t\t}\n\t\tthis._notify('media-source-updated', { ...this.eventScope, observedMediaSource });\n\n\t\treturn observedMediaSource;\n\t}\n\n\tprivate _updateOutboundRtpStats(stats: OutboundRtpStats) {\n\t\tlet observedOutboundRtp = this.observedOutboundRtps.get(stats.ssrc);\n\n\t\tif (!observedOutboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid OutboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedOutboundRtp = new ObservedOutboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedOutboundRtp.update(stats);\n\n\t\t\tthis.observedOutboundRtps.set(stats.ssrc, observedOutboundRtp);\n\t\t\tthis._notify('outbound-rtp-added', { ...this.eventScope, observedOutboundRtp });\n\t\t} else {\n\t\t\tobservedOutboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('outbound-rtp-updated', { ...this.eventScope, observedOutboundRtp });\n\n\t\treturn observedOutboundRtp;\n\t}\n\n\tprivate _updateOutboundTrackSample(stats: OutboundTrackSample) {\n\t\tlet observedOutboundTrack = this.observedOutboundTracks.get(stats.id);\n\n\t\tif (!observedOutboundTrack) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid OutboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst observedMediaSource = [ ...this.observedMediaSources.values() ].find((mediaSource) => mediaSource.trackIdentifier === stats.id);\n\t\t\tconst outboundRtps = observedMediaSource\n\t\t\t\t? [ ...this.observedOutboundRtps.values() ].filter((outboundRtp) => outboundRtp.mediaSourceId === observedMediaSource?.id) : undefined;\n\n\t\t\tobservedOutboundTrack = new ObservedOutboundTrack(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis,\n\t\t\t\toutboundRtps,\n\t\t\t\tobservedMediaSource,\n\t\t\t);\n\n\t\t\tobservedOutboundTrack.update(stats);\n\n\t\t\tthis.observedOutboundTracks.set(stats.id, observedOutboundTrack);\n\t\t\tthis._notify('outbound-track-added', { ...this.eventScope, observedOutboundTrack });\n\t\t} else {\n\t\t\tobservedOutboundTrack.update(stats);\n\t\t}\n\t\tthis._notify('outbound-track-updated', { ...this.eventScope, observedOutboundTrack });\n\n\t\treturn observedOutboundTrack;\n\t}\n\n\tprivate _updatePeerConnectionTransportStats(stats: PeerConnectionTransportStats) {\n\t\tlet observedPeerConnectionTransport = this.observedPeerConnectionTransports.get(stats.id);\n\n\t\tif (!observedPeerConnectionTransport) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid PeerConnectionTransportStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedPeerConnectionTransport = new ObservedPeerConnectionTransport(stats.timestamp, stats.id, this);\n\n\t\t\tobservedPeerConnectionTransport.update(stats);\n\n\t\t\tthis.observedPeerConnectionTransports.set(stats.id, observedPeerConnectionTransport);\n\t\t\tthis._notify('peer-connection-transport-added', { ...this.eventScope, observedPeerConnectionTransport });\n\t\t} else {\n\t\t\tobservedPeerConnectionTransport.update(stats);\n\t\t}\n\t\tthis._notify('peer-connection-transport-updated', { ...this.eventScope, observedPeerConnectionTransport });\n\n\t\treturn observedPeerConnectionTransport;\n\t}\n\n\tprivate _updateRemoteInboundRtpStats(stats: RemoteInboundRtpStats) {\n\t\tlet observedRemoteInboundRtp = this.observedRemoteInboundRtps.get(stats.ssrc);\n\n\t\tif (!observedRemoteInboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid RemoteInboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedRemoteInboundRtp = new ObservedRemoteInboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedRemoteInboundRtp.update(stats);\n\n\t\t\tthis.observedRemoteInboundRtps.set(stats.ssrc, observedRemoteInboundRtp);\n\t\t\tthis._notify('remote-inbound-rtp-added', { ...this.eventScope, observedRemoteInboundRtp });\n\t\t} else {\n\t\t\tobservedRemoteInboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('remote-inbound-rtp-updated', { ...this.eventScope, observedRemoteInboundRtp });\n\n\t\treturn observedRemoteInboundRtp;\n\t}\n\n\tprivate _updateRemoteOutboundRtpStats(stats: RemoteOutboundRtpStats) {\n\t\tlet observedRemoteOutboundRtp = this.observedRemoteOutboundRtps.get(stats.ssrc);\n\n\t\tif (!observedRemoteOutboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid RemoteOutboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedRemoteOutboundRtp = new ObservedRemoteOutboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedRemoteOutboundRtp.update(stats);\n\n\t\t\tthis.observedRemoteOutboundRtps.set(stats.ssrc, observedRemoteOutboundRtp);\n\t\t\tthis._notify('remote-outbound-rtp-added', { ...this.eventScope, observedRemoteOutboundRtp });\n\t\t} else {\n\t\t\tobservedRemoteOutboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('remote-outbound-rtp-updated', { ...this.eventScope, observedRemoteOutboundRtp });\n\n\t\treturn observedRemoteOutboundRtp;\n\t}\n\n\t/** Emit an Observer-bus event scoped to this peer connection. */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.client.call.observer.emit(type, ...args);\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { InboundRtpStats } from './schema/ClientSample';\n\nexport class ObservedInboundRtp implements InboundRtpStats {\n\tpublic appData?: Record<string, unknown>;\n\n\tprivate _visited = false;\n\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsReceived?: number | undefined;\n\tpacketsLost?: number | undefined;\n\tmid?: string | undefined;\n\tremoteId?: string | undefined;\n\tframesDecoded?: number | undefined;\n\tkeyFramesDecoded?: number | undefined;\n\tframesRendered?: number | undefined;\n\tframesDropped?: number | undefined;\n\tframeWidth?: number | undefined;\n\tframeHeight?: number | undefined;\n\tframesPerSecond?: number | undefined;\n\tqpSum?: number | undefined;\n\ttotalDecodeTime?: number | undefined;\n\ttotalInterFrameDelay?: number | undefined;\n\ttotalSquaredInterFrameDelay?: number | undefined;\n\tpauseCount?: number | undefined;\n\ttotalPausesDuration?: number | undefined;\n\tfreezeCount?: number | undefined;\n\ttotalFreezesDuration?: number | undefined;\n\tlastPacketReceivedTimestamp?: number | undefined;\n\theaderBytesReceived?: number | undefined;\n\tpacketsDiscarded?: number | undefined;\n\tfecBytesReceived?: number | undefined;\n\tfecPacketsReceived?: number | undefined;\n\tfecPacketsDiscarded?: number | undefined;\n\tbytesReceived?: number | undefined;\n\tnackCount?: number | undefined;\n\tfirCount?: number | undefined;\n\tpliCount?: number | undefined;\n\ttotalProcessingDelay?: number | undefined;\n\testimatedPlayoutTimestamp?: number | undefined;\n\tjitterBufferDelay?: number | undefined;\n\tjitterBufferTargetDelay?: number | undefined;\n\tjitterBufferEmittedCount?: number | undefined;\n\tjitterBufferMinimumDelay?: number | undefined;\n\ttotalSamplesReceived?: number | undefined;\n\tconcealedSamples?: number | undefined;\n\tsilentConcealedSamples?: number | undefined;\n\tconcealmentEvents?: number | undefined;\n\tinsertedSamplesForDeceleration?: number | undefined;\n\tremovedSamplesForAcceleration?: number | undefined;\n\taudioLevel?: number | undefined;\n\ttotalAudioEnergy?: number | undefined;\n\ttotalSamplesDuration?: number | undefined;\n\tframesReceived?: number | undefined;\n\tdecoderImplementation?: string | undefined;\n\tplayoutId?: string | undefined;\n\tpowerEfficientDecoder?: boolean | undefined;\n\tframesAssembledFromMultiplePackets?: number | undefined;\n\ttotalAssemblyTime?: number | undefined;\n\tretransmittedPacketsReceived?: number | undefined;\n\tretransmittedBytesReceived?: number | undefined;\n\trtxSsrc?: number | undefined;\n\tfecSsrc?: number | undefined;\n\ttotalCorruptionProbability?: number | undefined;\n\ttotalSquaredCorruptionProbability?: number | undefined;\n\tcorruptionMeasurements?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\tjitter?: number | undefined;\n\t\n\tpublic bitrate = 0;\n\tpublic fractionLost?: number;\n\tpublic bitPerPixel = 0;\n\n\tpublic deltaLostPackets = 0;\n\tpublic deltaReceivedPackets = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaReceivedSamples = 0;\n\tpublic deltaSilentConcealedSamples = 0;\n\n\t// Derived from the corresponding remote-outbound-rtp (sender report), when present.\n\tpublic remoteRttInMs?: number;\n\tpublic remoteBytesSent?: number;\n\tpublic remotePacketsSent?: number;\n\tpublic remoteTimestamp?: number;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tpublic trackIdentifier: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getRemoteOutboundRtp() {\n\t\treturn this._peerConnection.observedRemoteOutboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic getMediaPlayout() {\n\t\treturn this._peerConnection.observedMediaPlayouts.get(this.playoutId ?? '');\n\t}\n\n\tpublic getTrack() {\n\t\treturn this._peerConnection.observedInboundTracks.get(this.trackIdentifier);\n\t}\n\n\tpublic update(stats: InboundRtpStats) {\n\t\tthis._visited = true;\n\t\tthis.deltaBytesReceived = 0;\n\t\tthis.deltaLostPackets = 0;\n\t\tthis.deltaReceivedPackets = 0;\n\t\tthis.deltaReceivedSamples = 0;\n\t\tthis.deltaSilentConcealedSamples = 0;\n\t\tthis.remoteRttInMs = undefined;\n\t\tthis.remoteBytesSent = undefined;\n\t\tthis.remotePacketsSent = undefined;\n\t\tthis.remoteTimestamp = undefined;\n\t\tthis.bitrate = 0;\n\t\tthis.jitter = undefined;\n\t\tthis.fractionLost = undefined;\n\t\tthis.bitPerPixel = 0;\n\n\t\tconst elapsedTimeInMs = stats.timestamp - this.timestamp;\n\n\t\tif (elapsedTimeInMs) {\n\t\t\t// update metrics here\n\t\t\tif (this.bytesReceived && stats.bytesReceived && this.bytesReceived < stats.bytesReceived) {\n\t\t\t\tthis.bitrate = ((stats.bytesReceived - (this.bytesReceived ?? 0)) * 8) / elapsedTimeInMs;\n\t\t\t}\n\t\t\tif (this.packetsLost && stats.packetsLost && this.packetsLost < stats.packetsLost) {\n\t\t\t\tthis.deltaLostPackets = stats.packetsLost - this.packetsLost;\n\t\t\t}\n\t\t\tif (this.packetsReceived && stats.packetsReceived && this.packetsReceived < stats.packetsReceived) {\n\t\t\t\tthis.deltaReceivedPackets = stats.packetsReceived - this.packetsReceived;\n\t\t\t}\n\t\t\tif (this.totalSamplesReceived && stats.totalSamplesReceived && this.totalSamplesReceived < stats.totalSamplesReceived) {\n\t\t\t\tthis.deltaReceivedSamples = stats.totalSamplesReceived - this.totalSamplesReceived;\n\t\t\t}\n\t\t\tif (this.silentConcealedSamples && stats.silentConcealedSamples && this.silentConcealedSamples < stats.silentConcealedSamples) {\n\t\t\t\tthis.deltaSilentConcealedSamples = stats.silentConcealedSamples - this.silentConcealedSamples;\n\t\t\t}\n\t\t\tif (stats.bytesReceived && this.framesReceived && stats.framesReceived && this.framesReceived < stats.framesReceived) {\n\t\t\t\tthis.bitPerPixel = (stats.bytesReceived - (this.bytesReceived ?? 0)) / (stats.framesReceived - this.framesReceived);\n\t\t\t}\n\t\t\tif (this.deltaLostPackets && this.deltaReceivedPackets) {\n\t\t\t\tthis.fractionLost = this.deltaLostPackets / (this.deltaLostPackets + this.deltaReceivedPackets);\n\t\t\t}\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.packetsLost = stats.packetsLost;\n\t\tthis.mid = stats.mid;\n\t\tthis.remoteId = stats.remoteId;\n\t\tthis.framesDecoded = stats.framesDecoded;\n\t\tthis.keyFramesDecoded = stats.keyFramesDecoded;\n\t\tthis.framesRendered = stats.framesRendered;\n\t\tthis.framesDropped = stats.framesDropped;\n\t\tthis.frameWidth = stats.frameWidth;\n\t\tthis.frameHeight = stats.frameHeight;\n\t\tthis.framesPerSecond = stats.framesPerSecond;\n\t\tthis.qpSum = stats.qpSum;\n\t\tthis.totalDecodeTime = stats.totalDecodeTime;\n\t\tthis.totalInterFrameDelay = stats.totalInterFrameDelay;\n\t\tthis.totalSquaredInterFrameDelay = stats.totalSquaredInterFrameDelay;\n\t\tthis.pauseCount = stats.pauseCount;\n\t\tthis.totalPausesDuration = stats.totalPausesDuration;\n\t\tthis.freezeCount = stats.freezeCount;\n\t\tthis.totalFreezesDuration = stats.totalFreezesDuration;\n\t\tthis.lastPacketReceivedTimestamp = stats.lastPacketReceivedTimestamp;\n\t\tthis.headerBytesReceived = stats.headerBytesReceived;\n\t\tthis.packetsDiscarded = stats.packetsDiscarded;\n\t\tthis.fecBytesReceived = stats.fecBytesReceived;\n\t\tthis.fecPacketsReceived = stats.fecPacketsReceived;\n\t\tthis.fecPacketsDiscarded = stats.fecPacketsDiscarded;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.nackCount = stats.nackCount;\n\t\tthis.firCount = stats.firCount;\n\t\tthis.pliCount = stats.pliCount;\n\t\tthis.totalProcessingDelay = stats.totalProcessingDelay;\n\t\tthis.estimatedPlayoutTimestamp = stats.estimatedPlayoutTimestamp;\n\t\tthis.jitterBufferDelay = stats.jitterBufferDelay;\n\t\tthis.jitterBufferTargetDelay = stats.jitterBufferTargetDelay;\n\t\tthis.jitterBufferEmittedCount = stats.jitterBufferEmittedCount;\n\t\tthis.jitterBufferMinimumDelay = stats.jitterBufferMinimumDelay;\n\t\tthis.totalSamplesReceived = stats.totalSamplesReceived;\n\t\tthis.concealedSamples = stats.concealedSamples;\n\t\tthis.silentConcealedSamples = stats.silentConcealedSamples;\n\t\tthis.concealmentEvents = stats.concealmentEvents;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { OutboundRtpStats, QualityLimitationDurations } from './schema/ClientSample';\n\nexport class ObservedOutboundRtp implements OutboundRtpStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsSent?: number | undefined;\n\tbytesSent?: number | undefined;\n\tmid?: string | undefined;\n\tmediaSourceId?: string | undefined;\n\tremoteId?: string | undefined;\n\trid?: string | undefined;\n\theaderBytesSent?: number | undefined;\n\tretransmittedPacketsSent?: number | undefined;\n\tretransmittedBytesSent?: number | undefined;\n\trtxSsrc?: number | undefined;\n\ttargetBitrate?: number | undefined;\n\ttotalEncodedBytesTarget?: number | undefined;\n\tframeWidth?: number | undefined;\n\tframeHeight?: number | undefined;\n\tframesPerSecond?: number | undefined;\n\tframesSent?: number | undefined;\n\thugeFramesSent?: number | undefined;\n\tframesEncoded?: number | undefined;\n\tkeyFramesEncoded?: number | undefined;\n\tqpSum?: number | undefined;\n\ttotalEncodeTime?: number | undefined;\n\ttotalPacketSendDelay?: number | undefined;\n\tqualityLimitationReason?: string | undefined;\n\tqualityLimitationResolutionChanges?: number | undefined;\n\tnackCount?: number | undefined;\n\tfirCount?: number | undefined;\n\tpliCount?: number | undefined;\n\tencoderImplementation?: string | undefined;\n\tpowerEfficientEncoder?: boolean | undefined;\n\tactive?: boolean | undefined;\n\tscalabilityMode?: string | undefined;\n\tqualityLimitationDurations?: QualityLimitationDurations | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\t// derived fields\n\tpublic bitrate = 0;\n\tpublic payloadBitrate = 0;\n\tpublic packetRate = 0;\n\tpublic bitPerPixel = 0;\n\t\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaBytesSent = 0;\n\n\t// Derived from the corresponding remote-inbound-rtp (receiver report), when present.\n\tpublic remoteRttInMs?: number;\n\tpublic remoteFractionLost?: number;\n\tpublic remoteJitter?: number;\n\tpublic remotePacketsLost?: number;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t) {\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\t\n\t\tthis._visited = false;\n\t\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getRemoteInboundRtp() {\n\t\treturn this._peerConnection.observedRemoteInboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic getMediaSource() {\n\t\treturn this._peerConnection.observedMediaSources.get(this.mediaSourceId ?? '');\n\t}\n\n\tpublic getTrack() {\n\t\treturn this.getMediaSource()?.getTrack();\n\t}\n\n\tpublic update(stats: OutboundRtpStats) {\n\t\tthis._visited = true;\n\t\tthis.bitPerPixel = 0;\n\t\tthis.bitrate = 0;\n\t\tthis.payloadBitrate = 0;\n\t\tthis.packetRate = 0;\n\t\tthis.deltaPacketsSent = 0;\n\t\tthis.deltaBytesSent = 0;\n\t\tthis.remoteRttInMs = undefined;\n\t\tthis.remoteFractionLost = undefined;\n\t\tthis.remoteJitter = undefined;\n\t\tthis.remotePacketsLost = undefined;\n\n\t\tconst elapsedTimeInMs = stats.timestamp - this.timestamp;\n\n\t\tif (elapsedTimeInMs) {\n\t\t\t// Guard against counter resets / SSRC reuse: only accept a non-negative delta.\n\t\t\tif (stats.packetsSent !== undefined && this.packetsSent !== undefined && stats.packetsSent >= this.packetsSent) {\n\t\t\t\tthis.deltaPacketsSent = stats.packetsSent - this.packetsSent;\n\t\t\t\tthis.packetRate = this.deltaPacketsSent / (elapsedTimeInMs / 1000);\n\t\t\t}\n\t\t\tif (stats.bytesSent !== undefined && this.bytesSent !== undefined && stats.bytesSent >= this.bytesSent) {\n\t\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t\t\tthis.bitrate = (this.deltaBytesSent * 8) / (elapsedTimeInMs / 1000);\n\t\t\t}\n\t\t\tif (stats.headerBytesSent !== undefined && this.headerBytesSent !== undefined) {\n\t\t\t\tthis.payloadBitrate = ((this.deltaBytesSent ?? 0 - (stats.headerBytesSent - this.headerBytesSent)) * 8) / (elapsedTimeInMs / 1000);\n\t\t\t}\n\t\t\tif (this.framesSent !== undefined && stats.framesSent !== undefined) {\n\t\t\t\tthis.bitPerPixel = this.deltaBytesSent ? (this.deltaBytesSent * 8) / (this.framesSent - stats.framesSent) : 0;\n\t\t\t}\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.mid = stats.mid;\n\t\tthis.mediaSourceId = stats.mediaSourceId;\n\t\tthis.remoteId = stats.remoteId;\n\t\tthis.rid = stats.rid;\n\t\tthis.headerBytesSent = stats.headerBytesSent;\n\t\tthis.retransmittedPacketsSent = stats.retransmittedPacketsSent;\n\t\tthis.retransmittedBytesSent = stats.retransmittedBytesSent;\n\t\tthis.rtxSsrc = stats.rtxSsrc;\n\t\tthis.targetBitrate = stats.targetBitrate;\n\t\tthis.totalEncodedBytesTarget = stats.totalEncodedBytesTarget;\n\t\tthis.frameWidth = stats.frameWidth;\n\t\tthis.frameHeight = stats.frameHeight;\n\t\tthis.framesPerSecond = stats.framesPerSecond;\n\t\tthis.framesSent = stats.framesSent;\n\t\tthis.hugeFramesSent = stats.hugeFramesSent;\n\t\tthis.framesEncoded = stats.framesEncoded;\n\t\tthis.keyFramesEncoded = stats.keyFramesEncoded;\n\t\tthis.qpSum = stats.qpSum;\n\t\tthis.totalEncodeTime = stats.totalEncodeTime;\n\t\tthis.totalPacketSendDelay = stats.totalPacketSendDelay;\n\t\tthis.qualityLimitationReason = stats.qualityLimitationReason;\n\t\tthis.qualityLimitationResolutionChanges = stats.qualityLimitationResolutionChanges;\n\t\tthis.nackCount = stats.nackCount;\n\t\tthis.firCount = stats.firCount;\n\t\tthis.pliCount = stats.pliCount;\n\t\tthis.encoderImplementation = stats.encoderImplementation;\n\t\tthis.powerEfficientEncoder = stats.powerEfficientEncoder;\n\t\tthis.active = stats.active;\n\t\tthis.scalabilityMode = stats.scalabilityMode;\n\t\tthis.qualityLimitationDurations = stats.qualityLimitationDurations;\n\t\tthis.attachments = stats.attachments;\n\t}\n}","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { CertificateStats } from './schema/ClientSample';\n\nexport class ObservedCertificate implements CertificateStats {\n\tpublic appData?: Record<string, unknown>;\n\n\tprivate _visited = false;\n\n\tfingerprint?: string;\n\tfingerprintAlgorithm?: string;\n\tbase64Certificate?: string;\n\tissuerCertificateId?: string;\n\tattachments?: Record<string, unknown>;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: CertificateStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.fingerprint = stats.fingerprint;\n\t\tthis.fingerprintAlgorithm = stats.fingerprintAlgorithm;\n\t\tthis.base64Certificate = stats.base64Certificate;\n\t\tthis.issuerCertificateId = stats.issuerCertificateId;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { CodecStats } from './schema/ClientSample';\n\nexport class ObservedCodec implements CodecStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tpayloadType?: number | undefined;\n\ttransportId?: string | undefined;\n\tclockRate?: number | undefined;\n\tchannels?: number | undefined;\n\tsdpFmtpLine?: string | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic mimeType: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic update(stats: CodecStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.payloadType = stats.payloadType;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.clockRate = stats.clockRate;\n\t\tthis.channels = stats.channels;\n\t\tthis.sdpFmtpLine = stats.sdpFmtpLine;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { DataChannelStats } from './schema/ClientSample';\n\nexport type ObservedDataChannelState = 'connecting' | 'open' | 'closing' | 'closed';\n\nexport class ObservedDataChannel implements DataChannelStats\t{\n\tprivate _visited = false;\n\t\n\tlabel?: string | undefined;\n\tprotocol?: string | undefined;\n\tdataChannelIdentifier?: number | undefined;\n\tstate?: string | undefined;\n\tmessagesSent?: number | undefined;\n\tbytesSent?: number | undefined;\n\tmessagesReceived?: number | undefined;\n\tbytesReceived?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic addedAt?: number | undefined;\n\tpublic removedAt?: number | undefined;\n\t\n\tpublic deltaBytesSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaMessagesSent = 0;\n\tpublic deltaMessagesReceived = 0;\n\n\tpublic appData?: Record<string, unknown>;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t) {\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\t\n\t\tthis._visited = false;\n\t\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: DataChannelStats) {\n\t\tthis._visited = true;\n\n\t\tif (this.messagesSent && stats.messagesSent && stats.messagesSent >= this.messagesSent) {\n\t\t\tthis.deltaMessagesSent = stats.messagesSent - this.messagesSent;\n\t\t} else {\n\t\t\tthis.deltaMessagesSent = 0;\n\t\t}\n\n\t\tif (this.messagesReceived && stats.messagesReceived && stats.messagesReceived >= this.messagesReceived) {\n\t\t\tthis.deltaMessagesReceived = stats.messagesReceived - this.messagesReceived;\n\t\t} else {\n\t\t\tthis.deltaMessagesReceived = 0;\n\t\t}\n\n\t\tif (this.bytesSent && stats.bytesSent && stats.bytesSent >= this.bytesSent) {\n\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t} else {\n\t\t\tthis.deltaBytesSent = 0;\n\t\t}\n\n\t\tif (this.bytesReceived && stats.bytesReceived && stats.bytesReceived >= this.bytesReceived) {\n\t\t\tthis.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;\n\t\t} else {\n\t\t\tthis.deltaBytesReceived = 0;\n\t\t}\n\n\t\tthis.label = stats.label;\n\t\tthis.protocol = stats.protocol;\n\t\tthis.dataChannelIdentifier = stats.dataChannelIdentifier;\n\t\tthis.state = stats.state;\n\t\tthis.messagesSent = stats.messagesSent;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.messagesReceived = stats.messagesReceived;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { IceCandidateStats } from './schema/ClientSample';\n\nexport class ObservedIceCandidate implements IceCandidateStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\taddress?: string | undefined;\n\tport?: number | undefined;\n\tprotocol?: string | undefined;\n\tcandidateType?: string | undefined;\n\tpriority?: number | undefined;\n\turl?: string | undefined;\n\trelayProtocol?: string | undefined;\n\tfoundation?: string | undefined;\n\trelatedAddress?: string | undefined;\n\trelatedPort?: number | undefined;\n\tusernameFragment?: string | undefined;\n\ttcpType?: string | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic update(stats: IceCandidateStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.address = stats.address;\n\t\tthis.port = stats.port;\n\t\tthis.protocol = stats.protocol;\n\t\tthis.candidateType = stats.candidateType;\n\t\tthis.priority = stats.priority;\n\t\tthis.url = stats.url;\n\t\tthis.relayProtocol = stats.relayProtocol;\n\t\tthis.foundation = stats.foundation;\n\t\tthis.relatedAddress = stats.relatedAddress;\n\t\tthis.relatedPort = stats.relatedPort;\n\t\tthis.usernameFragment = stats.usernameFragment;\n\t\tthis.tcpType = stats.tcpType;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { IceCandidatePairStats } from './schema/ClientSample';\n\nexport class ObservedIceCandidatePair implements IceCandidatePairStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\tlocalCandidateId?: string | undefined;\n\tremoteCandidateId?: string | undefined;\n\tstate?: 'new' | 'in-progress' | 'waiting' | 'failed' | 'succeeded' | undefined;\n\tnominated?: boolean | undefined;\n\tpacketsSent?: number | undefined;\n\tpacketsReceived?: number | undefined;\n\tbytesSent?: number | undefined;\n\tbytesReceived?: number | undefined;\n\tlastPacketSentTimestamp?: number | undefined;\n\tlastPacketReceivedTimestamp?: number | undefined;\n\ttotalRoundTripTime?: number | undefined;\n\tcurrentRoundTripTime?: number | undefined;\n\tavailableOutgoingBitrate?: number | undefined;\n\tavailableIncomingBitrate?: number | undefined;\n\trequestsReceived?: number | undefined;\n\trequestsSent?: number | undefined;\n\tresponsesReceived?: number | undefined;\n\tresponsesSent?: number | undefined;\n\tconsentRequestsSent?: number | undefined;\n\tpacketsDiscardedOnSend?: number | undefined;\n\tbytesDiscardedOnSend?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic deltaBytesSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaPacketsReceived = 0;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t) {\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\t\n\t\tthis._visited = false;\n\t\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic getLocalCandidate() {\n\t\treturn this._peerConnection.observedIceCandidates.get(this.localCandidateId ?? '');\n\t}\n\n\tpublic getRemoteCandidate() {\n\t\treturn this._peerConnection.observedIceCandidates.get(this.remoteCandidateId ?? '');\n\t}\n\n\tpublic update(stats: IceCandidatePairStats) {\n\t\tthis._visited = true;\n\n\t\tif (this.packetsSent && stats.packetsSent && stats.packetsSent >= this.packetsSent) {\n\t\t\tthis.deltaPacketsSent = stats.packetsSent - this.packetsSent;\n\t\t} else {\n\t\t\tthis.deltaPacketsSent = 0;\n\t\t}\n\t\tif (this.packetsReceived && stats.packetsReceived && stats.packetsReceived >= this.packetsReceived) {\n\t\t\tthis.deltaPacketsReceived = stats.packetsReceived - this.packetsReceived;\n\t\t} else {\n\t\t\tthis.deltaPacketsReceived = 0;\n\t\t}\n\t\tif (this.bytesSent && stats.bytesSent && stats.bytesSent >= this.bytesSent) {\n\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t} else {\n\t\t\tthis.deltaBytesSent = 0;\n\t\t}\n\t\tif (this.bytesReceived && stats.bytesReceived && stats.bytesReceived >= this.bytesReceived) {\n\t\t\tthis.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;\n\t\t} else {\n\t\t\tthis.deltaBytesReceived = 0;\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.localCandidateId = stats.localCandidateId;\n\t\tthis.remoteCandidateId = stats.remoteCandidateId;\n\t\tthis.state = this._convertState(stats.state);\n\t\tthis.nominated = stats.nominated;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.lastPacketSentTimestamp = stats.lastPacketSentTimestamp;\n\t\tthis.lastPacketReceivedTimestamp = stats.lastPacketReceivedTimestamp;\n\t\tthis.totalRoundTripTime = stats.totalRoundTripTime;\n\t\tthis.currentRoundTripTime = stats.currentRoundTripTime;\n\t\tthis.availableOutgoingBitrate = stats.availableOutgoingBitrate;\n\t\tthis.availableIncomingBitrate = stats.availableIncomingBitrate;\n\t\tthis.requestsReceived = stats.requestsReceived;\n\t\tthis.requestsSent = stats.requestsSent;\n\t\tthis.responsesReceived = stats.responsesReceived;\n\t\tthis.responsesSent = stats.responsesSent;\n\t\tthis.consentRequestsSent = stats.consentRequestsSent;\n\t\tthis.packetsDiscardedOnSend = stats.packetsDiscardedOnSend;\n\t\tthis.bytesDiscardedOnSend = stats.bytesDiscardedOnSend;\n\t\tthis.attachments = stats.attachments;\n\t}\n\n\tprivate _convertState(state: string | undefined) {\n\t\tswitch (state) {\n\t\t\tcase 'new':\n\t\t\tcase 'in-progress':\n\t\t\tcase 'waiting':\n\t\t\tcase 'failed':\n\t\t\tcase 'succeeded':\n\t\t\t\treturn state;\n\t\t\tcase 'cancelled':\n\t\t\t\treturn 'failed';\n\t\t\tcase 'inprogress':\n\t\t\t\treturn 'in-progress';\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t}\n\t}\n}","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { IceTransportStats } from './schema/ClientSample';\n\nexport class ObservedIceTransport implements IceTransportStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tpacketsSent?: number | undefined;\n\tpacketsReceived?: number | undefined;\n\tbytesSent?: number | undefined;\n\tbytesReceived?: number | undefined;\n\ticeRole?: string | undefined;\n\ticeLocalUsernameFragment?: string | undefined;\n\tdtlsState?: string | undefined;\n\ticeState?: string | undefined;\n\tselectedCandidatePairId?: string | undefined;\n\tlocalCertificateId?: string | undefined;\n\tremoteCertificateId?: string | undefined;\n\ttlsVersion?: string | undefined;\n\tdtlsCipher?: string | undefined;\n\tdtlsRole?: string | undefined;\n\tsrtpCipher?: string | undefined;\n\tselectedCandidatePairChanges?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic deltaPacketsReceived = 0;\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaBytesSent = 0;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getSelectedCandidatePair() {\n\t\treturn this._peerConnection.observedIceCandidatesPair.get(this.selectedCandidatePairId ?? '');\n\t}\n\n\tpublic update(stats: IceTransportStats) {\n\t\tthis._visited = true;\n\n\t\tif (this.bytesReceived !== undefined && stats.bytesReceived !== undefined && this.bytesReceived <= stats.bytesReceived) {\n\t\t\tthis.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;\n\t\t} else {\n\t\t\tthis.deltaBytesReceived = 0;\n\t\t}\n\t\t\n\t\tif (this.bytesSent !== undefined && stats.bytesSent !== undefined && this.bytesSent <= stats.bytesSent) {\n\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t} else {\n\t\t\tthis.deltaBytesSent = 0;\n\t\t}\n\n\t\tif (this.packetsReceived !== undefined && stats.packetsReceived !== undefined && this.packetsReceived <= stats.packetsReceived) {\n\t\t\tthis.deltaPacketsReceived = stats.packetsReceived - this.packetsReceived;\n\t\t} else {\n\t\t\tthis.deltaPacketsReceived = 0;\n\t\t}\n\t\t\n\t\tif (this.packetsSent !== undefined && stats.packetsSent !== undefined && this.packetsSent <= stats.packetsSent) {\n\t\t\tthis.deltaPacketsSent = stats.packetsSent - this.packetsSent;\n\t\t} else {\n\t\t\tthis.deltaPacketsSent = 0;\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.iceRole = stats.iceRole;\n\t\tthis.iceLocalUsernameFragment = stats.iceLocalUsernameFragment;\n\t\tthis.dtlsState = stats.dtlsState;\n\t\tthis.iceState = stats.iceState;\n\t\tthis.selectedCandidatePairId = stats.selectedCandidatePairId;\n\t\tthis.localCertificateId = stats.localCertificateId;\n\t\tthis.remoteCertificateId = stats.remoteCertificateId;\n\t\tthis.tlsVersion = stats.tlsVersion;\n\t\tthis.dtlsCipher = stats.dtlsCipher;\n\t\tthis.dtlsRole = stats.dtlsRole;\n\t\tthis.srtpCipher = stats.srtpCipher;\n\t\tthis.selectedCandidatePairChanges = stats.selectedCandidatePairChanges;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { MediaSourceStats } from './schema/ClientSample';\n\nexport class ObservedMediaSource implements MediaSourceStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttrackIdentifier?: string | undefined;\n\taudioLevel?: number | undefined;\n\ttotalAudioEnergy?: number | undefined;\n\ttotalSamplesDuration?: number | undefined;\n\techoReturnLoss?: number | undefined;\n\techoReturnLossEnhancement?: number | undefined;\n\twidth?: number | undefined;\n\theight?: number | undefined;\n\tframes?: number | undefined;\n\tframesPerSecond?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getTrack() {\n\t\treturn this._peerConnection.observedOutboundTracks.get(this.trackIdentifier ?? '');\n\t}\n\n\tpublic update(stats: MediaSourceStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.trackIdentifier = stats.trackIdentifier;\n\t\tthis.audioLevel = stats.audioLevel;\n\t\tthis.totalAudioEnergy = stats.totalAudioEnergy;\n\t\tthis.totalSamplesDuration = stats.totalSamplesDuration;\n\t\tthis.echoReturnLoss = stats.echoReturnLoss;\n\t\tthis.echoReturnLossEnhancement = stats.echoReturnLossEnhancement;\n\t\tthis.width = stats.width;\n\t\tthis.height = stats.height;\n\t\tthis.frames = stats.frames;\n\t\tthis.framesPerSecond = stats.framesPerSecond;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { PeerConnectionTransportStats } from './schema/ClientSample';\n\nexport class ObservedPeerConnectionTransport implements PeerConnectionTransportStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tdataChannelsOpened?: number | undefined;\n\tdataChannelsClosed?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: PeerConnectionTransportStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.dataChannelsOpened = stats.dataChannelsOpened;\n\t\tthis.dataChannelsClosed = stats.dataChannelsClosed;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { MediaPlayoutStats } from './schema/ClientSample';\n\nexport class ObservedMediaPlayout implements MediaPlayoutStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tsynthesizedSamplesDuration?: number | undefined;\n\tsynthesizedSamplesEvents?: number | undefined;\n\ttotalSamplesDuration?: number | undefined;\n\ttotalPlayoutDelay?: number | undefined;\n\ttotalSamplesCount?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: MediaPlayoutStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.synthesizedSamplesDuration = stats.synthesizedSamplesDuration;\n\t\tthis.synthesizedSamplesEvents = stats.synthesizedSamplesEvents;\n\t\tthis.totalSamplesDuration = stats.totalSamplesDuration;\n\t\tthis.totalPlayoutDelay = stats.totalPlayoutDelay;\n\t\tthis.totalSamplesCount = stats.totalSamplesCount;\n\t\tthis.attachments = stats.attachments;\n\t\t\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { RemoteInboundRtpStats } from './schema/ClientSample';\n\nexport class ObservedRemoteInboundRtp implements RemoteInboundRtpStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsReceived?: number | undefined;\n\tpacketsLost?: number | undefined;\n\tjitter?: number | undefined;\n\tlocalId?: string | undefined;\n\troundTripTime?: number | undefined;\n\ttotalRoundTripTime?: number | undefined;\n\tfractionLost?: number | undefined;\n\troundTripTimeMeasurements?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getOutboundRtp() {\n\t\treturn this._peerConnection.observedOutboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic update(stats: RemoteInboundRtpStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.packetsLost = stats.packetsLost;\n\t\tthis.jitter = stats.jitter;\n\t\tthis.localId = stats.localId;\n\t\tthis.roundTripTime = stats.roundTripTime;\n\t\tthis.totalRoundTripTime = stats.totalRoundTripTime;\n\t\tthis.fractionLost = stats.fractionLost;\n\t\tthis.roundTripTimeMeasurements = stats.roundTripTimeMeasurements;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { RemoteOutboundRtpStats } from './schema/ClientSample';\n\nexport class ObservedRemoteOutboundRtp implements RemoteOutboundRtpStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsSent?: number | undefined;\n\tbytesSent?: number | undefined;\n\tlocalId?: string | undefined;\n\tremoteTimestamp?: number | undefined;\n\treportsSent?: number | undefined;\n\troundTripTime?: number | undefined;\n\ttotalRoundTripTime?: number | undefined;\n\troundTripTimeMeasurements?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getInboundRtp() {\n\t\treturn this._peerConnection.observedInboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic update(stats: RemoteOutboundRtpStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.localId = stats.localId;\n\t\tthis.remoteTimestamp = stats.remoteTimestamp;\n\t\tthis.reportsSent = stats.reportsSent;\n\t\tthis.roundTripTime = stats.roundTripTime;\n\t\tthis.totalRoundTripTime = stats.totalRoundTripTime;\n\t\tthis.roundTripTimeMeasurements = stats.roundTripTimeMeasurements;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { CalculatedScore } from './scores/CalculatedScore';\nimport { MediaKind } from './common/types';\nimport { InboundTrackSample } from './schema/ClientSample';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedInboundRtp } from './ObservedInboundRtp';\nimport { ObservedMediaPlayout } from './ObservedMediaPlayout';\nimport { ObservedOutboundTrack } from './ObservedOutboundTrack';\n\nexport class ObservedInboundTrack implements InboundTrackSample {\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\tpublic appData?: Record<string, unknown>;\n\tpublic remoteOutboundTrack?: ObservedOutboundTrack | undefined;\n\n\tprivate _visited = false;\n\n\tpublic addedAt?: number | undefined;\n\tpublic removedAt?: number | undefined;\n\n\tpublic muted?: boolean;\n\n\tattachments?: Record<string, unknown> | undefined;\n\n\tconstructor(\n\t\tpublic timestamp: number,\n\t\tpublic readonly id: string,\n\t\tpublic readonly kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t\tprivate readonly _inboundRtp?: ObservedInboundRtp,\n\t\tprivate readonly _mediaPlayout?: ObservedMediaPlayout,\n\t) {\n\t\t// no-op\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getInboundRtp() {\n\t\treturn this._inboundRtp;\n\t}\n\n\tpublic getMediaPlayout() {\n\t\treturn this._mediaPlayout;\n\t}\n\n\tpublic update(stats: InboundTrackSample): void {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.calculatedScore.value = stats.score;\n\t\tthis.attachments = stats.attachments;\n\t}\n}","import { CalculatedScore } from './scores/CalculatedScore';\nimport { MediaKind } from './common/types';\nimport { OutboundTrackSample } from './schema/ClientSample';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedOutboundRtp } from './ObservedOutboundRtp';\nimport { ObservedMediaSource } from './ObservedMediaSource';\nimport { ObservedInboundTrack } from './ObservedInboundTrack';\n\nexport class ObservedOutboundTrack implements OutboundTrackSample {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tpublic readonly remoteInboundTracks = new Set<ObservedInboundTrack>();\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\n\tpublic addedAt?: number | undefined;\n\tpublic removedAt?: number | undefined;\n\n\tpublic muted?: boolean;\n\n\tattachments?: Record<string, unknown> | undefined;\n\n\tconstructor(\n\t\tpublic timestamp: number,\n\t\tpublic readonly id: string,\n\t\tpublic readonly kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t\tprivate readonly _outboundRtps?: ObservedOutboundRtp[],\n\t\tprivate readonly _mediaSource?: ObservedMediaSource,\n\t) {\n\t\t// no-op\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getOutboundRtps() {\n\t\treturn this._outboundRtps;\n\t}\n\n\tpublic getMediaSource() {\n\t\treturn this._mediaSource;\n\t}\n\n\tpublic update(stats: OutboundTrackSample): void {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.calculatedScore.value = stats.score;\n\t\tthis.attachments = stats.attachments;\n\t}\n}","export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\nexport type Writable<T> = T extends object ? { -readonly [K in keyof T]: Writable<T[K]> } : T;\n\nexport function iteratorConverter<T>(generator: Generator<T, void, undefined>): IterableIterator<T> {\n\treturn {\n\t\t[Symbol.iterator](): IterableIterator<T> {\n\t\t\treturn this;\n\t\t},\n\t\tnext(): IteratorResult<T> {\n\t\t\treturn generator.next();\n\t\t},\n\t};\n}\n\nexport function asyncIteratorConverter<T>(generator: AsyncGenerator<T, void, undefined>): AsyncIterableIterator<T> {\n\treturn {\n\t\t[Symbol.asyncIterator](): AsyncIterableIterator<T> {\n\t\t\treturn this;\n\t\t},\n\t\tnext(): Promise<IteratorResult<T>> {\n\t\t\treturn generator.next();\n\t\t},\n\t};\n}\n\nexport function isValidUuid(str: string): boolean {\n\tconst regexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n\treturn regexp.test(str);\n}\n\nexport function getAverage(arr: number[], defaultAvgIfArrLengthIs0 = 0): number {\n\tif (arr.length === 0) return defaultAvgIfArrLengthIs0;\n\t\n\treturn arr.reduce((a, b) => a + b, 0) / arr.length;\n}\n\nexport function getMedian(arr: number[], copyArrayForSorting = true): number {\n\t// Sort the array in ascending order\n\tconst sortedArr = copyArrayForSorting \n\t\t? arr.slice().sort((a, b) => a - b)\n\t\t: arr.sort((a, b) => a-b)\n\n\t;\n\n\t// Calculate the middle index\n\tconst mid = Math.floor(sortedArr.length / 2);\n\n\t// If the array length is odd, return the middle element\n\tif (sortedArr.length % 2 !== 0) {\n\t\treturn sortedArr[mid];\n\t}\n\n\t// If the array length is even, return the average of the two middle elements\n\treturn (sortedArr[mid - 1] + sortedArr[mid]) / 2;\n}\n\nexport function parseJsonAs<T>(json?: string): T | undefined {\n\tif (!json) {\n\t\treturn undefined;\n\t}\n\t\n\ttry {\n\t\treturn JSON.parse(json) as T;\n\t} catch (error) {\n\t\treturn undefined;\n\t}\n}","/* eslint-disable no-shadow */\n\nexport enum ClientEventTypes {\n\tCLIENT_JOINED = 'CLIENT_JOINED',\n\tCLIENT_LEFT = 'CLIENT_LEFT',\n\tPEER_CONNECTION_OPENED = 'PEER_CONNECTION_OPENED',\n\tPEER_CONNECTION_CLOSED = 'PEER_CONNECTION_CLOSED',\n\tMEDIA_TRACK_ADDED = 'MEDIA_TRACK_ADDED',\n\tMEDIA_TRACK_REMOVED = 'MEDIA_TRACK_REMOVED',\n\tMEDIA_TRACK_RESUMED = 'MEDIA_TRACK_RESUMED',\n\tMEDIA_TRACK_MUTED = 'MEDIA_TRACK_MUTED',\n\tMEDIA_TRACK_UNMUTED = 'MEDIA_TRACK_UNMUTED',\n\tICE_GATHERING_STATE_CHANGED = 'ICE_GATHERING_STATE_CHANGED',\n\tPEER_CONNECTION_STATE_CHANGED = 'PEER_CONNECTION_STATE_CHANGED',\n\tICE_CONNECTION_STATE_CHANGED = 'ICE_CONNECTION_STATE_CHANGED',\n\tDATA_CHANNEL_OPEN = 'DATA_CHANNEL_OPEN',\n\tDATA_CHANNEL_CLOSED = 'DATA_CHANNEL_CLOSED',\n\tDATA_CHANNEL_ERROR = 'DATA_CHANNEL_ERROR',\n\tNEGOTIATION_NEEDED = 'NEGOTIATION_NEEDED',\n\tSIGNALING_STATE_CHANGE = 'SIGNALING_STATE_CHANGE',\n\t// ICE_GATHERING_STATE_CHANGE = 'ICE_GATHERING_STATE_CHANGE',\n\t// ICE_CONNECTION_STATE_CHANGE = 'ICE_CONNECTION_STATE_CHANGE',\n\tICE_CANDIDATE = 'ICE_CANDIDATE',\n\tICE_CANDIDATE_ERROR = 'ICE_CANDIDATE_ERROR',\n\t\n\t// mediasoup events\n\tPRODUCER_ADDED = 'PRODUCER_ADDED',\n\tPRODUCER_REMOVED = 'PRODUCER_REMOVED',\n\tPRODUCER_PAUSED = 'PRODUCER_PAUSED',\n\tPRODUCER_RESUMED = 'PRODUCER_RESUMED',\n\tCONSUMER_ADDED = 'CONSUMER_ADDED',\n\tCONSUMER_REMOVED = 'CONSUMER_REMOVED',\n\tCONSUMER_PAUSED = 'CONSUMER_PAUSED',\n\tCONSUMER_RESUMED = 'CONSUMER_RESUMED',\n\tDATA_PRODUCER_CREATED = 'DATA_PRODUCER_CREATED',\n\tDATA_PRODUCER_CLOSED = 'DATA_PRODUCER_CLOSED',\n\tDATA_CONSUMER_CREATED = 'DATA_CONSUMER_CREATED',\n\tDATA_CONSUMER_CLOSED = 'DATA_CONSUMER_CLOSED',\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface ClientJoinedEventPayload extends Record<string, unknown> {\n\t// empty\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface ClientLeftEventPayload extends Record<string, unknown> {\n}\n\nexport interface PeerConnectionOpenedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeConnectionState?: string;\n\ticeGatheringState?: string;\n\tsignalingState?: string;\n}\n\nexport interface PeerConnectionClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeConnectionState?: string;\n\ticeGatheringState?: string;\n\tsignalingState?: string;\n}\n\nexport interface MediaTrackAddedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n\tconstraints: MediaTrackConstraints,\n\tcapabilities: MediaTrackCapabilities,\n\tsettings: MediaTrackSettings,\n}\n\nexport interface MediaTrackRemovedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n}\n\nexport interface MediaTrackMutedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n}\n\nexport interface MediaTrackUnmutedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n}\n\nexport interface IceGatheringStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeGatheringState: string;\n}\n\nexport interface PeerConnectionStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tconnectionState: string;\n}\n\nexport interface IceConnectionStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeConnectionState: string;\n}\n\nexport interface DataChannelErrorEventPayload extends Record<string, unknown> {\n\tlabel: string;\n\tpeerConnectionId: string;\n\treadyState: string;\n\tdataChannelId: string | number | null,\n\terror: string | null,\n}\n\nexport interface DataChannelOpenEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tlabel: string;\n\treadyState: string;\n\tdataChannelId: string | number | null,\n}\n\nexport interface DataChannelClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tlabel: string;\n\treadyState: string;\n\tdataChannelId: string | number | null,\n}\n\nexport interface NegotiationNeededEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n}\n\nexport interface IceCandidateEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/address) */\n\taddress?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/candidate) */\n\tcandidate?: string;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/component) */\n\tcomponent?: RTCIceComponent | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/foundation) */\n\tfoundation?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/port) */\n\tport?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/priority) */\n\tpriority?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/protocol) */\n\tprotocol?: RTCIceProtocol | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/relatedAddress) */\n\trelatedAddress?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/relatedPort) */\n\trelatedPort?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/sdpMLineIndex) */\n\tsdpMLineIndex?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/sdpMid) */\n\tsdpMid?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/tcpType) */\n\ttcpType?: RTCIceTcpCandidateType | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/type) */\n\ttype?: RTCIceCandidateType | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/usernameFragment) */\n\tusernameFragment?: string | null;\n}\n\nexport interface IceCandidateErrorEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\terrorCode?: number;\n\terrorText?: string;\n\taddress?: string | null;\n\tport?: number | null;\n\turl?: string | null;\n}\n\nexport interface SignalingStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tsignalingState: string;\n}\n\nexport interface ProducerAddedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ProducerRemovedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ProducerPausedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ProducerResumedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ConsumerAddedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface ConsumerRemovedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface ConsumerPausedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface ConsumerResumedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface DataProducerCreatedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n}\n\nexport interface DataProducerClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n}\n\nexport interface DataConsumerCreatedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n\tdataConsumerId: string;\n}\n\nexport interface DataConsumerClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n\tdataConsumerId: string;\n}","/* eslint-disable no-shadow */\n\nexport enum ClientMetaTypes {\n\tMEDIA_CONSTRAINT = 'MEDIA_CONSTRAINT',\n\tMEDIA_DEVICE = 'MEDIA_DEVICE',\n\tMEDIA_DEVICES_SUPPORTED_CONSTRAINTS = 'MEDIA_DEVICES_SUPPORTED_CONSTRAINTS',\n\tUSER_MEDIA_ERROR = 'USER_MEDIA_ERROR',\n\tLOCAL_SDP = 'LOCAL_SDP',\n\n\tOPERATION_SYSTEM = 'OPERATION_SYSTEM',\n\tENGINE = 'ENGINE',\n\tPLATFORM = 'PLATFORM',\n\tBROWSER = 'BROWSER',\n}\n\nexport type MediaDeviceInfo = {\n\tdeviceId: string;\n\tlabel: string;\n\tkind: string;\n\tgroupId: string;\n}\n\nexport type Browser = {\n\tname: string;\n\tversion: string;\n}\n\nexport type Platform = {\n\tname: string;\n\tversion: string;\n}\n\nexport type Engine = {\n\tname: string;\n\tversion: string;\n}\n\nexport type OperationSystem = {\n\tname: string;\n\tversion: string;\n}","import { ObservedCall } from '../ObservedCall';\n\nexport class DefaultCallScoreCalculator {\n\n\tpublic constructor(\n\t\tpublic readonly observedCall: ObservedCall,\n\t) {\n\t}\n\n\tpublic update() {\n\t\tlet totalScore = 0;\n\t\tlet totalWeight = 0;\n\n\t\tfor (const client of this.observedCall.observedClients.values()) {\n\t\t\tif (client.score === undefined) continue;\n\n\t\t\ttotalScore += client.score * client.calculatedScore.weight;\n\t\t\ttotalWeight += client.calculatedScore.weight;\n\t\t}\n\n\t\tthis.observedCall.calculatedScore.value = totalWeight ? totalScore / totalWeight : undefined;\n\t}\n}","import { ObservedCall } from '../ObservedCall';\nimport { ObservedClient, ObservedClientEvents } from '../ObservedClient';\nimport type { AcceptContext } from '../Observer';\nimport { Updater } from './Updater';\n \nexport class OnAllClientCallUpdater implements Updater {\n\treadonly name = 'OnAllClientCallUpdater';\n\treadonly description = 'Call the update() method of the ObservedCall once all client has been updated';\n\n\tprivate readonly _updatedClients = new Set<string>();\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate _observedCall: ObservedCall\n\t) {\n\t\tthis._onNewObservedClient = this._onNewObservedClient.bind(this);\n\n\t\tthis._observedCall.once('close', () => {\n\t\t\tthis._observedCall.off('newclient', this._onNewObservedClient);\n\t\t});\n\t\tthis._observedCall.on('newclient', this._onNewObservedClient);\n\t}\n\t\n\tpublic close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\t// do nothing, as close once emitted unsubscription happened\n\t\tthis._updatedClients.clear();\n\t}\n\n\tprivate _onNewObservedClient(observedClient: ObservedClient) {\n\t\tif (this.closed) return;\n\t\t\n\t\tconst onUpdate = (...args: ObservedClientEvents['update']) => this._onClientUpdate(observedClient, args[2]);\n\n\t\tobservedClient.once('close', () => {\n\t\t\tobservedClient.off('update', onUpdate);\n\t\t\tthis._updatedClients.delete(observedClient.clientId);\n\t\t\tthis._updateIfEveryClientUpdated();\n\t\t});\n\t\tobservedClient.on('update', onUpdate);\n\t}\n\n\tprivate _onClientUpdate(observedClient: ObservedClient, context?: AcceptContext) {\n\t\tif (observedClient.closed) return;\n\n\t\tthis._updatedClients.add(observedClient.clientId);\n\t\tthis._updateIfEveryClientUpdated(context);\n\t}\n\n\tprivate _updateIfEveryClientUpdated(context?: AcceptContext) {\n\t\tif (this._updatedClients.size < this._observedCall.observedClients.size) {\n\t\t\treturn;\n\t\t} else if (this.closed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._updatedClients.clear();\n\t\tthis._observedCall.update(context);\n\t}\n\n}\t","import { ObservedCall } from '../ObservedCall';\nimport { ObservedClient, ObservedClientEvents } from '../ObservedClient';\nimport { Updater } from './Updater';\n \nexport class OnAnyClientCallUpdater implements Updater {\n\treadonly name = 'OnAnyClientCallUpdater';\n\treadonly description = 'Call the update() method of the ObservedCall when any of the client has been updated';\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate _observedCall: ObservedCall\n\t) {\n\t\tthis._onNewObservedClient = this._onNewObservedClient.bind(this);\n\n\t\tthis._observedCall.once('close', () => {\n\t\t\tthis._observedCall.off('newclient', this._onNewObservedClient);\n\t\t});\n\t\tthis._observedCall.on('newclient', this._onNewObservedClient);\n\t}\n\t\n\tpublic close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t}\n\n\tprivate _onNewObservedClient(observedClient: ObservedClient) {\n\t\tif (this.closed) return;\n\t\t\n\t\tconst onUpdate = (...args: ObservedClientEvents['update']) => {\n\t\t\tif (this.closed) return;\n\t\t\tthis._observedCall.update(args[2]);\n\t\t};\n\n\t\tobservedClient.once('close', () => {\n\t\t\tobservedClient.off('update', onUpdate);\n\t\t});\n\t\tobservedClient.on('update', onUpdate);\n\t}\n}","import { createLogger } from '../common/logger';\nimport { Detector } from './Detector';\n\nconst logger = createLogger('Detectors');\n\nexport class Detectors {\n\tprivate _detectors: Detector[];\n\n\tpublic constructor(...detectors: Detector[]) {\n\t\tthis._detectors = detectors;\n\t}\n\n\tpublic get listOfNames() {\n\t\treturn this._detectors.map((d) => d.name);\n\t}\n\n\tpublic add(detector: Detector) {\n\t\tthis._detectors.push(detector);\n\t}\n\n\tpublic remove(detector: Detector) {\n\t\tthis._detectors = this._detectors.filter((d) => d !== detector);\n\t}\n\n\tpublic update() {\n\t\tfor (const detector of this._detectors) {\n\t\t\ttry {\n\t\t\t\tdetector.update();\n\t\t\t} catch (err) {\n\t\t\t\tlogger.warn(`Error updating detector ${detector?.name}`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic clear() {\n\t\tthis._detectors = [];\n\t}\n}\n","import { createLogger } from './common/logger';\nimport { ObservedCall, ObservedCallSettings } from './ObservedCall';\nimport { EventEmitter } from 'events';\nimport { ClientSample } from './schema/ClientSample';\nimport { ObservedTURN } from './ObservedTURN';\nimport { Updater } from './updaters/Updater';\nimport { OnAllCallObserverUpdater } from './updaters/OnAllCallObserverUpdater';\nimport { OnAnyCallObserverUpdater } from './updaters/OnAnyCallObserverUpdater';\nimport type { RemoteTrackResolverFactory } from './utils/RemoteTrackResolver';\nimport type { ObserverEvents, ObserverEventBase, ObservedMediasoupRouterScope } from './ObserverEvents';\nimport type { ClientSampleSinkFactory } from './sinks/ClientSampleSink';\nimport { Middleware, MiddlewareProcessor } from './common/Middleware';\nimport { ObservedMediasoupRouter, ObservedMediasoupRouterSettings } from './ObservedMediasoupRouter';\n\nconst logger = createLogger('Observer');\n\nexport type SampleRejectedReason = 'observer-closed' | 'missing-callId' | 'missing-clientId';\n\nexport type { ObserverEvents } from './ObserverEvents';\n\n/**\n * Optional, free-form context supplied to `accept()`. A single context object is\n * threaded down the accept chain (Observer -> Client -> PeerConnection) and is\n * merged into the `appData` of entities created during the accept pass.\n */\nexport type AcceptContext = Record<string, unknown>;\n\n/** The payload threaded through `accept()` middlewares: the sample and its optional context. */\nexport type AcceptMiddlewarePayload = {\n\tsample: ClientSample,\n\tcontext?: AcceptContext,\n};\n\n/**\n * A global middleware run on every sample passed to `observer.accept()`, in registration order,\n * **before** the sample is dispatched to any call/client. It may inspect or mutate the sample\n * (e.g. set/normalize `callId`/`clientId`, enrich, redact) or the context, then call\n * `next(payload)` to continue the chain. Not calling `next` **drops** the sample.\n */\nexport type AcceptMiddleware = Middleware<AcceptMiddlewarePayload>;\n\n// Updates are event-driven: triggered when any/all calls have updated. `'none'` disables the\n// automatic trigger entirely — the application must call `observer.update()` itself.\n// (Apps wanting a fixed cadence can call `observer.update()` on their own timer.)\ntype ObserverUpdateConfig = {\n\tupdatePolicy?: 'update-on-any-call-updated' | 'update-when-all-call-updated' | 'none',\n};\n\n/** Produces the initial `appData` for a call created without an explicit `appData`. */\nexport type CallAppDataFactory = (params: { callId: string, observer: Observer }) => Record<string, unknown>;\n\n/** Produces the initial `appData` for a client created without an explicit `appData`. */\nexport type ClientAppDataFactory = (params: { clientId: string, observedCall: ObservedCall }) => Record<string, unknown>;\n\nexport type ObserverConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = ObserverUpdateConfig & {\n\tdefaultCallUpdatePolicy?: ObservedCallSettings['updatePolicy'],\n\tappData?: AppData,\n\tcloseClientIfIdleForMs?: number,\n\tcloseCallIfEmptyForMs?: number,\n\n\t/**\n\t * Optional factory invoked when a call is created without an explicit `appData`\n\t * (e.g. lazily by `accept()`), so apps can enrich appData without pre-creating the\n\t * entity. `appData` is application-owned; it is never modified by the `accept()` context.\n\t */\n\tcreateCallAppData?: CallAppDataFactory,\n\n\t/** Same as `createCallAppData`, for clients. Receives the (already-created) parent call. */\n\tcreateClientAppData?: ClientAppDataFactory,\n\n\t/**\n\t * Optional factory invoked when a client is created, producing a per-client sink that\n\t * receives every sample the client accepts (or `undefined` for no sink). The destination\n\t * can be derived from `callId` / `clientId`.\n\t */\n\tcreateClientSink?: ClientSampleSinkFactory,\n\n\t/**\n\t * Optional factory invoked when a call is created, producing the call's `RemoteTrackResolver`\n\t * (or `undefined` for none). Use the built-ins\n\t * (`createDefaultMediasoupRemoteTrackResolverFactory()` / `createP2pRemoteTrackResolverFactory()`)\n\t * or build a `RemoteTrackResolver` with custom publisher/subscriber id resolvers.\n\t */\n\tcreateRemoteTrackResolver?: RemoteTrackResolverFactory,\n}\n\nexport declare interface Observer {\n\ton<U extends keyof ObserverEvents>(event: U, listener: (...args: ObserverEvents[U]) => void): this;\n\toff<U extends keyof ObserverEvents>(event: U, listener: (...args: ObserverEvents[U]) => void): this;\n\tonce<U extends keyof ObserverEvents>(event: U, listener: (...args: ObserverEvents[U]) => void): this;\n\temit<U extends keyof ObserverEvents>(event: U, ...args: ObserverEvents[U]): boolean;\n}\n\nexport class Observer<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic readonly observedTURN = new ObservedTURN();\n\tpublic readonly observedCalls = new Map<string, ObservedCall>();\n\tpublic readonly observedMediasoupRouters = new Map<string, ObservedMediasoupRouter>();\n\n\tpublic updater?: Updater;\n\n\t/** Ancestry base shared by all Observer-bus events originating at the observer. */\n\tpublic readonly eventScope: ObserverEventBase = { observer: this };\n\n\tpublic closed = false;\n\n\tpublic totalAddedCall = 0;\n\tpublic totalRemovedCall = 0;\n\n\tpublic numberOfClientsUsingTurn = 0;\n\tpublic numberOfClients = 0;\n\tpublic numberOfInboundRtpStreams = 0;\n\tpublic numberOfOutboundRtpStreams = 0;\n\tpublic numberOfDataChannels = 0;\n\tpublic numberOfPeerConnections = 0;\n\n\t/** Global, pre-dispatch middleware chain run on every accepted sample. */\n\tpublic readonly acceptMiddlewares = new MiddlewareProcessor<AcceptMiddlewarePayload>();\n\n\tpublic constructor(public readonly config: ObserverConfig<AppData> = {\n\t\tupdatePolicy: 'update-when-all-call-updated',\n\t\tappData: {} as AppData,\n\t}) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\t\tthis.update = this.update.bind(this);\n\n\t\tconst currentUpdatePolicy = (config?.updatePolicy) ?? 'update-when-all-call-updated';\n\n\t\tswitch (currentUpdatePolicy) {\n\t\t\tcase 'update-on-any-call-updated':\n\t\t\t\tthis.updater = new OnAnyCallObserverUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'update-when-all-call-updated':\n\t\t\t\tthis.updater = new OnAllCallObserverUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'none':\n\t\t\t\t// No automatic updater: `observer.update()` only runs when the app calls it.\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tpublic get numberOfCalls() {\n\t\treturn this.observedCalls.size;\n\t}\n\n\tpublic get appData() {\n\t\treturn this.config.appData;\n\t}\n\n\tpublic getObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(callId: string): ObservedCall<T> | undefined {\n\t\tif (this.closed || !this.observedCalls.has(callId)) return;\n\n\t\treturn this.observedCalls.get(callId) as ObservedCall<T>;\n\t}\n\n\tpublic createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedCallSettings<T>\n\t): ObservedCall<T> | undefined {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to create a call (callId: %s) on a closed observer', settings.callId);\n\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this.observedCalls.has(settings.callId)) {\n\t\t\tlogger.warn('Observed Call with id %s already exists; returning the existing instance', settings.callId);\n\n\t\t\treturn this.observedCalls.get(settings.callId) as ObservedCall<T>;\n\t\t}\n\n\t\t// Apply observer-level defaults without mutating the caller's (discriminated-union) settings object.\n\t\tconst callSettings = {\n\t\t\t...settings,\n\t\t\tupdatePolicy: settings.updatePolicy ?? this.config.defaultCallUpdatePolicy,\n\t\t\tcloseCallIfEmptyForMs: settings.closeCallIfEmptyForMs ?? this.config.closeCallIfEmptyForMs,\n\t\t\tappData: settings.appData ?? this.config.createCallAppData?.({ callId: settings.callId, observer: this }),\n\t\t} as ObservedCallSettings<T>;\n\n\t\tconst observedCall = new ObservedCall(callSettings, this);\n\n\t\t// Build the call's track resolver from the configured factory (if any).\n\t\tobservedCall.remoteTrackResolver = this.config.createRemoteTrackResolver?.(observedCall);\n\n\t\tobservedCall.once('close', () => {\n\t\t\tthis.observedCalls.delete(observedCall.callId);\n\t\t\t++this.totalRemovedCall;\n\t\t});\n\n\t\tthis.observedCalls.set(observedCall.callId, observedCall);\n\t\t++this.totalAddedCall;\n\n\t\tthis._notify('call-added', { ...this.eventScope, observedCall });\n\n\t\treturn observedCall;\n\t}\n\n\tpublic getOrCreateObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedCallSettings<T>\n\t): ObservedCall<T> | undefined {\n\t\treturn this.getObservedCall<T>(settings.callId) ?? this.createObservedCall<T>(settings);\n\t}\n\n\tpublic createObservedMediasoupRouter<T extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedMediasoupRouterSettings<T> & {\n\t\t\t// When `true`, the observer emits `mediasoup-router-matched-with-peer-connection` for every\n\t\t\t// observed peer connection whose id matches one of this router's WebRTC transport ids.\n\t\t\t// When `false` / omitted, no peer-connection matching is performed.\n\t\t\tmatchPeerConnectionByWebRtcTransportId?: boolean,\n\t\t},\n\t) {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to create mediasoup router (id: %d) on a closed observer', settings.router.id);\n\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this.observedMediasoupRouters.has(settings.router.id)) {\n\t\t\tlogger.warn('Observed Mediasoup Router (id %s) already exists; returning the existing instance', settings.router.id);\n\n\t\t\treturn this.observedMediasoupRouters.get(settings.router.id);\n\t\t}\n\n\t\tconst observedMediasoupRouter = new ObservedMediasoupRouter(settings);\n\t\tconst observedMediasoupRouterScope: ObservedMediasoupRouterScope = {\n\t\t\tobservedMediasoupRouter,\n\t\t\tobserver: this,\n\t\t};\n\n\t\t// Peer-connection matching is opt-in (see `matchPeerConnectionByWebRtcTransportId`). When on,\n\t\t// emit `mediasoup-router-matched-with-peer-connection` for each peer connection whose id matches\n\t\t// one of the router's WebRTC transport ids; the observer stores nothing — the app owns the pairing.\n\t\tif (settings.matchPeerConnectionByWebRtcTransportId) {\n\t\t\tconst onPeerConnectionAdded = (observedPeerConnectionScope: ObserverEvents['peer-connection-added'][0]) => {\n\t\t\t\tif (!observedMediasoupRouter.webrtcTransportIds.has(observedPeerConnectionScope.observedPeerConnection.peerConnectionId)) return;\n\n\t\t\t\tthis.emit('mediasoup-router-matched-with-peer-connection', {\n\t\t\t\t\t...observedMediasoupRouterScope,\n\t\t\t\t\t...observedPeerConnectionScope,\n\t\t\t\t});\n\t\t\t};\n\t\t\tconst stopMatching = () => this.off('peer-connection-added', onPeerConnectionAdded);\n\n\t\t\tthis.on('peer-connection-added', onPeerConnectionAdded);\n\t\t\tthis.once('observer-closed', stopMatching);\n\t\t\tobservedMediasoupRouter.once('close', stopMatching);\n\t\t}\n\n\t\tobservedMediasoupRouter.once('close', () => {\n\t\t\tthis.observedMediasoupRouters.delete(observedMediasoupRouter.id);\n\n\t\t\tthis.emit('mediasoup-router-removed', observedMediasoupRouterScope);\n\t\t});\n\t\tthis.observedMediasoupRouters.set(observedMediasoupRouter.id, observedMediasoupRouter);\n\n\t\tthis.emit('mediasoup-router-added', observedMediasoupRouterScope);\n\n\t\treturn observedMediasoupRouter;\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) {\n\t\t\treturn logger.debug('Attempted to close twice');\n\t\t}\n\t\tthis.closed = true;\n\n\t\tthis.observedCalls.forEach((call) => call.close());\n\n\t\tthis._notify('observer-closed', { ...this.eventScope });\n\t}\n\n\tpublic accept(sample: ClientSample, context?: AcceptContext): void {\n\t\tif (this.closed) {\n\t\t\treturn this._notify('sample-rejected', { ...this.eventScope, reason: 'observer-closed', sample });\n\t\t}\n\n\t\ttry {\n\t\t\tthis.acceptMiddlewares.process({ sample, context });\n\t\t} catch (err) {\n\t\t\tlogger.warn('An accept middleware threw; dropping the sample. %o', err);\n\t\t}\n\n\t\tif (!sample.callId) {\n\t\t\tthis._notify('sample-rejected', { ...this.eventScope, reason: 'missing-callId', sample });\n\n\t\t\treturn;\n\t\t}\n\t\tif (!sample.clientId) {\n\t\t\tthis._notify('sample-rejected', { ...this.eventScope, reason: 'missing-clientId', sample });\n\n\t\t\treturn;\n\t\t}\n\n\t\tlet call = this.getObservedCall(sample.callId);\n\n\t\tif (!call) {\n\t\t\tcall = this.createObservedCall({\n\t\t\t\tcallId: sample.callId,\n\t\t\t\tappData: this.config.createCallAppData?.({ callId: sample.callId, observer: this }),\n\t\t\t});\n\t\t}\n\t\tif (!call) return;\n\n\t\tlet client = call.getObservedClient(sample.clientId);\n\n\t\tif (!client) {\n\t\t\tclient = call.createObservedClient({\n\t\t\t\tclientId: sample.clientId,\n\t\t\t\tappData: this.config.createClientAppData?.({ clientId: sample.clientId, observedCall: call }),\n\t\t\t});\n\t\t}\n\t\tif (!client) return;\n\n\t\tclient.accept(sample, context);\n\t}\n\n\tpublic update() {\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.numberOfInboundRtpStreams = 0;\n\t\tthis.numberOfOutboundRtpStreams = 0;\n\t\tthis.numberOfPeerConnections = 0;\n\t\tthis.numberOfDataChannels = 0;\n\t\tthis.numberOfClients = 0;\n\t\tthis.numberOfClientsUsingTurn = 0;\n\n\t\tfor (const call of this.observedCalls.values()) {\n\t\t\tthis.numberOfInboundRtpStreams += call.numberOfInboundRtpStreams;\n\t\t\tthis.numberOfOutboundRtpStreams += call.numberOfOutboundRtpStreams;\n\t\t\tthis.numberOfPeerConnections += call.numberOfPeerConnections;\n\t\t\tthis.numberOfDataChannels += call.numberOfDataChannels;\n\t\t\tthis.numberOfClients += call.numberOfClients;\n\t\t\tthis.numberOfClientsUsingTurn += call.clientsUsedTurn.size;\n\t\t}\n\n\t\tthis.observedTURN.update();\n\n\t\tthis._notify('observer-updated', { ...this.eventScope });\n\t}\n\n\t/** Emit an Observer-bus event. */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.emit(type, ...args);\n\t}\n}\n","import { EventEmitter } from 'events';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedTurnServer } from './ObservedTurnServer';\nimport { createLogger } from './common/logger';\n\nconst logger = createLogger('ObservedTURN');\n\nexport type ObservedTURNEventMap = {\n\t'update': [ObservedTURN];\n\t'close': [];\n}\n\nexport declare interface ObservedTURN {\n\ton<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;\n\toff<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;\n\tonce<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;\n\temit<U extends keyof ObservedTURNEventMap>(event: U, ...args: ObservedTURNEventMap[U]): boolean;\n}\n\nexport class ObservedTURN extends EventEmitter {\n\tpublic totalBytesSent = 0;\n\tpublic totalBytesReceived = 0;\n\tpublic totalPacketsSent = 0;\n\tpublic totalPacketsReceived = 0;\n\n\tpublic packetsSentPerSecond = 0;\n\tpublic packetsReceivedPerSecond = 0;\n\tpublic outboundBitrate = 0;\n\tpublic inboundBitrate = 0;\n\tpublic numberOfClients = 0;\n \n\tpublic readonly servers = new Map<string, ObservedTurnServer>();\n\n\tpublic constructor(\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic update() {\n\t\tconst clientIds = new Set<string>();\n \n\t\tthis.packetsReceivedPerSecond = 0;\n\t\tthis.packetsSentPerSecond = 0;\n\t\tthis.outboundBitrate = 0;\n\t\tthis.inboundBitrate = 0;\n\n\t\tfor (const server of this.servers.values()) {\n\t\t\tserver.update();\n\t\t\tserver.observedPeerConnections.forEach((pc) => clientIds.add(pc.client.clientId));\n\t\t}\n\n\t\tthis.numberOfClients = clientIds.size;\n\t}\n\n\tpublic addPeerConnection(peerConnection: ObservedPeerConnection) {\n\t\tconst turnPairs = peerConnection.selectedIceCandidatePairs.filter((pair) => pair.getLocalCandidate()?.candidateType === 'relay' && pair.getRemoteCandidate()?.url?.startsWith('turn:'));\n\n\t\tif (turnPairs.length !== 1) {\n\t\t\treturn (logger.warn(`Expected exactly one TURN pair, but found for peerconnection ${peerConnection.peerConnectionId}`, turnPairs.length), undefined);\n\t\t}\n\n\t\tconst candidatePair = turnPairs[0];\n\t\tconst rawUrl = candidatePair.getRemoteCandidate()?.url;\n\n\t\tif (!rawUrl) {\n\t\t\treturn (logger.warn(`No remote candidate URL found for peerconnection ${peerConnection.peerConnectionId}`), undefined);\n\t\t}\n\n\t\tconst turnUrl = new URL(rawUrl);\n\t\tconst turnServerUrl = `${turnUrl.protocol}//${turnUrl.hostname}:${turnUrl.port}`;\n\t\tlet turnServer = this.servers.get(turnServerUrl);\n \n\t\tif (!turnServer) {\n\t\t\tturnServer = new ObservedTurnServer(turnServerUrl, this);\n\t\t}\n\n\t\treturn turnServer;\n\t}\n\n\tpublic removePeerConnection(peerConnection: ObservedPeerConnection) {\n\t\tfor (const turnServer of this.servers.values()) {\n\t\t\tturnServer.observedPeerConnections.delete(peerConnection.peerConnectionId);\n\t\t}\n\t}\n\n}","import { ObservedIceCandidatePair } from './ObservedIceCandidatePair';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedTURN } from './ObservedTURN';\n\nexport class ObservedTurnServer {\n\tpublic totalBytesSent = 0;\n\tpublic totalBytesReceived = 0;\n\tpublic totalPacketsSent = 0;\n\tpublic totalPacketsReceived = 0;\n\n\tpublic packetsSentPerSecond = 0;\n\tpublic packetsReceivedPerSecond = 0;\n\tpublic outboundBitrate = 0;\n\tpublic inboundBitrate = 0;\n\n\tpublic deltaBytesSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaPacketsReceived = 0;\n \n\tpublic readonly observedPeerConnections = new Map<string, ObservedPeerConnection>(); \n\n\tpublic updated = Date.now();\n\n\tpublic constructor(\n\t\tpublic readonly url: string,\n\t\tpublic readonly observedTURN: ObservedTURN,\n\t) {\n\n\t}\n\n\tpublic updateTurnUsage(...selectedcandidatepairs: ObservedIceCandidatePair[]) {\n\t\tfor (const selectedcandidatepair of selectedcandidatepairs) {\n\t\t\tthis.deltaBytesReceived += selectedcandidatepair.deltaBytesReceived;\n\t\t\tthis.deltaBytesSent += selectedcandidatepair.deltaBytesSent;\n\t\t\tthis.deltaPacketsReceived += selectedcandidatepair.deltaPacketsReceived;\n\t\t\tthis.deltaPacketsSent += selectedcandidatepair.deltaPacketsSent;\n\t\t}\n\t}\n\n\tpublic update() {\n\t\tconst now = Date.now();\n\t\tconst deltaInS = (now - this.updated) / 1000;\n \n\t\tthis.packetsSentPerSecond = this.deltaPacketsSent / deltaInS;\n\t\tthis.packetsReceivedPerSecond = this.deltaPacketsReceived / deltaInS; \n\t\tthis.outboundBitrate = (this.deltaBytesReceived * 8) / deltaInS;\n\t\tthis.inboundBitrate = (this.deltaBytesSent * 8) / deltaInS;\n \n\t\tthis.totalBytesSent += this.deltaBytesSent;\n\t\tthis.totalBytesReceived += this.deltaBytesReceived;\n\t\tthis.totalPacketsSent += this.deltaPacketsSent;\n\t\tthis.totalPacketsReceived += this.deltaPacketsReceived;\n\t\t\n\t\tthis.observedTURN.totalBytesSent += this.deltaBytesSent;\n\t\tthis.observedTURN.totalBytesReceived += this.deltaBytesReceived;\n\t\tthis.observedTURN.totalPacketsSent += this.deltaPacketsSent;\n\t\tthis.observedTURN.totalPacketsReceived += this.deltaPacketsReceived;\n \n\t\tthis.observedTURN.inboundBitrate += this.inboundBitrate;\n\t\tthis.observedTURN.outboundBitrate += this.outboundBitrate;\n\t\tthis.observedTURN.packetsReceivedPerSecond += this.packetsReceivedPerSecond;\n\t\tthis.observedTURN.packetsSentPerSecond += this.packetsSentPerSecond;\n \n\t\tthis.deltaBytesSent = 0;\n\t\tthis.deltaBytesReceived = 0;\n\t\tthis.deltaPacketsSent = 0;\n\t\tthis.deltaPacketsReceived = 0;\n\n\t\tthis.updated = now;\n\t}\n}","import { ObservedCall } from '../ObservedCall';\nimport { Observer } from '../Observer';\nimport type { ObservedCallScope } from '../ObserverEvents';\nimport { Updater } from './Updater';\n\nexport class OnAllCallObserverUpdater implements Updater {\n\tpublic readonly name = 'OnAllCallObserverUpdater';\n\tpublic readonly description = 'Call Observer\\'s update() method when all of the ObservedCalls are updated';\n\t\n\tprivate readonly _updatedCalls = new Set<string>();\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate observer: Observer\n\t) {\n\t\tthis._onNewObservedCall = this._onNewObservedCall.bind(this);\n\n\t\tthis.observer.once('observer-closed', () => {\n\t\t\tthis.observer.off('call-added', this._onNewObservedCall);\n\t\t});\n\t\tthis.observer.on('call-added', this._onNewObservedCall);\n\t}\n\n\tclose(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\n\t\tthis._updatedCalls.clear();\n\t}\n\n\tprivate _onNewObservedCall({ observedCall }: ObservedCallScope) {\n\t\tif (this.closed) return;\n\n\t\tconst onUpdate = () => this._onObservedCallUpdated(observedCall);\n\n\t\tobservedCall.once('close', () => {\n\t\t\tobservedCall.off('update', onUpdate);\n\t\t\tthis._updatedCalls.delete(observedCall.callId);\n\n\t\t\tthis._updateIfEveryCallUpdated();\n\t\t});\n\t\tobservedCall.on('update', onUpdate);\n\t}\n\n\tprivate _onObservedCallUpdated(observedCall: ObservedCall) {\n\t\tif (observedCall.closed) return;\n\n\t\tthis._updatedCalls.add(observedCall.callId);\n\n\t\tthis._updateIfEveryCallUpdated();\n\t}\n\n\tprivate _updateIfEveryCallUpdated() {\n\t\tif (this._updatedCalls.size < this.observer.observedCalls.size) return;\n\t\telse if (this.closed) return;\n\n\t\tthis._updatedCalls.clear();\n\t\tthis.observer.update();\n\t}\n}","import { Observer } from '../Observer';\nimport type { ObservedCallScope } from '../ObserverEvents';\nimport { Updater } from './Updater';\n\nexport class OnAnyCallObserverUpdater implements Updater {\n\tpublic readonly name = 'OnAnyCallObserverUpdater';\n\tpublic readonly description = 'Call Observer\\'s update() method on any of the ObservedCall is updated';\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate observver: Observer\n\t) {\n\t\tthis._onNewObservedCall = this._onNewObservedCall.bind(this);\n\n\t\tthis.observver.once('observer-closed', () => {\n\t\t\tthis.observver.off('call-added', this._onNewObservedCall);\n\t\t});\n\t\tthis.observver.on('call-added', this._onNewObservedCall);\n\t}\n\n\tpublic close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\t// do nothing, because we unsubscribe once close is emitted from observer\n\t}\n\n\tprivate _onNewObservedCall({ observedCall }: ObservedCallScope) {\n\t\tif (this.closed) return;\n\n\t\tconst onUpdate = () => {\n\t\t\tif (this.closed) return;\n\n\t\t\tthis.observver.update();\n\t\t};\n\n\t\tobservedCall.once('close', () => {\n\t\t\tobservedCall.off('update', onUpdate);\n\t\t});\n\t\tobservedCall.on('update', onUpdate);\n\t}\n}","export type Middleware<T> = (\n\tinput: T,\n\tnext: (nextInput: T) => void\n) => void;\n\nexport interface Processor<T> {\n\tfinalCallback?: Callback<T>;\n\tprocess(value: T): void;\n\taddMiddleware(...middlewares: Middleware<T>[]): Processor<T>;\n\tremoveMiddleware(...middlewares: Middleware<T>[]): Processor<T>;\n}\n\ntype Callback<T> = (input: T) => void;\n\nclass Executor<T> {\n\tpublic done = false;\n\tprivate index = 0;\n\tprivate prevIndex = -1;\n\n\tconstructor(\n\t\tprivate readonly stack: Middleware<T>[],\n\t\tprivate readonly finalCallback?: Callback<T>\n\t) {\n\t}\n\n\t// Executes the middleware stack\n\tpublic execute(input: T): void {\n\t\tif (this.index <= this.prevIndex) {\n\t\t\tthrow new Error('Middleware must call next() only once!');\n\t\t} else if (this.done) {\n\t\t\tthrow new Error('Middleware stack has already been executed!');\n\t\t}\n\n\t\tthis.prevIndex = this.index;\n\n\t\tconst middleware = this.stack[this.index];\n\n\t\tthis.index++;\n\n\t\tif (middleware) {\n\t\t\treturn middleware(input, (nextInput: T) => this.execute(nextInput));\n\t\t}\n\n\t\tthis.done = true;\n\t\tthis.finalCallback?.(input);\n\t}\n}\n\nexport class MiddlewareProcessor<T> implements Processor<T> {\n\tprivate stack: Middleware<T>[] = [];\n\tpublic finalCallback?: Callback<T>;\n\n\tpublic addMiddleware(...middlewares: Middleware<T>[]): Processor<T> {\n\t\tif (middlewares && middlewares.length > 0) {\n\t\t\tthis.stack.push(...middlewares);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic removeMiddleware(...middlewares: Middleware<T>[]): Processor<T> {\n\t\tif (middlewares && middlewares.length > 0) {\n\t\t\tfor (const middleware of middlewares) {\n\t\t\t\tconst index = this.stack.indexOf(middleware);\n\n\t\t\t\tif (index >= 0) {\n\t\t\t\t\tthis.stack.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic process(value: T): void {\n\t\tif (this.stack.length === 0) {\n\t\t\treturn this.finalCallback?.(value);\n\t\t}\n\n\t\tconst executor = new Executor(this.stack, this.finalCallback);\n\n\t\texecutor.execute(value);\n\t}\n}\n","import { EventEmitter } from 'events';\nimport type { types } from 'mediasoup';\nimport {\n\tMediasoupRouterSample,\n\tMediasoupTransportSample,\n\tMediasoupProducerSample,\n\tMediasoupConsumerSample,\n\tMediasoupDataProducerSample,\n\tMediasoupDataConsumerSample,\n\tMediasoupWebRtcTransportSampleEventMap,\n\tMediasoupPlainTransportSampleEventMap,\n\tMediasoupPipeTransportSampleEventMap,\n} from './schema/MediasoupRouter';\nimport { createLogger } from './common/logger';\n\nconst logger = createLogger('ObservedMediasoupRouter');\n\nexport type ObservedMediasoupRouterSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {\n\trouter: types.Router,\n\tappData?: AppData;\n\tattachments?: Record<string, unknown>,\n};\n\nexport type ObservedMediasoupRouterEvents = {\n\tclose: [];\n};\n\nexport declare interface ObservedMediasoupRouter {\n\ton<U extends keyof ObservedMediasoupRouterEvents>(event: U, listener: (...args: ObservedMediasoupRouterEvents[U]) => void): this;\n\toff<U extends keyof ObservedMediasoupRouterEvents>(event: U, listener: (...args: ObservedMediasoupRouterEvents[U]) => void): this;\n\tonce<U extends keyof ObservedMediasoupRouterEvents>(event: U, listener: (...args: ObservedMediasoupRouterEvents[U]) => void): this;\n\temit<U extends keyof ObservedMediasoupRouterEvents>(event: U, ...args: ObservedMediasoupRouterEvents[U]): boolean;\n}\n\n/**\n * Observes a live mediasoup `Router` by subscribing to its `observer` API and **accumulates** its\n * topology and lifecycle into an in-memory `MediasoupRouterSample` (`observedRouter.sample`):\n * transports, producers, consumers, data producers/consumers, their state-change history and\n * `createdAt` / `closedAt`. The sample grows for the life of the router (closed entities are kept,\n * with their `closedAt` set) and is yours to read, snapshot, or persist.\n *\n * NOTE: this is intentionally the simplest approach — everything is held in memory. For very large\n * routers (e.g. ~100 participants producing and consuming on one router, where consumers grow as\n * O(N²)) this can become substantial; in that case do your own periodic sampling/persistence and\n * discard what you don't need (see the README's \"Memory & large meetings\" note).\n */\nexport class ObservedMediasoupRouter<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic readonly router: types.Router;\n\tpublic appData: AppData;\n\tpublic readonly sample: MediasoupRouterSample;\n\n\tpublic readonly webrtcTransportIds = new Set<string>();\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tsettings: ObservedMediasoupRouterSettings<AppData>,\n\t) {\n\t\tsuper();\n\n\t\tthis.router = settings.router;\n\t\tthis.appData = (settings.appData ?? {}) as AppData;\n\t\tthis.sample = {\n\t\t\trouterId: this.router.id,\n\t\t\tattachments: settings.attachments ?? {},\n\t\t\tcreatedAt: Date.now(),\n\t\t\tproducers: [],\n\t\t\tconsumers: [],\n\t\t\tdataProducers: [],\n\t\t\tdataConsumers: [],\n\t\t\ttransports: [],\n\t\t};\n\n\t\tthis.attachRouterListeners();\n\t}\n\n\tpublic get id() {\n\t\treturn this.router.id;\n\t}\n\n\tpublic get attachments() {\n\t\treturn this.sample.attachments;\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\n\t\tthis.closed = true;\n\t\tif (this.sample.closedAt === undefined) this.sample.closedAt = Date.now();\n\n\t\tthis.emit('close');\n\t}\n\n\tpublic addTransport = (transport: types.Transport) => {\n\t\tlet transportType = transport.type;\n\n\t\t// for backward compatibility\n\t\tif (!transportType) {\n\t\t\tif (transport.constructor.name === 'WebRtcTransport') transportType = 'webrtc';\n\t\t\telse if (transport.constructor.name === 'PlainTransport') transportType = 'plain';\n\t\t\telse if (transport.constructor.name === 'PipeTransport') transportType = 'pipe';\n\t\t\telse if (transport.constructor.name === 'DirectTransport') transportType = 'direct';\n\t\t}\n\n\t\tif (!transportType) return logger.warn(`Unknown transport type for transport ${transport.id}: ${transport.constructor.name}`);\n\n\t\tswitch (transportType) {\n\t\t\tcase 'webrtc':\n\t\t\t\treturn this.addWebRtcTransport(transport as types.WebRtcTransport);\n\t\t\tcase 'plain':\n\t\t\t\treturn this.addPlainTransport(transport as types.PlainTransport);\n\t\t\tcase 'pipe':\n\t\t\t\treturn this.addPipeTransport(transport as types.PipeTransport);\n\t\t\tcase 'direct':\n\t\t\t\treturn this.addDirectTransport(transport as types.DirectTransport);\n\t\t\tdefault:\n\t\t\t\treturn logger.warn(`Unsupported transport type for transport ${transport.id}: ${transportType}`);\n\t\t}\n\t};\n\n\tpublic addWebRtcTransport(transport: types.WebRtcTransport) {\n\t\tconst history: MediasoupWebRtcTransportSampleEventMap[] = [];\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'webrtc', createdAt: Date.now(), tuple: transport.iceSelectedTuple, history,\n\t\t};\n\n\t\tthis.sample.transports.push(transportSample);\n\t\tthis.webrtcTransportIds.add(transport.id);\n\n\t\tconst onIceStateChange = (iceState: types.IceState) =>\n\t\t\thistory.push({ type: `icestate-changed-to-${iceState}`, timestamp: Date.now() } as MediasoupWebRtcTransportSampleEventMap);\n\t\tconst onIceSelectedTupleChange = (tuple: types.TransportTuple) => {\n\t\t\ttransportSample.tuple = tuple;\n\t\t\thistory.push({ type: 'iceselectedtuple-changed', timestamp: Date.now(), ...tuple });\n\t\t};\n\t\tconst onDtlsStateChange = (dtlsState: types.DtlsState) => {\n\t\t\thistory.push({ type: `dtlsstate-changed-to-${dtlsState}`, timestamp: Date.now() } as MediasoupWebRtcTransportSampleEventMap);\n\t\t\tif (dtlsState === 'connected' && transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t};\n\t\tconst onSctpStateChange = (sctpState: types.SctpState) =>\n\t\t\thistory.push({ type: `sctpstate-changed-to-${sctpState}`, timestamp: Date.now() } as MediasoupWebRtcTransportSampleEventMap);\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample, () => {\n\t\t\ttransport.observer.off('icestatechange', onIceStateChange);\n\t\t\ttransport.observer.off('iceselectedtuplechange', onIceSelectedTupleChange);\n\t\t\ttransport.observer.off('dtlsstatechange', onDtlsStateChange);\n\t\t\ttransport.observer.off('sctpstatechange', onSctpStateChange);\n\n\t\t\tthis.webrtcTransportIds.delete(transport.id);\n\t\t});\n\n\t\ttransport.observer.on('icestatechange', onIceStateChange);\n\t\ttransport.observer.on('iceselectedtuplechange', onIceSelectedTupleChange);\n\t\ttransport.observer.on('dtlsstatechange', onDtlsStateChange);\n\t\ttransport.observer.on('sctpstatechange', onSctpStateChange);\n\t}\n\n\tpublic addPlainTransport(transport: types.PlainTransport) {\n\t\tconst history: MediasoupPlainTransportSampleEventMap[] = [];\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'plain', createdAt: Date.now(), tuple: transport.tuple, rtcpTuple: transport.rtcpTuple, history,\n\t\t};\n\n\t\tthis.sample.transports.push(transportSample);\n\n\t\tconst onTuple = (tuple: types.TransportTuple) => {\n\t\t\ttransportSample.tuple = tuple;\n\t\t\tif (transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t\thistory.push({ type: 'tuple-changed', timestamp: Date.now(), ...tuple });\n\t\t};\n\t\tconst onRtcpTuple = (rtcpTuple: types.TransportTuple) => {\n\t\t\ttransportSample.rtcpTuple = rtcpTuple;\n\t\t\thistory.push({ type: 'rtcptuple-changed', timestamp: Date.now(), ...rtcpTuple });\n\t\t};\n\t\tconst onSctpStateChange = (sctpState: types.SctpState) => {\n\t\t\tif (sctpState === 'connected' && transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t\thistory.push({ type: `sctpstate-changed-to-${sctpState}`, timestamp: Date.now() } as MediasoupPlainTransportSampleEventMap);\n\t\t};\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample, () => {\n\t\t\ttransport.observer.off('tuple', onTuple);\n\t\t\ttransport.observer.off('rtcptuple', onRtcpTuple);\n\t\t\ttransport.observer.off('sctpstatechange', onSctpStateChange);\n\t\t});\n\n\t\ttransport.observer.on('tuple', onTuple);\n\t\ttransport.observer.on('rtcptuple', onRtcpTuple);\n\t\ttransport.observer.on('sctpstatechange', onSctpStateChange);\n\t}\n\n\tpublic addPipeTransport(transport: types.PipeTransport) {\n\t\tconst history: MediasoupPipeTransportSampleEventMap[] = [];\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'pipe', createdAt: Date.now(), tuple: transport.tuple, history,\n\t\t};\n\n\t\tthis.sample.transports.push(transportSample);\n\n\t\tconst onSctpStateChange = (sctpState: types.SctpState) => {\n\t\t\tif (sctpState === 'connected' && transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t\thistory.push({ type: `sctpstate-changed-to-${sctpState}`, timestamp: Date.now() } as MediasoupPipeTransportSampleEventMap);\n\t\t};\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample, () => {\n\t\t\ttransport.observer.off('sctpstatechange', onSctpStateChange);\n\t\t});\n\n\t\ttransport.observer.on('sctpstatechange', onSctpStateChange);\n\t}\n\n\tpublic addDirectTransport(transport: types.DirectTransport) {\n\t\tconst now = Date.now();\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'direct', createdAt: now, connectedAt: now, history: [],\n\t\t};\n\n\t\tthis.sample.transports.push(transportSample);\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample);\n\t}\n\n\tpublic addProducer(transport: types.Transport, producer: types.Producer) {\n\t\tconst firstCodec = producer.rtpParameters.codecs[0];\n\t\tconst producerSample: MediasoupProducerSample = {\n\t\t\tid: producer.id,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tkind: producer.kind,\n\t\t\tcodecInfo: {\n\t\t\t\tmimeType: firstCodec?.mimeType ?? 'unknown/unknown',\n\t\t\t\tpayloadType: firstCodec?.payloadType ?? 0,\n\t\t\t\tclockRate: firstCodec?.clockRate ?? 0,\n\t\t\t\tchannels: firstCodec?.channels,\n\t\t\t\tparameters: firstCodec?.parameters,\n\t\t\t\trtcpFeedback: firstCodec?.rtcpFeedback,\n\t\t\t},\n\t\t\tssrcs: producer.rtpParameters.encodings?.map((e) => e.ssrc).filter((s): s is number => typeof s === 'number'),\n\t\t\trids: producer.rtpParameters.encodings?.map((e) => e.rid).filter((r): r is string => typeof r === 'string'),\n\t\t\thistory: [],\n\t\t};\n\n\t\tthis.sample.producers.push(producerSample);\n\n\t\tconst onPause = () => producerSample.history.push({ type: 'pause', timestamp: Date.now() });\n\t\tconst onResume = () => producerSample.history.push({ type: 'resume', timestamp: Date.now() });\n\n\t\tproducer.observer.once('close', () => {\n\t\t\tproducer.observer.off('pause', onPause);\n\t\t\tproducer.observer.off('resume', onResume);\n\t\t\tproducerSample.closedAt = Date.now();\n\t\t});\n\t\tproducer.observer.on('pause', onPause);\n\t\tproducer.observer.on('resume', onResume);\n\t}\n\n\tpublic addConsumer(transport: types.Transport, consumer: types.Consumer) {\n\t\tconst consumerSample: MediasoupConsumerSample = {\n\t\t\tid: consumer.id,\n\t\t\tproducerId: consumer.producerId,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tkind: consumer.kind,\n\t\t\thistory: [],\n\t\t};\n\n\t\tthis.sample.consumers.push(consumerSample);\n\n\t\tconst onPause = () => consumerSample.history.push({ type: 'pause', timestamp: Date.now() });\n\t\tconst onResume = () => consumerSample.history.push({ type: 'resume', timestamp: Date.now() });\n\t\tconst onProducerPause = () => consumerSample.history.push({ type: 'producerPaused', timestamp: Date.now() });\n\t\tconst onProducerResume = () => consumerSample.history.push({ type: 'producerResumed', timestamp: Date.now() });\n\n\t\tconsumer.observer.once('close', () => {\n\t\t\tconsumer.observer.off('pause', onPause);\n\t\t\tconsumer.observer.off('resume', onResume);\n\t\t\tconsumer.off('producerresume', onProducerResume);\n\t\t\tconsumer.off('producerpause', onProducerPause);\n\t\t\tconsumerSample.closedAt = Date.now();\n\t\t});\n\n\t\tconsumer.observer.on('pause', onPause);\n\t\tconsumer.observer.on('resume', onResume);\n\t\tconsumer.on('producerpause', onProducerPause);\n\t\tconsumer.on('producerresume', onProducerResume);\n\t}\n\n\tpublic addDataProducer(transport: types.Transport, dataProducer: types.DataProducer) {\n\t\tconst dataProducerSample: MediasoupDataProducerSample = {\n\t\t\tid: dataProducer.id,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tlabel: dataProducer.label,\n\t\t\tprotocol: dataProducer.protocol,\n\t\t};\n\n\t\tthis.sample.dataProducers.push(dataProducerSample);\n\n\t\tdataProducer.observer.once('close', () => (dataProducerSample.closedAt = Date.now()));\n\t}\n\n\tpublic addDataConsumer(transport: types.Transport, dataConsumer: types.DataConsumer) {\n\t\tconst dataConsumerSample: MediasoupDataConsumerSample = {\n\t\t\tid: dataConsumer.id,\n\t\t\tdataProducerId: dataConsumer.dataProducerId,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tlabel: dataConsumer.label,\n\t\t\tprotocol: dataConsumer.protocol,\n\t\t};\n\n\t\tthis.sample.dataConsumers.push(dataConsumerSample);\n\n\t\tdataConsumer.observer.once('close', () => (dataConsumerSample.closedAt = Date.now()));\n\t}\n\n\tprivate attachRouterListeners() {\n\t\tthis.router.observer.once('close', () => {\n\t\t\tthis.router.observer.off('newtransport', this.addTransport);\n\n\t\t\tthis.sample.closedAt = Date.now();\n\t\t\tthis.close();\n\t\t});\n\t\tthis.router.observer.on('newtransport', this.addTransport);\n\t}\n\n\tprivate _attachTransportObserverListeners(\n\t\ttransport: types.Transport,\n\t\ttransportSample: MediasoupTransportSample,\n\t\tonClose?: () => void,\n\t) {\n\t\tconst onNewProducer = (producer: types.Producer) => this.addProducer(transport, producer);\n\t\tconst onNewConsumer = (consumer: types.Consumer) => this.addConsumer(transport, consumer);\n\t\tconst onNewDataProducer = (dataProducer: types.DataProducer) => this.addDataProducer(transport, dataProducer);\n\t\tconst onNewDataConsumer = (dataConsumer: types.DataConsumer) => this.addDataConsumer(transport, dataConsumer);\n\n\t\ttransport.observer.once('close', () => {\n\t\t\ttransport.observer.off('newproducer', onNewProducer);\n\t\t\ttransport.observer.off('newconsumer', onNewConsumer);\n\t\t\ttransport.observer.off('newdataproducer', onNewDataProducer);\n\t\t\ttransport.observer.off('newdataconsumer', onNewDataConsumer);\n\n\t\t\tonClose?.();\n\n\t\t\ttransportSample.closedAt = Date.now();\n\t\t});\n\n\t\ttransport.observer.on('newproducer', onNewProducer);\n\t\ttransport.observer.on('newconsumer', onNewConsumer);\n\t\ttransport.observer.on('newdataproducer', onNewDataProducer);\n\t\ttransport.observer.on('newdataconsumer', onNewDataConsumer);\n\t}\n}\n","import { EventEmitter } from 'events';\nimport type { ClientSample } from '../schema/ClientSample';\nimport type { ObservedCall } from '../ObservedCall';\n\n/** The lifecycle events a sink may emit (a subset of Node's writable-stream events). */\nexport type ClientSampleSinkEvents = {\n\n\t/** The destination is fully written and closed (e.g. a file flushed and its fd closed). */\n\tclose: [];\n\n\t/** The destination failed. */\n\terror: [Error];\n\n\t/** `end()` was processed and all queued data was flushed (before `close`). */\n\tfinish: [];\n\n\t/** The buffer drained after backpressure; safe to write more. */\n\tdrain: [];\n};\n\nexport declare interface ClientSampleSink {\n\ton<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;\n\tonce<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;\n\toff<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;\n\temit<E extends keyof ClientSampleSinkEvents>(event: E, ...args: ClientSampleSinkEvents[E]): boolean;\n}\n\n/**\n * A per-client destination for accepted samples — a typed `EventEmitter` base class. One sink is\n * created per `ObservedClient` (via `ObserverConfig.createClientSink`). It is **object-mode**:\n * `write` receives the `ClientSample` itself, so each sink decides how to serialize it (JSON\n * line, protobuf, msgpack, a remote payload, …).\n *\n * The library calls `write(sample)` synchronously per accepted sample (not awaited), `end()`s the\n * sink when the client closes, and attaches an `error` listener so a failing sink can't crash the\n * process. The application — which created the sink — listens for `close` (destination ready,\n * e.g. a file flushed and its fd closed) and `error`.\n *\n * Subclass this and implement `write`/`end` (and `emit` your lifecycle events). Built-in sinks\n * (`JsonlFileSink`, `InMemorySink`) and their factories are exported from the package root.\n */\nexport abstract class ClientSampleSink extends EventEmitter {\n\t/** Accept one sample; the sink serializes it however it likes. `false` signals backpressure. */\n\tpublic abstract write(sample: ClientSample): boolean;\n\n\t/** Finish writing; the sink flushes and (if applicable) emits `close`. */\n\tpublic abstract end(): void;\n}\n\n/**\n * Produces a sink for a newly-created client, or `undefined` for no sink. Receives the\n * client id and its (already-created) parent call, so the destination can be derived\n * from `callId` / `clientId`.\n */\nexport type ClientSampleSinkFactory = (params: {\n\tclientId: string,\n\tobservedCall: ObservedCall,\n}) => ClientSampleSink | undefined;\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { ClientSampleSink, ClientSampleSinkFactory } from './ClientSampleSink';\nimport type { ClientSample } from '../schema/ClientSample';\n\nexport type JsonlFileSinkOptions = {\n\n\t/** Absolute or relative file path to append JSONL lines to. */\n\tpath: string,\n\n\t/** Optional custom serializer; defaults to `JSON.stringify`. */\n\tserializeSample?: (sample: ClientSample) => string,\n};\n\n/**\n * A sink that serializes each sample to a JSON line and appends it to a file. It wraps an\n * `fs.WriteStream` and re-emits its lifecycle events, so `close` fires once the file is flushed\n * and its descriptor is closed (file ready) and `error` surfaces file errors.\n */\nexport class JsonlFileSink extends ClientSampleSink {\n\t/** The file this sink writes to. Read it (e.g. in a `close` handler) to upload/move the file. */\n\tpublic readonly path: string;\n\n\tprivate readonly _stream: fs.WriteStream;\n\tprivate readonly _serializeSample: (sample: ClientSample) => string;\n\n\tpublic constructor(options: JsonlFileSinkOptions) {\n\t\tsuper();\n\t\tthis.path = options.path;\n\t\tthis._stream = fs.createWriteStream(this.path, { flags: 'a' });\n\n\t\tthis._stream.on('close', () => this.emit('close'));\n\t\tthis._stream.on('finish', () => this.emit('finish'));\n\t\tthis._stream.on('drain', () => this.emit('drain'));\n\t\tthis._stream.on('error', (err) => this.emit('error', err));\n\n\t\tthis._serializeSample = options.serializeSample ?? ((sample) => JSON.stringify(sample));\n\t}\n\n\tpublic write(sample: ClientSample): boolean {\n\t\treturn this._stream.write(`${this._serializeSample(sample)}\\n`);\n\t}\n\n\tpublic end(): void {\n\t\tthis._stream.end();\n\t}\n}\n\n/** Build a JSONL file sink for a single path. */\nexport function createJsonlFileSink(options: JsonlFileSinkOptions): ClientSampleSink {\n\treturn new JsonlFileSink(options);\n}\n\nexport type JsonlFileSinkFactoryOptions = {\n\n\t/** Directory the per-client files are written into (must exists). */\n\tdirectory: string,\n\n\t/** Builds the file name from the call/client ids. Defaults to `${callId}__${clientId}.jsonl`. */\n\tgetFileName?: (params: { callId: string, clientId: string }) => string,\n\n\t/** Optional custom serializer; defaults to `JSON.stringify`. */\n\tserializeSample?: (sample: ClientSample) => string,\n};\n\n/**\n * Convenience factory that writes one JSONL file per client, with the path derived from\n * `callId` / `clientId`. Plug into `ObserverConfig.createClientSink`.\n */\nexport function createJsonlFileSinkFactory(options: JsonlFileSinkFactoryOptions): ClientSampleSinkFactory {\n\n\treturn ({ clientId, observedCall }) => {\n\t\tconst filename = options.getFileName?.({ callId: observedCall.callId, clientId }) ?? `${observedCall.callId}__${clientId}.jsonl`;\n\n\t\treturn createJsonlFileSink({\n\t\t\tpath: path.join(options.directory, filename),\n\t\t\tserializeSample: options.serializeSample,\n\t\t});\n\t};\n}\n","import { ClientSampleSink } from './ClientSampleSink';\nimport type { ClientSample } from '../schema/ClientSample';\n\n/**\n * A `ClientSampleSink` that collects the accepted sample objects into an array. Useful for\n * tests and offline replay. Emits `close` on `end()`.\n */\nexport class InMemorySink extends ClientSampleSink {\n\tpublic constructor(public readonly samples: ClientSample[] = []) {\n\t\tsuper();\n\t}\n\n\tpublic write(sample: ClientSample): boolean {\n\t\tthis.samples.push(sample);\n\n\t\treturn true;\n\t}\n\n\tpublic end(): void {\n\t\tthis.emit('close');\n\t}\n}\n\nexport function createInMemorySink(samples?: ClientSample[]): InMemorySink {\n\treturn new InMemorySink(samples);\n}\n","import { ObservedCall } from '../ObservedCall';\nimport { ObservedInboundTrack } from '../ObservedInboundTrack';\nimport { ObservedOutboundTrack } from '../ObservedOutboundTrack';\nimport type { ObserverEvents } from '../ObserverEvents';\n\nexport type RemoteTrackResolverFactory = (observedCall: ObservedCall) => RemoteTrackResolver;\n\n/**\n * Strategy functions that map a track to its publish/subscribe identity. Two tracks are linked\n * when a subscribed (inbound) track's **publisher id** equals a published (outbound) track's\n * **publisher id** — one publisher → many subscribers. The **subscriber id** is optional and is\n * only used to look an inbound track up via `getInboundTrackBySubscriberId`.\n *\n * The \"publisher id\" is whatever a strategy uses as the link key: mediasoup passes its producerId,\n * a p2p strategy the SSRC, a generic strategy a shared attachment value.\n */\nexport type RemoteTrackResolvers = {\n\n\t/** The publisher id a subscribed (inbound) track receives. Required — this is the link key. */\n\tresolveInboundTrackPublisherId: (inboundTrack: ObservedInboundTrack) => string | undefined,\n\n\t/** The publisher id a published (outbound) track represents. Required — this is the link key. */\n\tresolveOutboundTrackPublisherId: (outboundTrack: ObservedOutboundTrack) => string | undefined,\n\n\t/** Optional: the inbound track's own subscription id (enables `getInboundTrackBySubscriberId`). */\n\tresolveInboundTrackSubscriberId?: (inboundTrack: ObservedInboundTrack) => string | undefined,\n};\n\n/**\n * Generic, strategy-driven base resolver. It subscribes to the Observer bus (filtered to one call),\n * links subscribed↔published tracks by publisher id, and maintains the links directly on the tracks\n * (`inboundTrack.remoteOutboundTrack`, `outboundTrack.remoteInboundTracks`).\n *\n * Concrete strategies (mediasoup, p2p-by-SSRC, generic attachment) are just different\n * {@link RemoteTrackResolvers} passed to this class. Ids are re-resolved on demand rather than\n * cached, so the only state kept is the two lookup indexes that back the public getters.\n */\nexport class RemoteTrackResolver {\n\tprivate readonly _publisherIdToOutboundTrack = new Map<string, ObservedOutboundTrack>();\n\tprivate readonly _subscriberIdToInboundTrack = new Map<string, ObservedInboundTrack>();\n\n\tpublic constructor(\n\t\tpublic readonly observedCall: ObservedCall,\n\t\tprivate readonly resolvers: RemoteTrackResolvers,\n\t) {\n\t\tconst observer = observedCall.observer;\n\n\t\t// Subscribe to the central Observer bus, filtering to this call's tracks.\n\t\tconst onInboundAdded = (p: ObserverEvents['inbound-track-added'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._addInboundTrack(p.observedInboundTrack);\n\t\t};\n\t\tconst onInboundRemoved = (p: ObserverEvents['inbound-track-removed'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._removeInboundTrack(p.observedInboundTrack);\n\t\t};\n\t\tconst onOutboundAdded = (p: ObserverEvents['outbound-track-added'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._addOutboundTrack(p.observedOutboundTrack);\n\t\t};\n\t\tconst onOutboundRemoved = (p: ObserverEvents['outbound-track-removed'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._removeOutboundTrack(p.observedOutboundTrack);\n\t\t};\n\n\t\tobservedCall.once('close', () => {\n\t\t\tobserver.off('inbound-track-added', onInboundAdded);\n\t\t\tobserver.off('inbound-track-removed', onInboundRemoved);\n\t\t\tobserver.off('outbound-track-added', onOutboundAdded);\n\t\t\tobserver.off('outbound-track-removed', onOutboundRemoved);\n\t\t});\n\n\t\tobserver.on('inbound-track-added', onInboundAdded);\n\t\tobserver.on('inbound-track-removed', onInboundRemoved);\n\t\tobserver.on('outbound-track-added', onOutboundAdded);\n\t\tobserver.on('outbound-track-removed', onOutboundRemoved);\n\t}\n\n\t/** The published (outbound) track for a publisher id, if any. */\n\tpublic getOutboundTrackByPublisherId(publisherId: string): ObservedOutboundTrack | undefined {\n\t\treturn this._publisherIdToOutboundTrack.get(publisherId);\n\t}\n\n\t/** The subscribed (inbound) track for a subscriber id, if the strategy resolves subscriber ids. */\n\tpublic getInboundTrackBySubscriberId(subscriberId: string): ObservedInboundTrack | undefined {\n\t\treturn this._subscriberIdToInboundTrack.get(subscriberId);\n\t}\n\n\t// RemoteTrackResolver interface — thin readers over the links maintained on the tracks.\n\tpublic resolveRemoteOutboundTrack(inboundTrack: ObservedInboundTrack): ObservedOutboundTrack | undefined {\n\t\treturn inboundTrack.remoteOutboundTrack;\n\t}\n\n\tpublic resolveRemoteInboundTracks(outboundTrack: ObservedOutboundTrack): ObservedInboundTrack[] | undefined {\n\t\treturn [ ...outboundTrack.remoteInboundTracks ];\n\t}\n\n\tprivate _addInboundTrack(inboundTrack: ObservedInboundTrack) {\n\t\tconst publisherId = this.resolvers.resolveInboundTrackPublisherId(inboundTrack);\n\n\t\tif (!publisherId) return;\n\n\t\tconst subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);\n\n\t\tif (subscriberId) {\n\t\t\tthis._subscriberIdToInboundTrack.set(subscriberId, inboundTrack);\n\t\t}\n\n\t\tconst outboundTrack = this._publisherIdToOutboundTrack.get(publisherId);\n\n\t\tif (!outboundTrack) return;\n\n\t\toutboundTrack.remoteInboundTracks.add(inboundTrack);\n\t\tinboundTrack.remoteOutboundTrack = outboundTrack;\n\t}\n\n\tprivate _removeInboundTrack(inboundTrack: ObservedInboundTrack) {\n\t\t// Use the stored link to unlink; no need to re-resolve the publisher id here.\n\t\tinboundTrack.remoteOutboundTrack?.remoteInboundTracks.delete(inboundTrack);\n\t\tinboundTrack.remoteOutboundTrack = undefined;\n\n\t\tconst subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);\n\n\t\tif (subscriberId) {\n\t\t\tthis._subscriberIdToInboundTrack.delete(subscriberId);\n\t\t}\n\t}\n\n\tprivate _addOutboundTrack(outboundTrack: ObservedOutboundTrack) {\n\t\tconst publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);\n\n\t\tif (!publisherId) return;\n\n\t\tthis._publisherIdToOutboundTrack.set(publisherId, outboundTrack);\n\n\t\t// Link any already-present subscribers of this publisher.\n\t\tfor (const observedClient of this.observedCall.observedClients.values()) {\n\t\t\tfor (const observedPeerConnection of observedClient.observedPeerConnections.values()) {\n\t\t\t\tfor (const inboundTrack of observedPeerConnection.observedInboundTracks.values()) {\n\t\t\t\t\tif (this.resolvers.resolveInboundTrackPublisherId(inboundTrack) !== publisherId) continue;\n\n\t\t\t\t\toutboundTrack.remoteInboundTracks.add(inboundTrack);\n\t\t\t\t\tinboundTrack.remoteOutboundTrack = outboundTrack;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _removeOutboundTrack(outboundTrack: ObservedOutboundTrack) {\n\t\tconst publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);\n\n\t\t// Only clear the map entry if it still points at this track (guards republish races).\n\t\tif (publisherId && this._publisherIdToOutboundTrack.get(publisherId) === outboundTrack) {\n\t\t\tthis._publisherIdToOutboundTrack.delete(publisherId);\n\t\t}\n\n\t\tfor (const inboundTrack of outboundTrack.remoteInboundTracks) {\n\t\t\tinboundTrack.remoteOutboundTrack = undefined;\n\t\t}\n\t\toutboundTrack.remoteInboundTracks.clear();\n\t}\n}\n","import { ObservedCall } from '../ObservedCall';\nimport { RemoteTrackResolver, RemoteTrackResolverFactory } from './RemoteTrackResolver';\n\nexport function createDefaultMediasoupRemoteTrackResolverFactory(): RemoteTrackResolverFactory {\n\treturn (observedCall: ObservedCall) => new RemoteTrackResolver(observedCall, {\n\t\tresolveInboundTrackPublisherId: (inboundTrack) => inboundTrack.attachments?.producerId as string | undefined,\n\t\tresolveInboundTrackSubscriberId: (inboundTrack) => inboundTrack.attachments?.consumerId as string | undefined,\n\t\tresolveOutboundTrackPublisherId: (outboundTrack) => outboundTrack.attachments?.producerId as string | undefined,\n\t});\n}\n\nexport function createP2pRemoteTrackResolverFactory(): RemoteTrackResolverFactory {\n\treturn (observedCall: ObservedCall) => new RemoteTrackResolver(observedCall, {\n\t\tresolveInboundTrackPublisherId: (inboundTrack) => {\n\t\t\tconst ssrc = inboundTrack.getInboundRtp()?.ssrc;\n\n\t\t\treturn ssrc ? `${ssrc}` : undefined;\n\t\t},\n\t\tresolveInboundTrackSubscriberId: (inboundTrack) => {\n\t\t\tconst ssrc = inboundTrack.getInboundRtp()?.ssrc;\n\n\t\t\treturn ssrc ? `${ssrc}` : undefined;\n\t\t},\n\t\tresolveOutboundTrackPublisherId: (outboundTrack) => {\n\t\t\t// In p2p the sender's SSRC is preserved end-to-end, so it matches the receiver's\n\t\t\t// inbound SSRC. (Single-encoding case; simulcast would need per-encoding keys.)\n\t\t\tconst rtps = outboundTrack.getOutboundRtps();\n\n\t\t\tif (!rtps || rtps.length === 0) return undefined;\n\n\t\t\treturn rtps.map((rtp) => rtp.ssrc).join(',');\n\t\t}\n\t});\n}\n"],"mappings":"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","names":["module","logger","import_events","import_events","ClientEventTypes","ClientMetaTypes","logger","logger","logger","import_events","import_events","logger","import_events","logger","logger","import_events"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/common/logger.ts","../src/ObservedCall.ts","../src/ObservedClient.ts","../src/ObservedPeerConnection.ts","../src/utils/stats.ts","../src/ObservedInboundRtp.ts","../src/ObservedOutboundRtp.ts","../src/ObservedCertificate.ts","../src/ObservedCodec.ts","../src/ObservedDataChannel.ts","../src/ObservedIceCandidate.ts","../src/ObservedIceCandidatePair.ts","../src/ObservedIceTransport.ts","../src/ObservedMediaSource.ts","../src/ObservedPeerConnectionTransport.ts","../src/ObservedMediaPlayout.ts","../src/ObservedRemoteInboundRtp.ts","../src/ObservedRemoteOutboundRtp.ts","../src/ObservedInboundTrack.ts","../src/ObservedOutboundTrack.ts","../src/common/utils.ts","../src/schema/ClientEventTypes.ts","../src/schema/ClientMetaTypes.ts","../src/common/ActiveClientIssue.ts","../src/scores/DefaultCallScoreCalculator.ts","../src/updaters/OnAllClientCallUpdater.ts","../src/updaters/OnAnyClientCallUpdater.ts","../src/detectors/Detectors.ts","../src/Observer.ts","../src/ObservedTURN.ts","../src/ObservedTurnServer.ts","../src/updaters/OnAllCallObserverUpdater.ts","../src/updaters/OnAnyCallObserverUpdater.ts","../src/common/Middleware.ts","../src/ObservedMediasoupRouter.ts","../src/utils/TrackDistributionAggregator.ts","../src/utils/CallHealthAggregator.ts","../src/detectors/CommonSourceDegradationDetector.ts","../src/detectors/CallWideDegradationDetector.ts","../src/detectors/PliAndFreezeFanOutDetector.ts","../src/detectors/AudioImpairmentFanOutDetector.ts","../src/detectors/IceDisruptionDetector.ts","../src/detectors/TurnServerHealthDetector.ts","../src/utils/IssueRegistry.ts","../src/detectors/ConcurrentIssueDetector.ts","../src/detectors/IssueFanOutDetector.ts","../src/detectors/WorstReceiverContagionDetector.ts","../src/detectors/TrackDeliveryMismatchDetector.ts","../src/detectors/UnconsumedTrackDetector.ts","../src/sinks/ClientSampleSink.ts","../src/sinks/JsonlFileSink.ts","../src/sinks/InMemorySink.ts","../src/utils/RemoteTrackResolver.ts","../src/utils/RemoteTrackResolverFactories.ts"],"sourcesContent":["export type { ObserverEvents, SampleRejectedReason, AcceptContext, CallAppDataFactory, ClientAppDataFactory, AcceptMiddleware, AcceptMiddlewarePayload } from './Observer';\nexport type {\n\tObserverEventBase,\n\tObservedCallScope,\n\tObservedClientScope,\n\tObservedPeerConnectionScope,\n\tObservedMediasoupRouterScope,\n} from './ObserverEvents';\nexport type {\n\tObservedMediasoupRouterSettings,\n\tObservedMediasoupRouterEvents,\n\tMediasoupSampleEnricher,\n} from './ObservedMediasoupRouter';\nexport type {\n\tMediasoupRouterSample,\n\tMediasoupTransportSample,\n\tMediasoupProducerSample,\n\tMediasoupConsumerSample,\n\tMediasoupDataProducerSample,\n\tMediasoupDataConsumerSample,\n\tMediasoupWebRtcTransportSample,\n\tMediasoupPlainTransportSample,\n\tMediasoupPipeTransportSample,\n\tMediasoupDirectTransportSample,\n\tMediasoupWebRtcTransportSampleEventMap,\n\tMediasoupPlainTransportSampleEventMap,\n\tMediasoupPipeTransportSampleEventMap,\n\tMediasoupDirectTransportSampleEventMap,\n\tMediasoupProducerSampleEvent,\n\tMediasoupConsumerSampleEvent,\n} from './schema/MediasoupRouter';\n\nexport { Observer } from './Observer';\nexport { ObservedCall } from './ObservedCall';\nexport { ObservedInboundTrack } from './ObservedInboundTrack';\nexport { ObservedOutboundTrack } from './ObservedOutboundTrack';\nexport { ObservedClient } from './ObservedClient';\nexport { ObservedPeerConnection } from './ObservedPeerConnection';\nexport { ObservedMediaSource } from './ObservedMediaSource';\nexport { ObservedMediaPlayout } from './ObservedMediaPlayout';\nexport { ObservedCodec } from './ObservedCodec';\nexport { ObservedCertificate } from './ObservedCertificate';\nexport { ObservedDataChannel } from './ObservedDataChannel';\nexport { ObservedInboundRtp } from './ObservedInboundRtp';\nexport { ObservedOutboundRtp } from './ObservedOutboundRtp';\nexport { ObservedRemoteInboundRtp } from './ObservedRemoteInboundRtp';\nexport { ObservedRemoteOutboundRtp } from './ObservedRemoteOutboundRtp';\nexport { ObservedMediasoupRouter } from './ObservedMediasoupRouter';\nexport { ObservedIceCandidatePair } from './ObservedIceCandidatePair';\nexport { ObservedIceCandidate } from './ObservedIceCandidate';\nexport { ObservedIceTransport } from './ObservedIceTransport';\nexport { ObservedPeerConnectionTransport } from './ObservedPeerConnectionTransport';\nexport { ClientEventTypes } from './schema/ClientEventTypes';\nexport { ClientMetaTypes } from './schema/ClientMetaTypes';\nexport { ClientSample, ClientIssue, ClientEvent, ClientMetaData } from './schema/ClientSample';\nexport { ScoreCalculator } from './scores/ScoreCalculator';\nexport { Detectors } from './detectors/Detectors';\nexport type { Detector } from './detectors/Detector';\n// Cross-client detection: the publisher→subscribers aggregation primitive and the detectors on it.\nexport {\n\tTrackDistributionAggregator,\n\tdefaultReceiverHealthThresholds,\n} from './utils/TrackDistributionAggregator';\nexport type {\n\tObservedTrackDistribution,\n\tReceiverDistributionEntry,\n\tPublisherDistributionEntry,\n\tReceiverHealthThresholds,\n} from './utils/TrackDistributionAggregator';\nexport {\n\tCallHealthAggregator,\n\tdefaultClientHealthThresholds,\n} from './utils/CallHealthAggregator';\nexport type {\n\tCallHealth,\n\tClientHealth,\n\tClientHealthThresholds,\n} from './utils/CallHealthAggregator';\n// Concrete cross-client detectors (all opt-in — register them on `call.detectors` /\n// `observer.detectors`; the library ships none of them enabled).\nexport {\n\tCommonSourceDegradationDetector,\n\tCommonSourceDegradationTypes,\n} from './detectors/CommonSourceDegradationDetector';\nexport type { CommonSourceDegradationDetectorConfig } from './detectors/CommonSourceDegradationDetector';\nexport {\n\tCallWideDegradationDetector,\n\tCallWideDegradationTypes,\n} from './detectors/CallWideDegradationDetector';\nexport type { CallWideDegradationDetectorConfig } from './detectors/CallWideDegradationDetector';\nexport {\n\tPliAndFreezeFanOutDetector,\n\tPliAndFreezeFanOutTypes,\n} from './detectors/PliAndFreezeFanOutDetector';\nexport type { PliAndFreezeFanOutDetectorConfig } from './detectors/PliAndFreezeFanOutDetector';\nexport {\n\tAudioImpairmentFanOutDetector,\n\tAudioImpairmentFanOutTypes,\n} from './detectors/AudioImpairmentFanOutDetector';\nexport type { AudioImpairmentFanOutDetectorConfig } from './detectors/AudioImpairmentFanOutDetector';\nexport {\n\tIceDisruptionDetector,\n\tIceDisruptionTypes,\n} from './detectors/IceDisruptionDetector';\nexport type { IceDisruptionDetectorConfig } from './detectors/IceDisruptionDetector';\nexport {\n\tTurnServerHealthDetector,\n\tTurnServerHealthTypes,\n} from './detectors/TurnServerHealthDetector';\nexport type { TurnServerHealthDetectorConfig, TurnServerHealth } from './detectors/TurnServerHealthDetector';\n// Issue-driven correlation: the client reports WHAT is wrong for itself, the observer correlates\n// WHO ELSE is in the same state and WHERE in publisher -> SFU -> subscriber the fault sits.\nexport { IssueRegistry } from './utils/IssueRegistry';\nexport type { IssueCohort, IssueRegistryConfig } from './utils/IssueRegistry';\nexport {\n\tRESOLVED_ISSUE_SUFFIX,\n\tbaseIssueType,\n\tisResolutionEntry,\n\tparseIssuePayload,\n} from './common/ActiveClientIssue';\nexport type { ActiveClientIssue, ResolvedClientIssue } from './common/ActiveClientIssue';\nexport {\n\tConcurrentIssueDetector,\n\tConcurrentIssueTypes,\n} from './detectors/ConcurrentIssueDetector';\nexport type { ConcurrentIssueDetectorConfig } from './detectors/ConcurrentIssueDetector';\nexport {\n\tIssueFanOutDetector,\n\tIssueFanOutTypes,\n} from './detectors/IssueFanOutDetector';\nexport type { IssueFanOutDetectorConfig } from './detectors/IssueFanOutDetector';\nexport {\n\tWorstReceiverContagionDetector,\n\tWorstReceiverContagionTypes,\n} from './detectors/WorstReceiverContagionDetector';\nexport type { WorstReceiverContagionDetectorConfig } from './detectors/WorstReceiverContagionDetector';\nexport {\n\tTrackDeliveryMismatchDetector,\n\tTrackDeliveryMismatchTypes,\n} from './detectors/TrackDeliveryMismatchDetector';\nexport type { TrackDeliveryMismatchDetectorConfig } from './detectors/TrackDeliveryMismatchDetector';\nexport {\n\tUnconsumedTrackDetector,\n\tUnconsumedTrackTypes,\n} from './detectors/UnconsumedTrackDetector';\nexport type { UnconsumedTrackDetectorConfig } from './detectors/UnconsumedTrackDetector';\n// Statistics helpers for building your own detectors.\nexport { percentile, median, summarize, counterDelta, SlidingWindow } from './utils/stats';\nexport type { StatsSummary, SlidingWindowEntry } from './utils/stats';\nexport { createLogger, setObserverLogger } from './common/logger';\nexport type { Logger, ObserverLogger } from './common/logger';\n// Per-client sample sinks. `ClientSampleSink` is the base class to subclass for a custom\n// destination; `JsonlFileSink` / `InMemorySink` are the built-ins.\nexport {\n\tClientSampleSink,\n\tJsonlFileSink,\n\tcreateJsonlFileSink,\n\tcreateJsonlFileSinkFactory,\n\tInMemorySink,\n\tcreateInMemorySink,\n} from './sinks';\nexport type {\n\tClientSampleSinkEvents,\n\tClientSampleSinkFactory,\n\tJsonlFileSinkOptions,\n\tJsonlFileSinkFactoryOptions,\n} from './sinks';\nexport { Middleware } from './common/Middleware';\n// Remote track correlation: the generic resolver + built-in strategy factories.\nexport { RemoteTrackResolver } from './utils/RemoteTrackResolver';\nexport type { RemoteTrackResolvers, RemoteTrackResolverFactory } from './utils/RemoteTrackResolver';\nexport {\n\tcreateDefaultMediasoupRemoteTrackResolverFactory,\n\tcreateP2pRemoteTrackResolverFactory,\n} from './utils/RemoteTrackResolverFactories';\n","export interface Logger {\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\ttrace(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tdebug(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tinfo(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\twarn(...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\terror(...args: any[]): void;\n}\n\nexport interface ObserverLogger {\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\ttrace(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tdebug(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\tinfo(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\twarn(module: string, ...args: any[]): void;\n\t/* eslint-disable @typescript-eslint/no-explicit-any */\n\terror(module: string, ...args: any[]): void;\n}\n\nlet mainLogger: ObserverLogger = new class implements ObserverLogger {\n\ttrace = () => void 0;\n\t// trace(module: string, ...args: any[]) {\n\t// \t// eslint-disable-next-line no-console\n\t// \tconsole.log(`[TRACE] ${module}`, ...args);\n\t// }\n\n\tdebug(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(`[DEBUG] ${module}`, ...args);\n\t}\n\n\tinfo(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.info(`[INFO] ${module}`, ...args);\n\t}\n\n\twarn(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(`[WARN] ${module}`, ...args);\n\t}\n\n\terror(module: string, ...args: any[]) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(`[ERROR] ${module}`, ...args);\n\t}\n}();\n\nexport function createLogger(moduleName: string): Logger {\n\treturn new class implements Logger {\n\t\ttrace(...args: any[]) {\n\t\t\tmainLogger.trace(moduleName, ...args);\n\t\t}\n\n\t\tdebug(...args: any[]) {\n\t\t\tmainLogger.debug(moduleName, ...args);\n\t\t}\n\n\t\tinfo(...args: any[]) {\n\t\t\tmainLogger.info(moduleName, ...args);\n\t\t}\n\n\t\twarn(...args: any[]) {\n\t\t\tmainLogger.warn(moduleName, ...args);\n\t\t}\n\n\t\terror(...args: any[]) {\n\t\t\tmainLogger.error(moduleName, ...args);\n\t\t}\n\n\t}();\n}\n\nexport function setObserverLogger(logger: ObserverLogger) {\n\tmainLogger = logger;\n}\n","import { EventEmitter } from 'events';\nimport { createLogger } from './common/logger';\nimport { ObservedClient, ObservedClientSettings } from './ObservedClient';\nimport { Observer } from './Observer';\nimport { ScoreCalculator } from './scores/ScoreCalculator';\nimport { CalculatedScore } from './scores/CalculatedScore';\nimport { DefaultCallScoreCalculator } from './scores/DefaultCallScoreCalculator';\nimport { RemoteTrackResolver } from './utils/RemoteTrackResolver';\nimport { OnAllClientCallUpdater } from './updaters/OnAllClientCallUpdater';\nimport { Updater } from './updaters/Updater';\nimport { OnAnyClientCallUpdater } from './updaters/OnAnyClientCallUpdater';\nimport { Detectors } from './detectors/Detectors';\nimport { ClientIssue } from './schema/ClientSample';\nimport type { AcceptContext } from './Observer';\nimport type { ObserverEvents, ObservedCallScope } from './ObserverEvents';\n\nconst logger = createLogger('ObservedCall');\n\n// Updates are event-driven: triggered when any/all clients in the call have updated. `'none'`\n// disables the automatic trigger — the application must call `call.update()` itself.\n// (Apps wanting a fixed cadence can call `call.update()` on their own timer.)\ntype ObservedCallUpdateConfig = {\n\tupdatePolicy?: 'update-on-any-client-updated' | 'update-when-all-client-updated' | 'none',\n};\n\nexport type ObservedCallSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = ObservedCallUpdateConfig & {\n\tcallId: string;\n\tappData?: AppData;\n\tcloseCallIfEmptyForMs?: number,\n};\n\nexport type ObservedCallEvents = {\n\tupdate: [],\n\tnewclient: [ObservedClient],\n\tempty: [],\n\t'not-empty': [],\n\tclose: [],\n}\n\nexport declare interface ObservedCall {\n\ton<U extends keyof ObservedCallEvents>(event: U, listener: (...args: ObservedCallEvents[U]) => void): this;\n\toff<U extends keyof ObservedCallEvents>(event: U, listener: (...args: ObservedCallEvents[U]) => void): this;\n\tonce<U extends keyof ObservedCallEvents>(event: U, listener: (...args: ObservedCallEvents[U]) => void): this;\n\temit<U extends keyof ObservedCallEvents>(event: U, ...args: ObservedCallEvents[U]): boolean;\n}\n\nexport class ObservedCall<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic updater?: Updater;\n\tpublic scoreCalculator: ScoreCalculator;\n\tpublic readonly detectors: Detectors;\n\tpublic readonly callId: string;\n\tpublic readonly observedClients = new Map<string, ObservedClient>();\n\tpublic readonly clientsUsedTurn = new Set<string>();\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\tpublic remoteTrackResolver?: RemoteTrackResolver;\n\n\tpublic totalAddedClients = 0;\n\tpublic totalRemovedClients = 0;\n\n\tpublic numberOfIssues = 0;\n\tpublic numberOfPeerConnections = 0;\n\tpublic numberOfInboundRtpStreams = 0;\n\tpublic numberOfOutboundRtpStreams = 0;\n\tpublic numberOfDataChannels = 0;\n\n\tpublic maxNumberOfClients = 0;\n\tpublic deltaNumberOfIssues = 0;\n\n\t// public deltaRttLt50Measurements = 0;\n\t// public deltaRttLt150Measurements = 0;\n\t// public deltaRttLt300Measurements = 0;\n\t// public deltaRttGtOrEq300Measurements = 0;\n\n\tpublic appData: AppData;\n\tpublic closed = false;\n\tpublic startedAt?: number;\n\tpublic endedAt?: number;\n\tpublic closedAt?: number;\n\n\tpublic readonly settings: Pick<ObservedCallSettings, 'closeCallIfEmptyForMs'>;\n\n\t/** Ancestry base shared by all Observer-bus events originating at this call. */\n\tpublic readonly eventScope: ObservedCallScope;\n\tprivate closeTimer?: ReturnType<typeof setTimeout>;\n\n\tpublic constructor(\n\t\tsettings: ObservedCallSettings<AppData>,\n\t\tpublic readonly observer: Observer,\n\t) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\n\t\tthis.eventScope = { observer: this.observer, observedCall: this };\n\t\tthis.callId = settings.callId;\n\t\tthis.appData = (settings.appData ?? {}) as AppData;\n\t\tthis.scoreCalculator = new DefaultCallScoreCalculator(this);\n\t\t// No built-in detectors ship yet. The registry is a server-side extension point:\n\t\t// add custom call-level Detectors via `call.detectors.add(...)` and surface findings\n\t\t// with `call.addIssue(...)` (emitted on the Observer bus as `call-issue`).\n\t\tthis.detectors = new Detectors();\n\n\t\tswitch (settings.updatePolicy) {\n\t\t\tcase 'update-on-any-client-updated':\n\t\t\t\tthis.updater = new OnAnyClientCallUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'update-when-all-client-updated':\n\t\t\t\tthis.updater = new OnAllClientCallUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'none':\n\t\t\t\t// No automatic updater: `call.update()` only runs when the app calls it.\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis.settings = {\n\t\t\tcloseCallIfEmptyForMs: settings.closeCallIfEmptyForMs,\n\t\t};\n\t}\n\n\tpublic get numberOfClients() {\n\t\treturn this.observedClients.size;\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\t/** Raise a call-level (server-side) issue; surfaced on the Observer bus as `call-issue`. */\n\tpublic addIssue(issue: ClientIssue) {\n\t\tif (this.closed) return;\n\n\t\tthis._notify('call-issue', { ...this.eventScope, issue });\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\t\tthis.update(); // last update before closing\n\t\tthis.closed = true;\n\n\t\tthis.updater?.close();\n\n\t\tlet minSampleTimestamps: number | undefined;\n\t\tlet maxSampleTimestamps: number | undefined;\n\n\t\tfor (const client of this.observedClients.values()) {\n\t\t\tclient.close();\n\n\t\t\tif (client.joinedAt) minSampleTimestamps = Math.min(minSampleTimestamps ?? client.joinedAt, client.joinedAt);\n\t\t\tif (client.leftAt) maxSampleTimestamps = Math.max(maxSampleTimestamps ?? client.leftAt, client.leftAt);\n\t\t}\n\n\t\tif (this.startedAt === undefined) this.startedAt = minSampleTimestamps;\n\t\tif (this.endedAt === undefined) this.endedAt = maxSampleTimestamps;\n\n\t\tthis.closedAt = Date.now();\n\t\t// Release detectors (they may hold bus subscriptions) before announcing the close.\n\t\tthis.detectors.clear();\n\t\tthis.emit('close');\n\t\tthis._notify('call-closed', { ...this.eventScope });\n\t}\n\n\tpublic getObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(clientId: string): ObservedClient<ClientAppData> | undefined {\n\t\tif (this.closed || !this.observedClients.has(clientId)) return;\n\n\t\treturn this.observedClients.get(clientId) as ObservedClient<ClientAppData>;\n\t}\n\n\tpublic createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>): ObservedClient<ClientAppData> | undefined {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to create a client (clientId: %s) on a closed call %s', settings.clientId, this.callId);\n\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this.observedClients.has(settings.clientId)) {\n\t\t\tlogger.warn('Client with id %s already exists in call %s; returning the existing instance', settings.clientId, this.callId);\n\n\t\t\treturn this.observedClients.get(settings.clientId) as ObservedClient<ClientAppData>;\n\t\t}\n\n\t\tif (!settings.closeClientIfIdleForMs) {\n\t\t\tsettings.closeClientIfIdleForMs = this.observer.config.closeClientIfIdleForMs;\n\t\t}\n\t\tif (settings.appData === undefined) {\n\t\t\tsettings.appData = this.observer.config.createClientAppData?.({ clientId: settings.clientId, observedCall: this }) as ClientAppData;\n\t\t}\n\n\t\tconst result = new ObservedClient<ClientAppData>(settings, this);\n\t\tconst wasEmpty = this.observedClients.size === 0;\n\t\tconst onUpdate = () => this._onClientUpdate(result);\n\t\tconst joined = () => this._clientJoined(result);\n\t\tconst left = () => this._clientLeft(result);\n\n\t\tresult.once('close', () => {\n\t\t\tresult.off('update', onUpdate);\n\t\t\tresult.off('joined', joined);\n\t\t\tresult.off('left', left);\n\t\t\tthis.observedClients.delete(settings.clientId);\n\n\t\t\tif (this.observedClients.size === 0) {\n\t\t\t\tthis.emit('empty');\n\t\t\t\tthis._notify('call-empty', { ...this.eventScope });\n\n\t\t\t\tif (this.settings.closeCallIfEmptyForMs) {\n\t\t\t\t\tthis.closeTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.close();\n\t\t\t\t\t}, this.settings.closeCallIfEmptyForMs);\n\t\t\t\t}\n\t\t\t}\n\t\t\t++this.totalRemovedClients;\n\t\t});\n\t\tresult.on('update', onUpdate);\n\t\tresult.on('joined', joined);\n\t\tresult.on('left', left);\n\t\t++this.totalAddedClients;\n\n\t\tthis.observedClients.set(settings.clientId, result);\n\t\tthis.maxNumberOfClients = Math.max(this.maxNumberOfClients, this.observedClients.size);\n\n\t\tif (this.closeTimer) {\n\t\t\tclearTimeout(this.closeTimer);\n\t\t\tthis.closeTimer = undefined;\n\t\t}\n\n\t\tthis.emit('newclient', result);\n\t\tthis._notify('client-added', { ...this.eventScope, observedClient: result });\n\n\t\tif (result.sink) {\n\t\t\tthis._notify('client-sink-created', { ...this.eventScope, observedClient: result, sink: result.sink });\n\t\t}\n\n\t\tif (wasEmpty) {\n\t\t\tthis.emit('not-empty');\n\t\t\tthis._notify('call-not-empty', { ...this.eventScope });\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic getOrCreateObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedClientSettings<ClientAppData>\n\t): ObservedClient<ClientAppData> | undefined {\n\t\treturn this.getObservedClient<ClientAppData>(settings.clientId) ?? this.createObservedClient<ClientAppData>(settings);\n\t}\n\n\tpublic update(context?: AcceptContext) {\n\t\tif (this.closed) return;\n\n\t\tthis.numberOfInboundRtpStreams = 0;\n\t\tthis.numberOfOutboundRtpStreams = 0;\n\t\tthis.numberOfPeerConnections = 0;\n\t\tthis.numberOfDataChannels = 0;\n\n\t\tfor (const client of this.observedClients.values()) {\n\t\t\tthis.numberOfInboundRtpStreams += client.numberOfInboundRtpStreams;\n\t\t\tthis.numberOfOutboundRtpStreams += client.numberOfOutboundRtpStreams;\n\t\t\tthis.numberOfPeerConnections += client.numberOfPeerConnections;\n\t\t\tthis.numberOfDataChannels += client.numberOfDataChannels;\n\t\t}\n\n\t\tthis.scoreCalculator.update();\n\t\tthis.detectors.update();\n\n\t\tthis.emit('update');\n\t\tthis._notify('call-updated', { ...this.eventScope, context });\n\n\t\tthis.deltaNumberOfIssues = 0;\n\t}\n\n\tprivate _onClientUpdate(client: ObservedClient) {\n\t\tthis.deltaNumberOfIssues += client.deltaNumberOfIssues;\n\t\tthis.numberOfIssues += client.deltaNumberOfIssues;\n\n\t\tif (client.usingTURN) {\n\t\t\tthis.clientsUsedTurn.add(client.clientId);\n\t\t}\n\t}\n\n\tprivate _clientJoined(client: ObservedClient) {\n\t\tif (!client.joinedAt) return;\n\n\t\tthis.startedAt = Math.min(this.startedAt ?? client.joinedAt, client.joinedAt);\n\t}\n\n\tprivate _clientLeft(client: ObservedClient) {\n\t\tif (!client.leftAt) return;\n\n\t\tthis.endedAt = Math.max(this.endedAt ?? client.leftAt, client.leftAt);\n\t}\n\n\t/** Emit an Observer-bus event scoped to this call. */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.observer.emit(type, ...args);\n\t}\n}","import { EventEmitter } from 'events';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { createLogger } from './common/logger';\n// eslint-disable-next-line camelcase\nimport { ClientEvent, ClientMetaData, ClientSample, PeerConnectionSample, ClientIssue, ExtensionStat } from './schema/ClientSample';\nimport * as MetaData from './schema/ClientMetaTypes';\nimport { ClientEventTypes } from './schema/ClientEventTypes';\nimport { ObservedCall } from './ObservedCall';\nimport { ClientMetaTypes } from './schema/ClientMetaTypes';\nimport { parseJsonAs } from './common/utils';\nimport { CalculatedScore } from './scores/CalculatedScore';\nimport type { AcceptContext } from './Observer';\nimport type { ObserverEvents, ObservedClientScope } from './ObserverEvents';\nimport type { ClientSampleSink } from './sinks/ClientSampleSink';\nimport {\n\tActiveClientIssue,\n\tResolvedClientIssue,\n\tbaseIssueType,\n\tisResolutionEntry,\n\tparseIssuePayload,\n} from './common/ActiveClientIssue';\n\nconst logger = createLogger('ObservedClient');\n\nexport type ObservedClientSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {\n\tclientId: string;\n\tappData?: AppData;\n\tcloseClientIfIdleForMs?: number;\n};\n\n// Local lifecycle/coordination events only. Everything worth subscribing to is\n// emitted on the Observer bus (see ObserverEvents). These remain local so the\n// parent ObservedCall and the updaters can wire to them for teardown/aggregation.\nexport type ObservedClientEvents = {\n\tupdate: [sample: ClientSample, elapsedTimeInMs: number, context?: AcceptContext];\n\tclose: [];\n\tjoined: [];\n\tleft: [];\n};\n\nexport declare interface ObservedClient {\n\ton<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;\n\toff<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;\n\tonce<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;\n\temit<U extends keyof ObservedClientEvents>(event: U, ...args: ObservedClientEvents[U]): boolean;\n}\n\nexport class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic readonly clientId: string;\n\tpublic readonly observedPeerConnections = new Map<string, ObservedPeerConnection>();\n\n\t/** Per-client sink (from `ObserverConfig.createClientSink`), if any. */\n\tpublic readonly sink?: ClientSampleSink;\n\n\t/** Ancestry base shared by all Observer-bus events originating at this client. */\n\tpublic readonly eventScope: ObservedClientScope;\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\n\tpublic readonly settings: Pick<ObservedClientSettings, 'closeClientIfIdleForMs'>;\n\n\tpublic appData: AppData;\n\tpublic attachments?: Record<string, unknown>;\n\n\tpublic updated = Date.now();\n\tpublic acceptedSamples = 0;\n\tpublic closed = false;\n\n\tpublic joinedAt?: number;\n\tpublic leftAt?: number;\n\tpublic closedAt?: number;\n\tpublic lastSampleTimestamp?: number;\n\t// the timestamp of the CLIENT_JOINED event\n\tpublic operationSystem?: MetaData.OperationSystem;\n\tpublic engine?: MetaData.Engine;\n\tpublic platform?: MetaData.Platform;\n\tpublic browser?: MetaData.Browser;\n\tpublic mediaConstraints: string[] = [];\n\n\tpublic usingTURN = false;\n\tpublic usingTCP = false;\n\tpublic availableOutgoingBitrate = 0;\n\tpublic availableIncomingBitrate = 0;\n\n\tpublic deltaReceivedAudioBytes = 0;\n\tpublic deltaReceivedVideoBytes = 0;\n\tpublic deltaSentAudioBytes = 0;\n\tpublic deltaSentVideoBytes = 0;\n\tpublic deltaDataChannelBytesSent = 0;\n\tpublic deltaDataChannelBytesReceived = 0;\n\tpublic deltaDataChannelMessagesSent = 0;\n\tpublic deltaDataChannelMessagesReceived = 0;\n\tpublic deltaInboundPacketsLost = 0;\n\tpublic deltaInboundPacketsReceived = 0;\n\tpublic deltaOutboundPacketsSent = 0;\n\tpublic deltaTransportSentBytes = 0;\n\tpublic deltaTransportReceivedBytes = 0;\n\tpublic deltaRttLt50Measurements = 0;\n\tpublic deltaRttLt150Measurements = 0;\n\tpublic deltaRttLt300Measurements = 0;\n\tpublic deltaRttGtOrEq300Measurements = 0;\n\n\tpublic currentMaxRttInMs?: number;\n\tpublic currentMinRttInMs?: number;\n\tpublic currentAvgRttInMs?: number;\n\n\tpublic sendingAudioBitrate = 0;\n\tpublic sendingVideoBitrate = 0;\n\tpublic receivingAudioBitrate = 0;\n\tpublic receivingVideoBitrate = 0;\n\n\tpublic numberOfInboundRtpStreams = 0;\n\tpublic numberOfInbundTracks = 0;\n\tpublic numberOfOutboundRtpStreams = 0;\n\tpublic numberOfOutboundTracks = 0;\n\tpublic numberOfDataChannels = 0;\n\n\tpublic deltaNumberOfIssues = 0;\n\n\tpublic totalScoreSum = 0;\n\tpublic numberOfScoreMeasurements = 0;\n\t// public totalNumberOfIssues = 0;\n\n\tpublic readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];\n\tpublic issues: ClientIssue[] = [];\n\n\t/**\n\t * The client's currently **open** stateful issues, keyed by `ClientIssue.key` — the server-side\n\t * mirror of the client monitor's own active-issue map (client-monitor-js >= 4.6.0).\n\t *\n\t * This turns point-in-time symptom reports into intervals, which is what lets detectors ask\n\t * \"are these clients broken *at the same time*\" instead of \"did they both report something\n\t * recently\". Entries are opened by a raise, closed by the matching `<type>-resolved` entry, and\n\t * force-closed when the client closes.\n\t */\n\tpublic readonly activeIssues = new Map<string, ActiveClientIssue>();\n\n\tprivate _pendingInjections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};\n\tprivate _activeSample?: ClientSample;\n\n\tprivate closeTimer?: ReturnType<typeof setTimeout>;\n\n\tpublic constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\n\t\tthis.eventScope = { observer: call.observer, observedCall: call, observedClient: this };\n\t\tthis.sink = call.observer.config.createClientSink?.({ clientId: settings.clientId, observedCall: call });\n\t\tthis.clientId = settings.clientId;\n\t\tthis.appData = (settings.appData ?? {}) as AppData;\n\n\t\tthis.settings = {\n\t\t\tcloseClientIfIdleForMs: settings.closeClientIfIdleForMs,\n\t\t};\n\n\t\tif (this.sink) {\n\t\t\tconst onError = (err: Error) => logger.warn('ClientSampleSink error for client %s: %o', this.clientId, err);\n\n\t\t\tthis.sink.once('close', () => this.sink?.off('error', onError));\n\t\t\tthis.sink.on('error', onError);\n\t\t}\n\t}\n\n\tpublic get numberOfPeerConnections() {\n\t\treturn this.observedPeerConnections.size;\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\n\t\tthis._flushPendingInjections();\n\n\t\t// Close any issue the client never resolved (crash, network death, or a monitor that did not\n\t\t// auto-resolve on close). Without this, correlators reading the active set would keep a\n\t\t// departed client's issues open forever and fire indefinitely.\n\t\tthis.resolveActiveIssues('client-closed');\n\n\t\tthis.closed = true;\n\n\t\tArray.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());\n\t\tif (!this.leftAt) {\n\t\t\tthis.leftAt = this.lastSampleTimestamp;\n\n\t\t\tif (this.leftAt) {\n\t\t\t\tthis.emit('left');\n\t\t\t\tthis._notify('client-left', { ...this.eventScope });\n\t\t\t}\n\t\t}\n\t\tthis.closedAt = Date.now();\n\n\t\tthis.emit('close');\n\t\tthis._notify('client-closed', { ...this.eventScope });\n\n\t\ttry {\n\t\t\tthis.sink?.end();\n\t\t} catch (err) {\n\t\t\tlogger.warn('ClientSampleSink.end failed for client %s: %o', this.clientId, err);\n\t\t}\n\t}\n\n\tpublic accept(sample: ClientSample, context?: AcceptContext): void {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to accept a sample on a closed client %s', this.clientId);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.closeTimer) {\n\t\t\tclearTimeout(this.closeTimer);\n\t\t\tthis.closeTimer = undefined;\n\t\t}\n\n\t\tconst now = Date.now();\n\t\tconst elapsedInMs = now - this.updated;\n\t\tconst elapsedInSeconds = elapsedInMs / 1000;\n\t\tlet sumOfRtts = 0;\n\t\tlet numberOfRttMeasurements = 0;\n\n\t\t++this.acceptedSamples;\n\n\t\tthis.availableIncomingBitrate = 0;\n\t\tthis.availableOutgoingBitrate = 0;\n\t\tthis.deltaDataChannelBytesReceived = 0;\n\t\tthis.deltaDataChannelBytesSent = 0;\n\t\tthis.deltaDataChannelMessagesReceived = 0;\n\t\tthis.deltaDataChannelMessagesSent = 0;\n\t\tthis.deltaInboundPacketsLost = 0;\n\t\tthis.deltaInboundPacketsReceived = 0;\n\t\tthis.deltaOutboundPacketsSent = 0;\n\t\tthis.deltaReceivedAudioBytes = 0;\n\t\tthis.deltaReceivedVideoBytes = 0;\n\t\tthis.deltaSentAudioBytes = 0;\n\t\tthis.deltaSentVideoBytes = 0;\n\t\tthis.deltaTransportReceivedBytes = 0;\n\t\tthis.deltaTransportSentBytes = 0;\n\t\tthis.deltaRttLt50Measurements = 0;\n\t\tthis.deltaRttLt150Measurements = 0;\n\t\tthis.deltaRttLt300Measurements = 0;\n\t\tthis.deltaRttGtOrEq300Measurements = 0;\n\t\tthis.deltaNumberOfIssues = 0;\n\n\t\tthis.numberOfDataChannels = 0;\n\t\tthis.numberOfInboundRtpStreams = 0;\n\t\tthis.numberOfInbundTracks = 0;\n\t\tthis.numberOfOutboundRtpStreams = 0;\n\t\tthis.numberOfOutboundTracks = 0;\n\t\tthis.usingTURN = false;\n\t\tthis.usingTCP = false;\n\t\tthis.currentMinRttInMs = undefined;\n\t\tthis.currentMaxRttInMs = undefined;\n\n\t\tthis._mergePendingInjections(sample);\n\n\t\t// From here until the end of accept, `inject*` targets this sample directly (see `_activeSample`).\n\t\tthis._activeSample = sample;\n\n\t\tconst clientEventsPostBuffer: ClientEvent[] = [];\n\n\t\tfor (const clientEvent of sample.clientEvents ?? []) {\n\t\t\tthis._processClientEvent(clientEvent, clientEventsPostBuffer);\n\t\t}\n\n\t\tfor (const metaData of sample.clientMetaItems ?? []) {\n\t\t\tthis.addMetadata(metaData);\n\t\t}\n\n\t\tfor (const issue of sample.clientIssues ?? []) {\n\t\t\tthis.addIssue(issue);\n\n\t\t\t++this.deltaNumberOfIssues;\n\t\t}\n\n\t\tfor (const extensionStat of sample.extensionStats ?? []) {\n\t\t\tthis.addExtensionStats(extensionStat);\n\t\t}\n\n\t\tfor (const pcSample of sample.peerConnections ?? []) {\n\t\t\tconst observedPeerConnection = this._updatePeerConnection(pcSample, context);\n\n\t\t\tif (!observedPeerConnection) continue;\n\n\t\t\tthis.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;\n\t\t\tthis.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;\n\t\t\tthis.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;\n\t\t\tthis.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;\n\t\t\tthis.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;\n\t\t\tthis.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;\n\t\t\tthis.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;\n\t\t\tthis.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;\n\t\t\tthis.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;\n\t\t\tthis.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;\n\t\t\tthis.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;\n\t\t\tthis.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;\n\t\t\tthis.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;\n\n\t\t\tthis.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;\n\t\t\tthis.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;\n\n\t\t\tthis.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;\n\t\t\tthis.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;\n\t\t\tthis.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;\n\t\t\tthis.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;\n\t\t\tthis.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;\n\n\t\t\tif (observedPeerConnection.usingTURN) {\n\t\t\t\tthis.usingTURN = true;\n\t\t\t}\n\t\t\tif (observedPeerConnection.usingTCP) {\n\t\t\t\tthis.usingTCP = true;\n\t\t\t}\n\n\t\t\tif (observedPeerConnection.currentRttInMs) {\n\t\t\t\tif (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {\n\t\t\t\t\tthis.currentMinRttInMs = observedPeerConnection.currentRttInMs;\n\t\t\t\t}\n\t\t\t\tif (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {\n\t\t\t\t\tthis.currentMaxRttInMs = observedPeerConnection.currentRttInMs;\n\t\t\t\t}\n\t\t\t\tif (observedPeerConnection.currentRttInMs < 50) {\n\t\t\t\t\tthis.deltaRttLt50Measurements += 1;\n\t\t\t\t} else if (observedPeerConnection.currentRttInMs < 150) {\n\t\t\t\t\tthis.deltaRttLt150Measurements += 1;\n\t\t\t\t} else if (observedPeerConnection.currentRttInMs < 300) {\n\t\t\t\t\tthis.deltaRttLt300Measurements += 1;\n\t\t\t\t} else if (300 <= observedPeerConnection.currentRttInMs) {\n\t\t\t\t\tthis.deltaRttGtOrEq300Measurements += 1;\n\t\t\t\t}\n\n\t\t\t\tsumOfRtts += observedPeerConnection.currentRttInMs;\n\t\t\t\t++numberOfRttMeasurements;\n\t\t\t}\n\t\t}\n\n\t\tfor (const clientEvent of clientEventsPostBuffer) {\n\t\t\tthis._processClientEvent(clientEvent);\n\t\t}\n\n\t\t// emit new attachments?\n\t\tthis.attachments = sample.attachments;\n\n\t\t// Guard the division: two samples accepted within the same millisecond make `elapsedInSeconds`\n\t\t// 0, which previously produced Infinity/NaN bitrates that then poisoned every aggregate above.\n\t\tif (0 < elapsedInSeconds) {\n\t\t\tthis.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / elapsedInSeconds;\n\t\t\tthis.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / elapsedInSeconds;\n\t\t\tthis.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / elapsedInSeconds;\n\t\t\tthis.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / elapsedInSeconds;\n\t\t} else {\n\t\t\tthis.receivingAudioBitrate = 0;\n\t\t\tthis.receivingVideoBitrate = 0;\n\t\t\tthis.sendingAudioBitrate = 0;\n\t\t\tthis.sendingVideoBitrate = 0;\n\t\t}\n\t\tthis.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;\n\n\t\tthis.calculatedScore.value = sample.score;\n\n\t\tthis.lastSampleTimestamp = sample.timestamp;\n\t\t// emit update\n\t\tconst elapsedTimeInMs = now - this.updated;\n\n\t\tthis.emit('update', sample, elapsedTimeInMs, context);\n\t\tthis._notify('client-updated', { ...this.eventScope, sample, elapsedTimeInMs, context });\n\t\tthis.updated = now;\n\n\t\t// if result changed after update\n\t\tif (this.calculatedScore.value) {\n\t\t\tthis.totalScoreSum += this.calculatedScore.value;\n\t\t\t++this.numberOfScoreMeasurements;\n\t\t}\n\n\t\tif (this.settings.closeClientIfIdleForMs !== undefined) {\n\t\t\tthis.closeTimer = setTimeout(() => {\n\t\t\t\tthis.close();\n\t\t\t}, this.settings.closeClientIfIdleForMs);\n\t\t}\n\n\t\t// Done processing this sample. Stop directing injections at it, then persist the FINAL,\n\t\t// injection-merged sample to the sink (this is why the sink write is here, not at the top).\n\t\tthis._activeSample = undefined;\n\t\ttry {\n\t\t\tthis.sink?.write(sample);\n\t\t} catch (err) {\n\t\t\tlogger.warn('ClientSampleSink.write failed for client %s: %o', this.clientId, err);\n\t\t}\n\t}\n\n\tpublic injectMetaData(metaData: ClientMetaData) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.clientMetaItems) this._activeSample.clientMetaItems = [];\n\t\t\tthis._activeSample.clientMetaItems.push(metaData);\n\t\t\tthis.addMetadata(metaData);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.clientMetaItems) this._pendingInjections.clientMetaItems = [];\n\t\tthis._pendingInjections.clientMetaItems.push(metaData);\n\t}\n\n\tpublic injectEvent(event: ClientEvent) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.clientEvents) this._activeSample.clientEvents = [];\n\t\t\tthis._activeSample.clientEvents.push(event);\n\t\t\tthis._processClientEvent(event);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.clientEvents) this._pendingInjections.clientEvents = [];\n\t\tthis._pendingInjections.clientEvents.push(event);\n\t}\n\n\tpublic injectIssue(issue: ClientIssue) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.clientIssues) this._activeSample.clientIssues = [];\n\t\t\tthis._activeSample.clientIssues.push(issue);\n\t\t\tthis.addIssue(issue);\n\t\t\t++this.deltaNumberOfIssues;\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.clientIssues) this._pendingInjections.clientIssues = [];\n\t\tthis._pendingInjections.clientIssues.push(issue);\n\t}\n\n\tpublic injectExtensionStat(stat: ExtensionStat) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.extensionStats) this._activeSample.extensionStats = [];\n\t\t\tthis._activeSample.extensionStats.push(stat);\n\t\t\tthis.addExtensionStats(stat);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.extensionStats) this._pendingInjections.extensionStats = [];\n\t\tthis._pendingInjections.extensionStats.push(stat);\n\t}\n\n\tpublic injectAttachment(attachments: Record<string, unknown>) {\n\t\tif (this.closed) return;\n\n\t\tif (this._activeSample) {\n\t\t\tif (!this._activeSample.attachments) this._activeSample.attachments = {};\n\t\t\tObject.assign(this._activeSample.attachments, attachments);\n\t\t\tthis.attachments = this._activeSample.attachments;\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this._pendingInjections.attachments) this._pendingInjections.attachments = {};\n\t\tObject.assign(this._pendingInjections.attachments, attachments);\n\t}\n\n\tpublic addMetadata(metadata: ClientMetaData) {\n\t\tif (this.closed) return;\n\n\t\tswitch (metadata.type) {\n\t\t\tcase ClientMetaTypes.BROWSER: {\n\t\t\t\tthis.browser = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientMetaTypes.ENGINE: {\n\t\t\t\tthis.engine = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientMetaTypes.PLATFORM: {\n\t\t\t\tthis.platform = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientMetaTypes.OPERATION_SYSTEM: {\n\t\t\t\tthis.operationSystem = parseJsonAs(metadata.payload);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis._notify('client-metadata', { ...this.eventScope, metaData: metadata });\n\t}\n\n\t/**\n\t * Process one `clientIssues[]` entry.\n\t *\n\t * Entries come in two flavours (client-monitor-js >= 4.6.0):\n\t *\n\t * - a **raise** — opens an {@link ActiveClientIssue} under `issue.key` and emits `client-issue`;\n\t * - a **resolution** — `type` ends in `-resolved` and carries the same `key`; it closes the\n\t * matching active issue and emits `client-issue-resolved`.\n\t *\n\t * Keyless entries are one-shot: reported, never tracked. A re-raise of a key already active\n\t * refreshes the payload rather than opening a second interval.\n\t */\n\tpublic addIssue(issue: ClientIssue) {\n\t\tif (this.closed) return;\n\n\t\tif (isResolutionEntry(issue)) return this._resolveIssue(issue);\n\n\t\tconst now = Date.now();\n\n\t\tif (issue.key) {\n\t\t\tconst payload = parseIssuePayload(issue.payload);\n\t\t\tconst existing = this.activeIssues.get(issue.key);\n\n\t\t\tif (existing) {\n\t\t\t\t// A re-raise: same interval, fresher payload. Do not restart `raisedAt`.\n\t\t\t\texisting.payload = payload ?? existing.payload;\n\t\t\t} else {\n\t\t\t\tthis.activeIssues.set(issue.key, {\n\t\t\t\t\tkey: issue.key,\n\t\t\t\t\ttype: baseIssueType(issue.type),\n\t\t\t\t\tclientId: this.clientId,\n\t\t\t\t\traisedAt: issue.timestamp ?? now,\n\t\t\t\t\tobservedAt: now,\n\t\t\t\t\tpayload,\n\t\t\t\t\tpeerConnectionId: typeof payload?.peerConnectionId === 'string' ? payload.peerConnectionId : undefined,\n\t\t\t\t\ttrackId: typeof payload?.trackId === 'string' ? payload.trackId : undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis._notify('client-issue', { ...this.eventScope, issue });\n\t}\n\n\tpublic addExtensionStats(stats: ExtensionStat) {\n\t\tthis._notify('client-extension-stats', { ...this.eventScope, extensionStats: stats });\n\t}\n\n\t/**\n\t * Close every still-open issue, e.g. because the client is going away. Emits\n\t * `client-issue-resolved` for each with the given `resolvedBy`, so correlators relying on the\n\t * active set don't keep a departed client's issues open forever.\n\t */\n\tpublic resolveActiveIssues(resolvedBy: ResolvedClientIssue['resolvedBy'] = 'client-closed') {\n\t\tif (this.activeIssues.size === 0) return;\n\n\t\tconst now = Date.now();\n\n\t\tfor (const active of [ ...this.activeIssues.values() ]) {\n\t\t\tthis.activeIssues.delete(active.key);\n\t\t\tthis._notify('client-issue-resolved', {\n\t\t\t\t...this.eventScope,\n\t\t\t\tresolvedIssue: {\n\t\t\t\t\t...active,\n\t\t\t\t\tresolvedAt: now,\n\t\t\t\t\tobservedResolvedAt: now,\n\t\t\t\t\tdurationInMs: Math.max(0, now - active.observedAt),\n\t\t\t\t\tresolvedBy,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\t/** Close the active issue a `<type>-resolved` entry refers to, and announce the finished interval. */\n\tprivate _resolveIssue(issue: ClientIssue) {\n\t\tconst now = Date.now();\n\t\tconst resolutionPayload = parseIssuePayload(issue.payload);\n\t\tconst type = baseIssueType(issue.type);\n\t\t// The resolution carries `raisedAt` as a secondary join for consumers that don't store keys.\n\t\tconst raisedAt = typeof resolutionPayload?.raisedAt === 'number' ? resolutionPayload.raisedAt : undefined;\n\t\tconst active = issue.key ? this.activeIssues.get(issue.key) : undefined;\n\n\t\tif (active) this.activeIssues.delete(active.key);\n\n\t\tconst resolvedAt = issue.timestamp ?? now;\n\t\tconst durationInMs = typeof resolutionPayload?.durationInMs === 'number'\n\t\t\t? resolutionPayload.durationInMs\n\t\t\t: Math.max(0, resolvedAt - (active?.raisedAt ?? raisedAt ?? resolvedAt));\n\n\t\tthis._notify('client-issue-resolved', {\n\t\t\t...this.eventScope,\n\t\t\tresolvedIssue: {\n\t\t\t\tkey: active?.key ?? issue.key ?? `${this.clientId}:${type}:${raisedAt ?? resolvedAt}`,\n\t\t\t\ttype,\n\t\t\t\tclientId: this.clientId,\n\t\t\t\traisedAt: active?.raisedAt ?? raisedAt ?? resolvedAt,\n\t\t\t\tobservedAt: active?.observedAt ?? now,\n\t\t\t\tpayload: active?.payload,\n\t\t\t\tpeerConnectionId: active?.peerConnectionId,\n\t\t\t\ttrackId: active?.trackId,\n\t\t\t\tresolvedAt,\n\t\t\t\tobservedResolvedAt: now,\n\t\t\t\tdurationInMs,\n\t\t\t\tcomment: typeof resolutionPayload?.comment === 'string' ? resolutionPayload.comment : undefined,\n\t\t\t\tresolutionPayload,\n\t\t\t\tresolvedBy: 'client',\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {\n\t\t// eslint-disable-next-line no-console\n\t\t// console.warn('ClientEvent', event);\n\t\tswitch (event.type) {\n\t\t\tcase ClientEventTypes.CLIENT_JOINED: {\n\t\t\t\tif (event.timestamp) {\n\t\t\t\t\tif (!this.joinedAt) {\n\t\t\t\t\t\tthis.joinedAt = event.timestamp;\n\t\t\t\t\t\tthis.emit('joined');\n\t\t\t\t\t\tthis._notify('client-joined', { ...this.eventScope });\n\t\t\t\t\t} else if (this.joinedAt < event.timestamp) {\n\t\t\t\t\t\tthis._notify('client-rejoined', { ...this.eventScope, timestamp: event.timestamp });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.joinedAt = event.timestamp;\n\t\t\t\t\t\tlogger.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlogger.debug('Client %s joined at %o', this.clientId, event);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.CLIENT_LEFT: {\n\t\t\t\tif (event.timestamp) {\n\t\t\t\t\tif (!this.leftAt) {\n\t\t\t\t\t\tthis.leftAt = event.timestamp;\n\t\t\t\t\t\tthis.emit('left');\n\t\t\t\t\t\tthis._notify('client-left', { ...this.eventScope });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn(`Client ${this.clientId} leftAt timestamp was already set`);\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\tlogger.debug('Client %s left at %o', this.clientId, event);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.PEER_CONNECTION_OPENED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.openedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.PEER_CONNECTION_CLOSED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.closedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_ADDED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedTrack) {\n\t\t\t\t\t\tobservedTrack.addedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_REMOVED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedTrack) {\n\t\t\t\t\t\tobservedTrack.removedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.DATA_CHANNEL_OPEN: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);\n\n\t\t\t\t\tif (observedDataChannel) {\n\t\t\t\t\t\tobservedDataChannel.addedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.DATA_CHANNEL_CLOSED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);\n\n\t\t\t\t\tif (observedDataChannel) {\n\t\t\t\t\t\tobservedDataChannel.removedAt = event.timestamp;\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_MUTED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);\n\t\t\t\t\tconst observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tif (observedInboundTrack) {\n\t\t\t\t\t\t\tobservedInboundTrack.muted = true;\n\t\t\t\t\t\t\tthis._notify('inbound-track-muted', { ...this.eventScope, observedPeerConnection, observedInboundTrack });\n\t\t\t\t\t\t} else if (observedOutboundTrack) {\n\t\t\t\t\t\t\tobservedOutboundTrack.muted = true;\n\t\t\t\t\t\t\tthis._notify('outbound-track-muted', { ...this.eventScope, observedPeerConnection, observedOutboundTrack });\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_MUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.MEDIA_TRACK_UNMUTED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\t\t\t\t\tconst observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);\n\t\t\t\t\tconst observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tif (observedInboundTrack) {\n\t\t\t\t\t\t\tobservedInboundTrack.muted = false;\n\t\t\t\t\t\t\tthis._notify('inbound-track-unmuted', { ...this.eventScope, observedPeerConnection, observedInboundTrack });\n\t\t\t\t\t\t} else if (observedOutboundTrack) {\n\t\t\t\t\t\t\tobservedOutboundTrack.muted = false;\n\t\t\t\t\t\t\tthis._notify('outbound-track-unmuted', { ...this.eventScope, observedPeerConnection, observedOutboundTrack });\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received MEDIA_TRACK_UNMUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.ICE_CONNECTION_STATE_CHANGED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceConnectionState && typeof payload.iceConnectionState === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.iceConnectionState = payload.iceConnectionState as 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';\n\t\t\t\t\t\tthis._notify('ice-connection-state-changed', { ...this.eventScope, observedPeerConnection, state: payload.iceConnectionState });\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received ICE_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.ICE_GATHERING_STATE_CHANGED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceGatheringState && typeof payload.iceGatheringState === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.iceGatheringState = payload.iceGatheringState as 'new' | 'gathering' | 'complete';\n\t\t\t\t\t\tthis._notify('ice-gathering-state-changed', { ...this.eventScope, observedPeerConnection, state: payload.iceGatheringState });\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received ICE_GATHERING_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ClientEventTypes.PEER_CONNECTION_STATE_CHANGED: {\n\t\t\t\tconst payload = parseJsonAs<Record<string, unknown>>(event.payload);\n\n\t\t\t\tif (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.peerConnectionState && typeof payload.peerConnectionState === 'string') {\n\t\t\t\t\tconst observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);\n\n\t\t\t\t\tif (observedPeerConnection) {\n\t\t\t\t\t\tobservedPeerConnection.connectionState = payload.peerConnectionState as 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';\n\t\t\t\t\t\tthis._notify('connection-state-changed', { ...this.eventScope, observedPeerConnection, state: payload.peerConnectionState });\n\t\t\t\t\t} else if (postBuffer) {\n\t\t\t\t\t\tpostBuffer.push(event);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn('Received PEER_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis._notify('client-event', { ...this.eventScope, event });\n\t}\n\n\tprivate _updatePeerConnection(sample: PeerConnectionSample, context?: AcceptContext): ObservedPeerConnection | undefined {\n\t\tlet observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);\n\n\t\tif (!observedPeerConnection) {\n\t\t\tif (!sample.peerConnectionId) {\n\t\t\t\treturn (logger.warn(\n\t\t\t\t\t`ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,\n\t\t\t\t\tsample\n\t\t\t\t), void 0);\n\t\t\t}\n\n\t\t\tconst newObservedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);\n\n\t\t\tnewObservedPeerConnection.once('close', () => {\n\t\t\t\tthis.observedPeerConnections.delete(sample.peerConnectionId);\n\t\t\t});\n\t\t\tthis.observedPeerConnections.set(sample.peerConnectionId, newObservedPeerConnection);\n\n\t\t\tthis._notify('peer-connection-added', { ...this.eventScope, observedPeerConnection: newObservedPeerConnection });\n\n\t\t\tobservedPeerConnection = newObservedPeerConnection;\n\t\t}\n\n\t\tobservedPeerConnection.accept(sample, context);\n\n\t\treturn observedPeerConnection;\n\t}\n\n\tprivate _mergePendingInjections(sample: ClientSample): ClientSample {\n\t\tif (this.closed) return sample;\n\n\t\tif (this._pendingInjections.clientEvents) {\n\t\t\tif (!sample.clientEvents) sample.clientEvents = [];\n\t\t\tsample.clientEvents.push(...this._pendingInjections.clientEvents);\n\n\t\t\tthis._pendingInjections.clientEvents = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.clientIssues) {\n\t\t\tif (!sample.clientIssues) sample.clientIssues = [];\n\t\t\tsample.clientIssues.push(...this._pendingInjections.clientIssues);\n\n\t\t\tthis._pendingInjections.clientIssues = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.extensionStats) {\n\t\t\tif (!sample.extensionStats) sample.extensionStats = [];\n\t\t\tsample.extensionStats.push(...this._pendingInjections.extensionStats);\n\n\t\t\tthis._pendingInjections.extensionStats = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.attachments) {\n\t\t\tif (!sample.attachments) sample.attachments = {};\n\t\t\tObject.assign(sample.attachments, this._pendingInjections.attachments);\n\n\t\t\tthis._pendingInjections.attachments = undefined;\n\t\t}\n\n\t\tif (this._pendingInjections.clientMetaItems) {\n\t\t\tif (!sample.clientMetaItems) sample.clientMetaItems = [];\n\t\t\tsample.clientMetaItems.push(...this._pendingInjections.clientMetaItems);\n\n\t\t\tthis._pendingInjections.clientMetaItems = undefined;\n\t\t}\n\n\t\treturn sample;\n\t}\n\n\tprivate _flushPendingInjections() {\n\t\tconst hasPending = Boolean(\n\t\t\tthis._pendingInjections.clientEvents ||\n\t\t\tthis._pendingInjections.clientIssues ||\n\t\t\tthis._pendingInjections.extensionStats ||\n\t\t\tthis._pendingInjections.clientMetaItems ||\n\t\t\tthis._pendingInjections.attachments,\n\t\t);\n\n\t\tif (!hasPending) return;\n\n\t\tconst finalSample: ClientSample = { timestamp: Date.now() };\n\n\t\tthis._mergePendingInjections(finalSample);\n\n\t\tfor (const clientEvent of finalSample.clientEvents ?? []) this._processClientEvent(clientEvent);\n\t\tfor (const metaData of finalSample.clientMetaItems ?? []) this.addMetadata(metaData);\n\t\tfor (const issue of finalSample.clientIssues ?? []) this.addIssue(issue);\n\t\tfor (const extensionStat of finalSample.extensionStats ?? []) this.addExtensionStats(extensionStat);\n\t\tif (finalSample.attachments) this.attachments = { ...this.attachments, ...finalSample.attachments };\n\n\t\ttry {\n\t\t\tthis.sink?.write(finalSample);\n\t\t} catch (err) {\n\t\t\tlogger.warn('ClientSampleSink.write failed during injection flush for client %s: %o', this.clientId, err);\n\t\t}\n\t}\n\n\t/** Emit an Observer-bus event scoped to this client (or a peer connection under it). */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.call.observer.emit(type, ...args);\n\t}\n}\n","import { EventEmitter } from 'events';\nimport { ObservedClient } from './ObservedClient';\nimport { CertificateStats, CodecStats, DataChannelStats, IceCandidateStats, InboundRtpStats, InboundTrackSample, MediaPlayoutStats, MediaSourceStats, OutboundRtpStats, OutboundTrackSample, PeerConnectionSample, PeerConnectionTransportStats, RemoteInboundRtpStats, RemoteOutboundRtpStats } from './schema/ClientSample';\nimport { ObservedInboundRtp } from './ObservedInboundRtp';\nimport { createLogger } from './common/logger';\nimport { MediaKind } from './common/types';\nimport { ObservedOutboundRtp } from './ObservedOutboundRtp';\nimport { ObservedCertificate } from './ObservedCertificate';\nimport { ObservedCodec } from './ObservedCodec';\nimport { ObservedDataChannel } from './ObservedDataChannel';\nimport { ObservedIceCandidate } from './ObservedIceCandidate';\nimport { ObservedIceCandidatePair } from './ObservedIceCandidatePair';\nimport { ObservedIceTransport } from './ObservedIceTransport';\nimport { ObservedMediaSource } from './ObservedMediaSource';\nimport { ObservedPeerConnectionTransport } from './ObservedPeerConnectionTransport';\nimport { ObservedMediaPlayout } from './ObservedMediaPlayout';\nimport { ObservedRemoteInboundRtp } from './ObservedRemoteInboundRtp';\nimport { ObservedRemoteOutboundRtp } from './ObservedRemoteOutboundRtp';\nimport { ObservedInboundTrack } from './ObservedInboundTrack';\nimport { ObservedOutboundTrack } from './ObservedOutboundTrack';\nimport { CalculatedScore } from './scores/CalculatedScore';\nimport { ObservedTurnServer } from './ObservedTurnServer';\nimport { getMedian } from './common/utils';\nimport type { AcceptContext } from './Observer';\nimport type { ObserverEvents, ObservedPeerConnectionScope } from './ObserverEvents';\n\nconst logger = createLogger('ObservedPeerConnection');\n\n// Local lifecycle/coordination events only. All consumer-facing events are\n// emitted on the Observer bus (see ObserverEvents). `close` and the two track\n// `removed-*` events stay local because the parent ObservedClient wires to them\n// for teardown and track-report emission.\nexport type ObservedPeerConnectionEvents = {\n\t'removed-inbound-track': [ObservedInboundTrack];\n\t'removed-outbound-track': [ObservedOutboundTrack];\n\tclose: [];\n};\n\nexport declare interface ObservedPeerConnection {\n\ton<U extends keyof ObservedPeerConnectionEvents>(\n\t\tevent: U,\n\t\tlistener: (...args: ObservedPeerConnectionEvents[U]) => void\n\t): this;\n\toff<U extends keyof ObservedPeerConnectionEvents>(\n\t\tevent: U,\n\t\tlistener: (...args: ObservedPeerConnectionEvents[U]) => void\n\t): this;\n\tonce<U extends keyof ObservedPeerConnectionEvents>(\n\t\tevent: U,\n\t\tlistener: (...args: ObservedPeerConnectionEvents[U]) => void\n\t): this;\n\temit<U extends keyof ObservedPeerConnectionEvents>(event: U, ...args: ObservedPeerConnectionEvents[U]): boolean;\n}\n\nexport class ObservedPeerConnection extends EventEmitter {\n\tprivate _visited = true;\n\n\tpublic appData?: Record<string, unknown>;\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\n\tpublic closed = false;\n\t// timestamp of the PEER_CONNECTION_OPENED event\n\tpublic openedAt?: number;\n\t// timestamp of the PEER_CONNECTION_CLOSED event\n\tpublic closedAt?: number;\n\tpublic updated = Date.now();\n\n\tpublic connectionState?: 'new' | 'connecting' | 'connected' | 'disconnected' | 'failed' | 'closed';\n\tpublic iceConnectionState?: 'new' | 'checking' | 'connected' | 'completed' | 'failed' | 'disconnected' | 'closed';\n\tpublic iceGatheringState?: 'new' | 'gathering' | 'complete';\n\n\tpublic availableIncomingBitrate = 0;\n\tpublic availableOutgoingBitrate = 0;\n\tpublic totalInboundPacketsLost = 0;\n\tpublic totalInboundPacketsReceived = 0;\n\tpublic totalOutboundPacketsSent = 0;\n\tpublic totalDataChannelBytesSent = 0;\n\tpublic totalDataChannelBytesReceived = 0;\n\tpublic totalDataChannelMessagesSent = 0;\n\tpublic totalDataChannelMessagesReceived = 0;\n\n\tpublic totalSentAudioBytes = 0;\n\tpublic totalSentVideoBytes = 0;\n\tpublic totalSentAudioPackets = 0;\n\tpublic totalSentVideoPackets = 0;\n\tpublic totalReceivedAudioPacktes = 0;\n\tpublic totalReceivedVideoPackets = 0;\n\tpublic totalReceivedAudioBytes = 0;\n\tpublic totalReceivedVideoBytes = 0;\n\n\tpublic deltaInboundPacketsLost = 0;\n\tpublic deltaInboundPacketsReceived = 0;\n\tpublic deltaOutboundPacketsSent = 0;\n\tpublic deltaDataChannelBytesSent = 0;\n\tpublic deltaDataChannelBytesReceived = 0;\n\tpublic deltaDataChannelMessagesSent = 0;\n\tpublic deltaDataChannelMessagesReceived = 0;\n\tpublic deltaInboundReceivedBytes = 0;\n\tpublic deltaOutboundSentBytes = 0;\n\n\tpublic deltaReceivedAudioBytes = 0;\n\tpublic deltaReceivedVideoBytes = 0;\n\tpublic deltaReceivedAudioPackets = 0;\n\tpublic deltaReceivedVideoPackets = 0;\n\tpublic deltaSentAudioBytes = 0;\n\tpublic deltaSentVideoBytes = 0;\n\tpublic deltaSentAudioPackets = 0;\n\tpublic deltaSentVideoPackets = 0;\n\tpublic deltaTransportSentBytes = 0;\n\tpublic deltaTransportReceivedBytes = 0;\n\n\tpublic receivingPacketsPerSecond = 0;\n\tpublic sendingPacketsPerSecond = 0;\n\tpublic sendingAudioBitrate = 0;\n\tpublic sendingVideoBitrate = 0;\n\tpublic receivingAudioBitrate = 0;\n\tpublic receivingVideoBitrate = 0;\n\n\t/**\n\t * Median round-trip time of the tick, in ms.\n\t *\n\t * Prefers {@link rtcpRttInMs} and falls back to {@link iceRttInMs}, so within one tick it always\n\t * reports **one** kind of round trip. It used to be the median of both mixed together, which was\n\t * a bug: the mixing ratio changed as streams came and went, so the value moved for reasons that\n\t * had nothing to do with the network.\n\t */\n\tpublic currentRttInMs?: number;\n\n\t/**\n\t * RTT measured by ICE/STUN consent checks, in ms — the trip to **whatever terminates ICE**. In an\n\t * SFU topology that is the SFU, so this is the client↔SFU leg, not client↔client.\n\t */\n\tpublic iceRttInMs?: number;\n\n\t/**\n\t * RTT reported by RTCP receiver reports, in ms — an **end-to-end** media-path round trip.\n\t *\n\t * Not the same trip as {@link iceRttInMs}; the difference between the two is roughly the far side\n\t * of the SFU (see {@link sfuHopRttInMs}).\n\t */\n\tpublic rtcpRttInMs?: number;\n\n\t/**\n\t * `rtcpRttInMs - iceRttInMs`, when both are known — an estimate of everything *past* the SFU.\n\t *\n\t * Useful for splitting \"this client's own last mile is slow\" (high `iceRttInMs`) from \"the path\n\t * beyond the SFU is slow\" (low ICE, high hop).\n\t */\n\tpublic sfuHopRttInMs?: number;\n\tpublic currentJitter?: number;\n\n\tpublic usingTCP = false;\n\tpublic usingTURN = false;\n\n\tpublic observedTurnServer?: ObservedTurnServer;\n\tpublic readonly observedCertificates = new Map<string, ObservedCertificate>();\n\tpublic readonly observedCodecs = new Map<string, ObservedCodec>();\n\tpublic readonly observedDataChannels = new Map<string, ObservedDataChannel>();\n\tpublic readonly observedIceCandidates = new Map<string, ObservedIceCandidate>();\n\tpublic readonly observedIceCandidatesPair = new Map<string, ObservedIceCandidatePair>();\n\tpublic readonly observedIceTransports = new Map<string, ObservedIceTransport>();\n\tpublic readonly observedInboundRtps = new Map<number, ObservedInboundRtp>();\n\tpublic readonly observedInboundTracks = new Map<string, ObservedInboundTrack>();\n\tpublic readonly observedMediaPlayouts = new Map<string, ObservedMediaPlayout>();\n\tpublic readonly observedMediaSources = new Map<string, ObservedMediaSource>();\n\tpublic readonly observedOutboundRtps = new Map<number, ObservedOutboundRtp>();\n\tpublic readonly observedOutboundTracks = new Map<string, ObservedOutboundTrack>();\n\tpublic readonly observedPeerConnectionTransports = new Map<string, ObservedPeerConnectionTransport>();\n\tpublic readonly observedRemoteInboundRtps = new Map<number, ObservedRemoteInboundRtp>();\n\tpublic readonly observedRemoteOutboundRtps = new Map<number, ObservedRemoteOutboundRtp>();\n\n\tprivate readonly eventScope: ObservedPeerConnectionScope;\n\n\tpublic constructor(public readonly peerConnectionId: string, public readonly client: ObservedClient) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\t\tthis.eventScope = {\n\t\t\tobserver: client.call.observer,\n\t\t\tobservedCall: client.call,\n\t\t\tobservedClient: client,\n\t\t\tobservedPeerConnection: this,\n\t\t};\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic get codecs() {\n\t\treturn [ ...this.observedCodecs.values() ];\n\t}\n\n\tpublic get inboundRtps() {\n\t\treturn [ ...this.observedInboundRtps.values() ];\n\t}\n\n\tpublic get remoteOutboundRtps() {\n\t\treturn [ ...this.observedRemoteOutboundRtps.values() ];\n\t}\n\n\tpublic get outboundRtps() {\n\t\treturn [ ...this.observedOutboundRtps.values() ];\n\t}\n\n\tpublic get remoteInboundRtps() {\n\t\treturn [ ...this.observedRemoteInboundRtps.values() ];\n\t}\n\n\tpublic get mediaSources() {\n\t\treturn [ ...this.observedMediaSources.values() ];\n\t}\n\n\tpublic get mediaPlayouts() {\n\t\treturn [ ...this.observedMediaPlayouts.values() ];\n\t}\n\n\tpublic get dataChannels() {\n\t\treturn [ ...this.observedDataChannels.values() ];\n\t}\n\n\tpublic get peerConnectionTransports() {\n\t\treturn [ ...this.observedPeerConnectionTransports.values() ];\n\t}\n\n\tpublic get iceTransports() {\n\t\treturn [ ...this.observedIceTransports.values() ];\n\t}\n\n\tpublic get iceCandidates() {\n\t\treturn [ ...this.observedIceCandidates.values() ];\n\t}\n\n\tpublic get iceCandidatePairs() {\n\t\treturn [ ...this.observedIceCandidatesPair.values() ];\n\t}\n\n\tpublic get certificates() {\n\t\treturn [ ...this.observedCertificates.values() ];\n\t}\n\n\tpublic get selectedIceCandidatePairs() {\n\t\treturn this.iceTransports.map((iceTransport) => iceTransport.getSelectedCandidatePair())\n\t\t\t.filter((pair) => pair !== undefined) as ObservedIceCandidatePair[];\n\t}\n\n\tpublic get selectedIceCandiadtePairForTurn() {\n\t\t// The ICE server `url` is only exposed on *local* candidates (it identifies the server\n\t\t// the candidate was obtained from); remote candidates never carry it. `turn` also\n\t\t// matches `turns:` (TURN over TLS).\n\t\treturn this.selectedIceCandidatePairs\n\t\t\t.filter((pair) => {\n\t\t\t\tconst localCandidate = pair.getLocalCandidate();\n\n\t\t\t\treturn localCandidate?.candidateType === 'relay' && localCandidate?.url?.startsWith('turn') === true;\n\t\t\t});\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\n\t\tthis.observedCertificates.forEach((observedCertificate) => this._notify('certificate-removed', { ...this.eventScope, observedCertificate }));\n\t\tthis.observedCodecs.forEach((observedCodec) => this._notify('codec-removed', { ...this.eventScope, observedCodec }));\n\t\tthis.observedDataChannels.forEach((observedDataChannel) => this._notify('data-channel-removed', { ...this.eventScope, observedDataChannel }));\n\t\tthis.observedIceCandidates.forEach((observedIceCandidate) => this._notify('ice-candidate-removed', { ...this.eventScope, observedIceCandidate }));\n\t\tthis.observedIceCandidatesPair.forEach((pair) => this._notify('ice-candidate-pair-removed', { ...this.eventScope, observedIceCandidatePair: pair }));\n\t\tthis.observedIceTransports.forEach((transport) => this._notify('ice-transport-removed', { ...this.eventScope, observedIceTransport: transport }));\n\t\tthis.observedInboundRtps.forEach((rtp) => this._notify('inbound-rtp-removed', { ...this.eventScope, observedInboundRtp: rtp }));\n\t\tthis.observedInboundTracks.forEach((track) => { this.emit('removed-inbound-track', track); this._notify('inbound-track-removed', { ...this.eventScope, observedInboundTrack: track }); });\n\t\tthis.observedMediaPlayouts.forEach((playout) => this._notify('media-playout-removed', { ...this.eventScope, observedMediaPlayout: playout }));\n\t\tthis.observedMediaSources.forEach((source) => this._notify('media-source-removed', { ...this.eventScope, observedMediaSource: source }));\n\t\tthis.observedOutboundRtps.forEach((rtp) => this._notify('outbound-rtp-removed', { ...this.eventScope, observedOutboundRtp: rtp }));\n\t\tthis.observedOutboundTracks.forEach((track) => { this.emit('removed-outbound-track', track); this._notify('outbound-track-removed', { ...this.eventScope, observedOutboundTrack: track }); });\n\t\tthis.observedPeerConnectionTransports.forEach((transport) => this._notify('peer-connection-transport-removed', { ...this.eventScope, observedPeerConnectionTransport: transport }));\n\t\tthis.observedRemoteInboundRtps.forEach((rtp) => this._notify('remote-inbound-rtp-removed', { ...this.eventScope, observedRemoteInboundRtp: rtp }));\n\t\tthis.observedRemoteOutboundRtps.forEach((rtp) => this._notify('remote-outbound-rtp-removed', { ...this.eventScope, observedRemoteOutboundRtp: rtp }));\n\n\t\tthis.observedCertificates.clear();\n\t\tthis.observedCodecs.clear();\n\t\tthis.observedDataChannels.clear();\n\t\tthis.observedIceCandidates.clear();\n\t\tthis.observedIceCandidatesPair.clear();\n\t\tthis.observedIceTransports.clear();\n\t\tthis.observedInboundRtps.clear();\n\t\tthis.observedInboundTracks.clear();\n\t\tthis.observedMediaPlayouts.clear();\n\t\tthis.observedMediaSources.clear();\n\t\tthis.observedOutboundRtps.clear();\n\t\tthis.observedOutboundTracks.clear();\n\t\tthis.observedPeerConnectionTransports.clear();\n\t\tthis.observedRemoteInboundRtps.clear();\n\t\tthis.observedRemoteOutboundRtps.clear();\n\n\t\tthis.client.call.observer.observedTURN.removePeerConnection(this);\n\n\t\tif (!this.closedAt) this.closedAt = Date.now();\n\n\t\tthis.emit('close');\n\t\tthis._notify('peer-connection-closed', { ...this.eventScope });\n\t}\n\n\tpublic accept(sample: PeerConnectionSample, context?: AcceptContext) {\n\t\tif (this.closed) return;\n\t\tthis._visited = true;\n\n\t\tif (context) this.appData = { ...this.appData, ...context };\n\n\t\tthis.availableIncomingBitrate = 0;\n\t\tthis.availableOutgoingBitrate = 0;\n\t\tthis.deltaInboundPacketsLost = 0;\n\t\tthis.deltaInboundPacketsReceived = 0;\n\t\tthis.deltaOutboundPacketsSent = 0;\n\t\tthis.deltaDataChannelBytesSent = 0;\n\t\tthis.deltaDataChannelBytesReceived = 0;\n\t\tthis.deltaInboundReceivedBytes = 0;\n\t\tthis.deltaOutboundSentBytes = 0;\n\t\tthis.deltaReceivedAudioBytes = 0;\n\t\tthis.deltaReceivedVideoBytes = 0;\n\t\tthis.deltaReceivedAudioPackets = 0;\n\t\tthis.deltaReceivedVideoPackets = 0;\n\t\tthis.deltaSentAudioBytes = 0;\n\t\tthis.deltaSentVideoBytes = 0;\n\t\tthis.deltaSentAudioPackets = 0;\n\t\tthis.deltaSentVideoPackets = 0;\n\t\tthis.deltaTransportReceivedBytes = 0;\n\t\tthis.deltaTransportSentBytes = 0;\n\n\t\tthis.sendingAudioBitrate = 0;\n\t\tthis.sendingVideoBitrate = 0;\n\t\tthis.receivingAudioBitrate = 0;\n\t\tthis.receivingVideoBitrate = 0;\n\n\t\tconst now = Date.now();\n\t\tconst elapsedTimeInMs = now - this.updated;\n\t\tconst elapsedTimeInSec = elapsedTimeInMs / 1000;\n\t\t// Kept in two buckets: ICE/STUN and RTCP measure different round trips and must not be blended.\n\t\tconst iceRttMeasurementsInSec: number[] = [];\n\t\tconst rtcpRttMeasurementsInSec: number[] = [];\n\t\tconst jitterMeasurements: number[] = [];\n\n\t\tif (sample.certificates) {\n\t\t\tfor (const certificate of sample.certificates) {\n\t\t\t\tthis._updateCertificateStats(certificate);\n\t\t\t}\n\t\t}\n\t\tif (sample.codecs) {\n\t\t\tfor (const codec of sample.codecs) {\n\t\t\t\tthis._updateCodecStats(codec);\n\t\t\t}\n\t\t}\n\t\tif (sample.dataChannels) {\n\t\t\tfor (const dataChannel of sample.dataChannels) {\n\t\t\t\tconst observedDataChannel = this._updateDataChannelStats(dataChannel);\n\n\t\t\t\tif (!observedDataChannel) continue;\n\n\t\t\t\tthis.deltaDataChannelBytesSent += observedDataChannel.deltaBytesSent;\n\t\t\t\tthis.deltaDataChannelBytesReceived += observedDataChannel.deltaBytesReceived;\n\t\t\t\tthis.deltaDataChannelMessagesSent += observedDataChannel.deltaMessagesSent;\n\t\t\t\tthis.deltaDataChannelMessagesReceived += observedDataChannel.deltaMessagesReceived;\n\t\t\t}\n\t\t}\n\t\tif (sample.iceCandidates) {\n\t\t\tfor (const iceCandidate of sample.iceCandidates) {\n\t\t\t\tthis._updateIceCandidateStats(iceCandidate);\n\t\t\t}\n\t\t}\n\t\tif (sample.iceCandidatePairs) {\n\t\t\tfor (const iceCandidatePair of sample.iceCandidatePairs) {\n\t\t\t\tconst observedCandidatePair = this._updateIceCandidatePairStats(iceCandidatePair);\n\n\t\t\t\tif (!observedCandidatePair) continue;\n\n\t\t\t\tif (observedCandidatePair.currentRoundTripTime) {\n\t\t\t\t\t// ICE/STUN round trip — terminates at the SFU, kept apart from the RTCP one.\n\t\t\t\t\ticeRttMeasurementsInSec.push(observedCandidatePair.currentRoundTripTime);\n\t\t\t\t}\n\t\t\t\tif (observedCandidatePair.availableIncomingBitrate) {\n\t\t\t\t\tthis.availableIncomingBitrate += observedCandidatePair.availableIncomingBitrate;\n\t\t\t\t}\n\t\t\t\tif (observedCandidatePair.availableOutgoingBitrate) {\n\t\t\t\t\tthis.availableOutgoingBitrate += observedCandidatePair.availableOutgoingBitrate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (sample.iceTransports) {\n\t\t\tfor (const iceTransport of sample.iceTransports) {\n\t\t\t\tconst observedIceTransport = this._updateIceTransportStats(iceTransport);\n\n\t\t\t\tif (!observedIceTransport) continue;\n\t\t\t}\n\t\t}\n\t\tif (sample.inboundRtps) {\n\t\t\tfor (const inboundRtp of sample.inboundRtps) {\n\t\t\t\tconst observedInboundRtp = this._updateInboundRtpStats(inboundRtp);\n\n\t\t\t\tif (!observedInboundRtp) continue;\n\n\t\t\t\tthis.deltaInboundPacketsLost += observedInboundRtp.deltaLostPackets;\n\t\t\t\tthis.deltaInboundPacketsReceived += observedInboundRtp.deltaReceivedPackets;\n\t\t\t\tthis.deltaInboundReceivedBytes += observedInboundRtp.deltaBytesReceived;\n\n\t\t\t\tswitch (inboundRtp.kind) {\n\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tthis.deltaReceivedAudioBytes += observedInboundRtp.deltaBytesReceived;\n\t\t\t\t\t\tthis.deltaReceivedAudioPackets += observedInboundRtp.deltaReceivedPackets;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'video':\n\t\t\t\t\t\tthis.deltaReceivedVideoBytes += observedInboundRtp.deltaBytesReceived;\n\t\t\t\t\t\tthis.deltaReceivedVideoPackets += observedInboundRtp.deltaReceivedPackets;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (observedInboundRtp.jitter) {\n\t\t\t\t\tjitterMeasurements.push(observedInboundRtp.jitter);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (sample.mediaPlayouts) {\n\t\t\tfor (const mediaPlayout of sample.mediaPlayouts) {\n\t\t\t\tthis._updateMediaPlayoutStats(mediaPlayout);\n\t\t\t}\n\t\t}\n\t\tif (sample.mediaSources) {\n\t\t\tfor (const mediaSource of sample.mediaSources) {\n\t\t\t\tthis._updateMediaSourceStats(mediaSource);\n\t\t\t}\n\t\t}\n\t\tif (sample.outboundRtps) {\n\t\t\tfor (const outboundRtp of sample.outboundRtps) {\n\t\t\t\tconst observedOutboundRtp = this._updateOutboundRtpStats(outboundRtp);\n\n\t\t\t\tif (!observedOutboundRtp) continue;\n\n\t\t\t\tthis.deltaOutboundPacketsSent += observedOutboundRtp.deltaPacketsSent ?? 0;\n\t\t\t\tthis.deltaOutboundSentBytes += observedOutboundRtp.deltaBytesSent ?? 0;\n\n\t\t\t\tswitch (outboundRtp.kind) {\n\t\t\t\t\tcase 'audio':\n\t\t\t\t\t\tthis.deltaSentAudioBytes += observedOutboundRtp.deltaBytesSent;\n\t\t\t\t\t\tthis.deltaSentAudioPackets += observedOutboundRtp.deltaPacketsSent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'video':\n\t\t\t\t\t\tthis.deltaSentVideoBytes += observedOutboundRtp.deltaBytesSent;\n\t\t\t\t\t\tthis.deltaSentVideoPackets += observedOutboundRtp.deltaPacketsSent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\tif (sample.peerConnectionTransports) {\n\t\t\tfor (const peerConnectionTransport of sample.peerConnectionTransports) {\n\t\t\t\tconst observedTransport = this._updatePeerConnectionTransportStats(peerConnectionTransport);\n\n\t\t\t\tif (!observedTransport) continue;\n\n\t\t\t}\n\t\t}\n\t\tif (sample.remoteInboundRtps) {\n\t\t\tfor (const remoteInboundRtp of sample.remoteInboundRtps) {\n\t\t\t\tconst observedRemoteInboundRtp = this._updateRemoteInboundRtpStats(remoteInboundRtp);\n\n\t\t\t\tif (!observedRemoteInboundRtp) continue;\n\n\t\t\t\tif (observedRemoteInboundRtp.roundTripTime) {\n\t\t\t\t\t// RTCP round trip — end to end over the media path.\n\t\t\t\t\trtcpRttMeasurementsInSec.push(observedRemoteInboundRtp.roundTripTime);\n\t\t\t\t}\n\n\t\t\t\t// Surface receiver-report-derived metrics on the corresponding local outbound-rtp.\n\t\t\t\tconst observedOutboundRtp = observedRemoteInboundRtp.getOutboundRtp();\n\n\t\t\t\tif (observedOutboundRtp) {\n\t\t\t\t\tif (observedRemoteInboundRtp.roundTripTime !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remoteRttInMs = observedRemoteInboundRtp.roundTripTime * 1000;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteInboundRtp.fractionLost !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remoteFractionLost = observedRemoteInboundRtp.fractionLost;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteInboundRtp.jitter !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remoteJitter = observedRemoteInboundRtp.jitter;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteInboundRtp.packetsLost !== undefined) {\n\t\t\t\t\t\tobservedOutboundRtp.remotePacketsLost = observedRemoteInboundRtp.packetsLost;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (sample.remoteOutboundRtps) {\n\t\t\tfor (const remoteOutboundRtp of sample.remoteOutboundRtps) {\n\t\t\t\tconst observedRemoteOutboundRtp = this._updateRemoteOutboundRtpStats(remoteOutboundRtp);\n\n\t\t\t\tif (!observedRemoteOutboundRtp) continue;\n\n\t\t\t\t// Surface sender-report-derived metrics on the corresponding local inbound-rtp.\n\t\t\t\tconst observedInboundRtp = observedRemoteOutboundRtp.getInboundRtp();\n\n\t\t\t\tif (observedInboundRtp) {\n\t\t\t\t\tif (observedRemoteOutboundRtp.roundTripTime !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remoteRttInMs = observedRemoteOutboundRtp.roundTripTime * 1000;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteOutboundRtp.bytesSent !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remoteBytesSent = observedRemoteOutboundRtp.bytesSent;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteOutboundRtp.packetsSent !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remotePacketsSent = observedRemoteOutboundRtp.packetsSent;\n\t\t\t\t\t}\n\t\t\t\t\tif (observedRemoteOutboundRtp.remoteTimestamp !== undefined) {\n\t\t\t\t\t\tobservedInboundRtp.remoteTimestamp = observedRemoteOutboundRtp.remoteTimestamp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// tracks should be updated last as they are derived stats\n\t\t// and depends on base stats but they all received in the sample sample\n\t\tif (sample.inboundTracks) {\n\t\t\tfor (const inboundTrack of sample.inboundTracks) {\n\t\t\t\tthis._updateInboundTrackSample(inboundTrack);\n\t\t\t}\n\t\t}\n\t\tif (sample.outboundTracks) {\n\t\t\tfor (const outboundTrack of sample.outboundTracks) {\n\t\t\t\tthis._updateOutboundTrackSample(outboundTrack);\n\t\t\t}\n\t\t}\n\n\t\tthis.totalInboundPacketsLost += this.deltaInboundPacketsLost;\n\t\tthis.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;\n\t\tthis.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;\n\t\tthis.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;\n\t\tthis.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;\n\t\tthis.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;\n\t\tthis.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;\n\t\tthis.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;\n\t\tthis.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;\n\t\tthis.totalSentAudioBytes += this.deltaSentAudioBytes;\n\t\tthis.totalSentVideoBytes += this.deltaSentVideoBytes;\n\t\tthis.totalReceivedAudioPacktes += this.deltaReceivedAudioPackets;\n\t\tthis.totalReceivedVideoPackets += this.deltaReceivedVideoPackets;\n\t\tthis.totalSentAudioPackets += this.deltaSentAudioPackets;\n\t\tthis.totalSentVideoPackets += this.deltaSentVideoPackets;\n\n\t\tthis.receivingPacketsPerSecond = this.deltaInboundPacketsReceived / elapsedTimeInSec;\n\t\tthis.sendingPacketsPerSecond = this.deltaOutboundPacketsSent / elapsedTimeInSec;\n\t\tthis.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / elapsedTimeInSec;\n\t\tthis.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / elapsedTimeInSec;\n\t\tthis.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / elapsedTimeInSec;\n\t\tthis.receivingVideoBitrate = (this.deltaReceivedVideoBytes * 8) / elapsedTimeInSec;\n\n\t\tthis.iceRttInMs = 0 < iceRttMeasurementsInSec.length\n\t\t\t? getMedian(iceRttMeasurementsInSec, false) * 1000\n\t\t\t: undefined;\n\t\tthis.rtcpRttInMs = 0 < rtcpRttMeasurementsInSec.length\n\t\t\t? getMedian(rtcpRttMeasurementsInSec, false) * 1000\n\t\t\t: undefined;\n\n\t\t// Prefer the end-to-end (RTCP) trip, fall back to ICE — never a blend of the two.\n\t\tthis.currentRttInMs = this.rtcpRttInMs ?? this.iceRttInMs;\n\t\tthis.sfuHopRttInMs = this.rtcpRttInMs !== undefined && this.iceRttInMs !== undefined\n\t\t\t? Math.max(0, this.rtcpRttInMs - this.iceRttInMs)\n\t\t\t: undefined;\n\t\tif (jitterMeasurements.length > 0) {\n\t\t\tthis.currentJitter = getMedian(jitterMeasurements, false);\n\t\t} else {\n\t\t\tthis.currentJitter = undefined;\n\t\t}\n\t\tconst wasUsingTURN = this.usingTURN;\n\t\tconst selectedIceCandidatePairs = this.selectedIceCandidatePairs;\n\t\tconst selectedCandidatePairForTurn: ObservedIceCandidatePair[] = [];\n\n\t\tthis.usingTCP = false;\n\t\tthis.usingTURN = false;\n\n\t\tfor (const selectedCandidatePair of selectedIceCandidatePairs) {\n\t\t\tconst localCandidate = selectedCandidatePair.getLocalCandidate();\n\n\t\t\tif (localCandidate?.protocol === 'tcp') {\n\t\t\t\tthis.usingTCP = true;\n\t\t\t}\n\t\t\t// relay candidates are only obtained from TURN servers, so the local candidate's\n\t\t\t// type alone establishes TURN usage. The server `url` is only exposed on *local*\n\t\t\t// candidates (and not by every browser) — it is required only to attribute the\n\t\t\t// traffic to a concrete TURN server.\n\t\t\tif (localCandidate?.candidateType === 'relay') {\n\t\t\t\tthis.usingTURN = true;\n\t\t\t\tif (localCandidate.url?.startsWith('turn')) {\n\t\t\t\t\tselectedCandidatePairForTurn.push(selectedCandidatePair);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.deltaTransportReceivedBytes += selectedCandidatePair.deltaBytesReceived;\n\t\t\tthis.deltaTransportSentBytes += selectedCandidatePair.deltaBytesSent;\n\t\t}\n\n\t\tif (this.usingTURN) {\n\t\t\tif (!this.observedTurnServer) {\n\t\t\t\tthis.observedTurnServer = this.client.call.observer.observedTURN.addPeerConnection(this);\n\t\t\t}\n\t\t\tthis.observedTurnServer?.updateTurnUsage(...selectedCandidatePairForTurn);\n\t\t} else if (wasUsingTURN) {\n\t\t\tif (!this.usingTURN) {\n\t\t\t\tthis.client.call.observer.observedTURN.removePeerConnection(this);\n\t\t\t}\n\t\t}\n\t\tthis.calculatedScore.value = sample.score;\n\t\tthis.updated = now;\n\t\tthis._checkVisited();\n\n\t\tthis._notify('peer-connection-updated', { ...this.eventScope, context });\n\t}\n\n\tprivate _checkVisited() {\n\t\tfor (const certificate of [ ...this.observedCertificates.values() ]) {\n\t\t\tif (certificate.visited) continue;\n\n\t\t\tthis.observedCertificates.delete(certificate.id);\n\t\t}\n\t\tfor (const observedCodec of [ ...this.observedCodecs.values() ]) {\n\t\t\tif (observedCodec.visited) continue;\n\n\t\t\tthis.observedCodecs.delete(observedCodec.id);\n\t\t\tthis._notify('codec-removed', { ...this.eventScope, observedCodec });\n\t\t}\n\t\tfor (const observedDataChannel of [ ...this.observedDataChannels.values() ]) {\n\t\t\tif (observedDataChannel.visited) continue;\n\n\t\t\tthis.observedDataChannels.delete(observedDataChannel.id);\n\t\t\tthis._notify('data-channel-removed', { ...this.eventScope, observedDataChannel });\n\t\t}\n\t\tfor (const observedIceCandidate of [ ...this.observedIceCandidates.values() ]) {\n\t\t\tif (observedIceCandidate.visited) continue;\n\n\t\t\tthis.observedIceCandidates.delete(observedIceCandidate.id);\n\t\t\tthis._notify('ice-candidate-removed', { ...this.eventScope, observedIceCandidate });\n\t\t}\n\t\tfor (const observedIceCandidatePair of [ ...this.observedIceCandidatesPair.values() ]) {\n\t\t\tif (observedIceCandidatePair.visited) continue;\n\n\t\t\tthis.observedIceCandidatesPair.delete(observedIceCandidatePair.id);\n\t\t\tthis._notify('ice-candidate-pair-removed', { ...this.eventScope, observedIceCandidatePair });\n\t\t}\n\t\tfor (const observedIceTransport of [ ...this.observedIceTransports.values() ]) {\n\t\t\tif (observedIceTransport.visited) continue;\n\n\t\t\tthis.observedIceTransports.delete(observedIceTransport.id);\n\t\t\tthis._notify('ice-transport-removed', { ...this.eventScope, observedIceTransport });\n\t\t}\n\t\tfor (const observedInboundRtp of [ ...this.observedInboundRtps.values() ]) {\n\t\t\tif (observedInboundRtp.visited) continue;\n\n\t\t\tthis.observedInboundRtps.delete(observedInboundRtp.ssrc);\n\t\t\tthis._notify('inbound-rtp-removed', { ...this.eventScope, observedInboundRtp });\n\t\t}\n\t\tfor (const observedInboundTrack of [ ...this.observedInboundTracks.values() ]) {\n\t\t\tif (observedInboundTrack.visited) continue;\n\n\t\t\tthis.observedInboundTracks.delete(observedInboundTrack.id);\n\t\t\tthis.emit('removed-inbound-track', observedInboundTrack);\n\t\t\tthis._notify('inbound-track-removed', { ...this.eventScope, observedInboundTrack });\n\t\t}\n\t\tfor (const observedMediaPlayout of [ ...this.observedMediaPlayouts.values() ]) {\n\t\t\tif (observedMediaPlayout.visited) continue;\n\n\t\t\tthis.observedMediaPlayouts.delete(observedMediaPlayout.id);\n\t\t\tthis._notify('media-playout-removed', { ...this.eventScope, observedMediaPlayout });\n\t\t}\n\t\tfor (const observedMediaSource of [ ...this.observedMediaSources.values() ]) {\n\t\t\tif (observedMediaSource.visited) continue;\n\n\t\t\tthis.observedMediaSources.delete(observedMediaSource.id);\n\t\t\tthis._notify('media-source-removed', { ...this.eventScope, observedMediaSource });\n\t\t}\n\t\tfor (const observedOutboundRtp of [ ...this.observedOutboundRtps.values() ]) {\n\t\t\tif (observedOutboundRtp.visited) continue;\n\n\t\t\tthis.observedOutboundRtps.delete(observedOutboundRtp.ssrc);\n\t\t\tthis._notify('outbound-rtp-removed', { ...this.eventScope, observedOutboundRtp });\n\t\t}\n\t\tfor (const observedOutboundTrack of [ ...this.observedOutboundTracks.values() ]) {\n\t\t\tif (observedOutboundTrack.visited) continue;\n\n\t\t\tthis.observedOutboundTracks.delete(observedOutboundTrack.id);\n\t\t\tthis.emit('removed-outbound-track', observedOutboundTrack);\n\t\t\tthis._notify('outbound-track-removed', { ...this.eventScope, observedOutboundTrack });\n\t\t}\n\t\tfor (const observedPeerConnectionTransport of [ ...this.observedPeerConnectionTransports.values() ]) {\n\t\t\tif (observedPeerConnectionTransport.visited) continue;\n\n\t\t\tthis.observedPeerConnectionTransports.delete(observedPeerConnectionTransport.id);\n\t\t\tthis._notify('peer-connection-transport-removed', { ...this.eventScope, observedPeerConnectionTransport });\n\t\t}\n\t\tfor (const observedRemoteInboundRtp of [ ...this.observedRemoteInboundRtps.values() ]) {\n\t\t\tif (observedRemoteInboundRtp.visited) continue;\n\n\t\t\tthis.observedRemoteInboundRtps.delete(observedRemoteInboundRtp.ssrc);\n\t\t\tthis._notify('remote-inbound-rtp-removed', { ...this.eventScope, observedRemoteInboundRtp });\n\t\t}\n\t\tfor (const observedRemoteOutboundRtp of [ ...this.observedRemoteOutboundRtps.values() ]) {\n\t\t\tif (observedRemoteOutboundRtp.visited) continue;\n\n\t\t\tthis.observedRemoteOutboundRtps.delete(observedRemoteOutboundRtp.ssrc);\n\t\t\tthis._notify('remote-outbound-rtp-removed', { ...this.eventScope, observedRemoteOutboundRtp });\n\t\t}\n\t}\n\n\tprivate _updateCertificateStats(stats: CertificateStats) {\n\t\tlet observedCertificate = this.observedCertificates.get(stats.id);\n\n\t\tif (!observedCertificate) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.fingerprint) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid CertificateStats (missing timestamp OR id OR fingerprint field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedCertificate = new ObservedCertificate(stats.timestamp, stats.id, this);\n\n\t\t\tobservedCertificate.update(stats);\n\n\t\t\tthis.observedCertificates.set(stats.id, observedCertificate);\n\t\t\tthis._notify('certificate-added', { ...this.eventScope, observedCertificate });\n\t\t} else {\n\t\t\tobservedCertificate.update(stats);\n\t\t\tthis._notify('certificate-updated', { ...this.eventScope, observedCertificate });\n\t\t}\n\n\t\treturn observedCertificate;\n\t}\n\n\tprivate _updateCodecStats(stats: CodecStats) {\n\t\tlet observedCodec = this.observedCodecs.get(stats.id);\n\n\t\tif (!observedCodec) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.mimeType) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid CodecStats (missing timestamp OR id OR mimeType field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedCodec = new ObservedCodec(stats.timestamp, stats.id, stats.mimeType, this);\n\n\t\t\tobservedCodec.update(stats);\n\n\t\t\tthis.observedCodecs.set(stats.id, observedCodec);\n\t\t\tthis._notify('codec-added', { ...this.eventScope, observedCodec });\n\t\t} else {\n\t\t\tobservedCodec.update(stats);\n\t\t}\n\t\tthis._notify('codec-updated', { ...this.eventScope, observedCodec });\n\n\t\treturn observedCodec;\n\t}\n\n\tprivate _updateDataChannelStats(stats: DataChannelStats) {\n\t\tlet observedDataChannel = this.observedDataChannels.get(stats.id);\n\n\t\tif (!observedDataChannel) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid DataChannelStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedDataChannel = new ObservedDataChannel(stats.timestamp, stats.id, this);\n\n\t\t\tobservedDataChannel.update(stats);\n\n\t\t\tthis.observedDataChannels.set(stats.id, observedDataChannel);\n\t\t\tthis._notify('data-channel-added', { ...this.eventScope, observedDataChannel });\n\t\t} else {\n\t\t\tobservedDataChannel.update(stats);\n\t\t}\n\t\tthis._notify('data-channel-updated', { ...this.eventScope, observedDataChannel });\n\n\t\treturn observedDataChannel;\n\t}\n\n\tprivate _updateIceCandidateStats(stats: IceCandidateStats) {\n\t\tlet observedIceCandidate = this.observedIceCandidates.get(stats.id);\n\n\t\tif (!observedIceCandidate) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedIceCandidate = new ObservedIceCandidate(stats.timestamp, stats.id, this);\n\n\t\t\tobservedIceCandidate.update(stats);\n\n\t\t\tthis.observedIceCandidates.set(stats.id, observedIceCandidate);\n\t\t\tthis._notify('ice-candidate-added', { ...this.eventScope, observedIceCandidate });\n\t\t} else {\n\t\t\tobservedIceCandidate.update(stats);\n\t\t}\n\t\tthis._notify('ice-candidate-updated', { ...this.eventScope, observedIceCandidate });\n\n\t\treturn observedIceCandidate;\n\t}\n\n\tprivate _updateIceCandidatePairStats(stats: IceCandidateStats) {\n\t\tlet observedIceCandidatePair = this.observedIceCandidatesPair.get(stats.id);\n\n\t\tif (!observedIceCandidatePair) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedIceCandidatePair = new ObservedIceCandidatePair(stats.timestamp, stats.id, this);\n\n\t\t\tobservedIceCandidatePair.update(stats);\n\n\t\t\tthis.observedIceCandidatesPair.set(stats.id, observedIceCandidatePair);\n\t\t\tthis._notify('ice-candidate-pair-added', { ...this.eventScope, observedIceCandidatePair });\n\t\t} else {\n\t\t\tobservedIceCandidatePair.update(stats);\n\t\t}\n\t\tthis._notify('ice-candidate-pair-updated', { ...this.eventScope, observedIceCandidatePair });\n\n\t\treturn observedIceCandidatePair;\n\t}\n\n\tprivate _updateIceTransportStats(stats: IceCandidateStats) {\n\t\tlet observedIceTransport = this.observedIceTransports.get(stats.id);\n\n\t\tif (!observedIceTransport) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedIceTransport = new ObservedIceTransport(stats.timestamp, stats.id, this);\n\n\t\t\tobservedIceTransport.update(stats);\n\n\t\t\tthis.observedIceTransports.set(stats.id, observedIceTransport);\n\t\t\tthis._notify('ice-transport-added', { ...this.eventScope, observedIceTransport });\n\t\t} else {\n\t\t\tobservedIceTransport.update(stats);\n\t\t}\n\t\tthis._notify('ice-transport-updated', { ...this.eventScope, observedIceTransport });\n\n\t\treturn observedIceTransport;\n\t}\n\n\tprivate _updateInboundRtpStats(stats: InboundRtpStats) {\n\t\tlet observedInboundRtp = this.observedInboundRtps.get(stats.ssrc);\n\n\t\tif (!observedInboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind || !stats.trackIdentifier) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR ssrc OR kind OR trackIdentifier field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedInboundRtp = new ObservedInboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tstats.trackIdentifier,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedInboundRtp.update(stats);\n\n\t\t\tthis.observedInboundRtps.set(stats.ssrc, observedInboundRtp);\n\t\t\tthis._notify('inbound-rtp-added', { ...this.eventScope, observedInboundRtp });\n\t\t} else {\n\t\t\tobservedInboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('inbound-rtp-updated', { ...this.eventScope, observedInboundRtp });\n\n\t\treturn observedInboundRtp;\n\t}\n\n\tprivate _updateInboundTrackSample(stats: InboundTrackSample) {\n\t\tlet observedInboundTrack = this.observedInboundTracks.get(stats.id);\n\n\t\tif (!observedInboundTrack) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst inboundRtp = [ ...this.observedInboundRtps.values() ].find((inbRtp) => inbRtp.trackIdentifier === stats.id);\n\t\t\tconst mediaPlayout = inboundRtp ?\n\t\t\t\t[ ...this.observedMediaPlayouts.values() ].find((mp) => mp.id === inboundRtp.playoutId) : undefined;\n\n\t\t\tobservedInboundTrack = new ObservedInboundTrack(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis,\n\t\t\t\tinboundRtp,\n\t\t\t\tmediaPlayout,\n\t\t\t);\n\n\t\t\tobservedInboundTrack.update(stats);\n\n\t\t\tthis.observedInboundTracks.set(stats.id, observedInboundTrack);\n\t\t\tthis._notify('inbound-track-added', { ...this.eventScope, observedInboundTrack });\n\t\t} else {\n\t\t\tobservedInboundTrack.update(stats);\n\t\t}\n\t\tthis._notify('inbound-track-updated', { ...this.eventScope, observedInboundTrack });\n\n\t\treturn observedInboundTrack;\n\t}\n\n\tprivate _updateMediaPlayoutStats(stats: MediaPlayoutStats) {\n\t\tlet observedMediaPlayout = this.observedMediaPlayouts.get(stats.id);\n\n\t\tif (!observedMediaPlayout) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind OR trackIdentifier field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedMediaPlayout = new ObservedMediaPlayout(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedMediaPlayout.update(stats);\n\n\t\t\tthis.observedMediaPlayouts.set(stats.id, observedMediaPlayout);\n\t\t\tthis._notify('media-playout-added', { ...this.eventScope, observedMediaPlayout });\n\t\t} else {\n\t\t\tobservedMediaPlayout.update(stats);\n\t\t}\n\t\tthis._notify('media-playout-updated', { ...this.eventScope, observedMediaPlayout });\n\n\t\treturn observedMediaPlayout;\n\t}\n\n\tprivate _updateMediaSourceStats(stats: MediaSourceStats) {\n\t\tlet observedMediaSource = this.observedMediaSources.get(stats.id);\n\n\t\tif (!observedMediaSource) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedMediaSource = new ObservedMediaSource(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedMediaSource.update(stats);\n\n\t\t\tthis.observedMediaSources.set(stats.id, observedMediaSource);\n\t\t\tthis._notify('media-source-added', { ...this.eventScope, observedMediaSource });\n\t\t} else {\n\t\t\tobservedMediaSource.update(stats);\n\t\t}\n\t\tthis._notify('media-source-updated', { ...this.eventScope, observedMediaSource });\n\n\t\treturn observedMediaSource;\n\t}\n\n\tprivate _updateOutboundRtpStats(stats: OutboundRtpStats) {\n\t\tlet observedOutboundRtp = this.observedOutboundRtps.get(stats.ssrc);\n\n\t\tif (!observedOutboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid OutboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedOutboundRtp = new ObservedOutboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedOutboundRtp.update(stats);\n\n\t\t\tthis.observedOutboundRtps.set(stats.ssrc, observedOutboundRtp);\n\t\t\tthis._notify('outbound-rtp-added', { ...this.eventScope, observedOutboundRtp });\n\t\t} else {\n\t\t\tobservedOutboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('outbound-rtp-updated', { ...this.eventScope, observedOutboundRtp });\n\n\t\treturn observedOutboundRtp;\n\t}\n\n\tprivate _updateOutboundTrackSample(stats: OutboundTrackSample) {\n\t\tlet observedOutboundTrack = this.observedOutboundTracks.get(stats.id);\n\n\t\tif (!observedOutboundTrack) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid OutboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst observedMediaSource = [ ...this.observedMediaSources.values() ].find((mediaSource) => mediaSource.trackIdentifier === stats.id);\n\t\t\tconst outboundRtps = observedMediaSource\n\t\t\t\t? [ ...this.observedOutboundRtps.values() ].filter((outboundRtp) => outboundRtp.mediaSourceId === observedMediaSource?.id) : undefined;\n\n\t\t\tobservedOutboundTrack = new ObservedOutboundTrack(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis,\n\t\t\t\toutboundRtps,\n\t\t\t\tobservedMediaSource,\n\t\t\t);\n\n\t\t\tobservedOutboundTrack.update(stats);\n\n\t\t\tthis.observedOutboundTracks.set(stats.id, observedOutboundTrack);\n\t\t\tthis._notify('outbound-track-added', { ...this.eventScope, observedOutboundTrack });\n\t\t} else {\n\t\t\tobservedOutboundTrack.update(stats);\n\t\t}\n\t\tthis._notify('outbound-track-updated', { ...this.eventScope, observedOutboundTrack });\n\n\t\treturn observedOutboundTrack;\n\t}\n\n\tprivate _updatePeerConnectionTransportStats(stats: PeerConnectionTransportStats) {\n\t\tlet observedPeerConnectionTransport = this.observedPeerConnectionTransports.get(stats.id);\n\n\t\tif (!observedPeerConnectionTransport) {\n\t\t\tif (!stats.timestamp || !stats.id) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid PeerConnectionTransportStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedPeerConnectionTransport = new ObservedPeerConnectionTransport(stats.timestamp, stats.id, this);\n\n\t\t\tobservedPeerConnectionTransport.update(stats);\n\n\t\t\tthis.observedPeerConnectionTransports.set(stats.id, observedPeerConnectionTransport);\n\t\t\tthis._notify('peer-connection-transport-added', { ...this.eventScope, observedPeerConnectionTransport });\n\t\t} else {\n\t\t\tobservedPeerConnectionTransport.update(stats);\n\t\t}\n\t\tthis._notify('peer-connection-transport-updated', { ...this.eventScope, observedPeerConnectionTransport });\n\n\t\treturn observedPeerConnectionTransport;\n\t}\n\n\tprivate _updateRemoteInboundRtpStats(stats: RemoteInboundRtpStats) {\n\t\tlet observedRemoteInboundRtp = this.observedRemoteInboundRtps.get(stats.ssrc);\n\n\t\tif (!observedRemoteInboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid RemoteInboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedRemoteInboundRtp = new ObservedRemoteInboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedRemoteInboundRtp.update(stats);\n\n\t\t\tthis.observedRemoteInboundRtps.set(stats.ssrc, observedRemoteInboundRtp);\n\t\t\tthis._notify('remote-inbound-rtp-added', { ...this.eventScope, observedRemoteInboundRtp });\n\t\t} else {\n\t\t\tobservedRemoteInboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('remote-inbound-rtp-updated', { ...this.eventScope, observedRemoteInboundRtp });\n\n\t\treturn observedRemoteInboundRtp;\n\t}\n\n\tprivate _updateRemoteOutboundRtpStats(stats: RemoteOutboundRtpStats) {\n\t\tlet observedRemoteOutboundRtp = this.observedRemoteOutboundRtps.get(stats.ssrc);\n\n\t\tif (!observedRemoteOutboundRtp) {\n\t\t\tif (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {\n\t\t\t\treturn logger.warn(\n\t\t\t\t\t`ObservedPeerConnection received an invalid RemoteOutboundRtpStats (missing timestamp OR id OR ssrc OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,\n\t\t\t\t\tstats\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tobservedRemoteOutboundRtp = new ObservedRemoteOutboundRtp(\n\t\t\t\tstats.timestamp,\n\t\t\t\tstats.id,\n\t\t\t\tstats.ssrc,\n\t\t\t\tstats.kind as MediaKind,\n\t\t\t\tthis\n\t\t\t);\n\n\t\t\tobservedRemoteOutboundRtp.update(stats);\n\n\t\t\tthis.observedRemoteOutboundRtps.set(stats.ssrc, observedRemoteOutboundRtp);\n\t\t\tthis._notify('remote-outbound-rtp-added', { ...this.eventScope, observedRemoteOutboundRtp });\n\t\t} else {\n\t\t\tobservedRemoteOutboundRtp.update(stats);\n\t\t}\n\t\tthis._notify('remote-outbound-rtp-updated', { ...this.eventScope, observedRemoteOutboundRtp });\n\n\t\treturn observedRemoteOutboundRtp;\n\t}\n\n\t/** Emit an Observer-bus event scoped to this peer connection. */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.client.call.observer.emit(type, ...args);\n\t}\n}\n","/**\n * Small statistics helpers used by the aggregators and detectors.\n *\n * Rationale: a mean is a poor summary for call telemetry — one participant with a 1500 ms RTT\n * skews the average for nine healthy ones. Detectors should reason with medians, high percentiles\n * and \"affected ratios\" instead.\n */\n\n/** A distribution summary of a numeric sample set. */\nexport type StatsSummary = {\n\tcount: number;\n\tmin: number;\n\tmax: number;\n\tmean: number;\n\tmedian: number;\n\tp75: number;\n\tp95: number;\n};\n\n/**\n * The p-th percentile (0..1) using linear interpolation between closest ranks.\n * Returns `undefined` for an empty input.\n */\nexport function percentile(values: number[], p: number): number | undefined {\n\tif (values.length === 0) return undefined;\n\n\tconst sorted = [ ...values ].sort((a, b) => a - b);\n\n\tif (sorted.length === 1) return sorted[0];\n\n\tconst clamped = Math.min(1, Math.max(0, p));\n\tconst position = clamped * (sorted.length - 1);\n\tconst lowerIndex = Math.floor(position);\n\tconst upperIndex = Math.ceil(position);\n\n\tif (lowerIndex === upperIndex) return sorted[lowerIndex];\n\n\tconst weight = position - lowerIndex;\n\n\treturn (sorted[lowerIndex] * (1 - weight)) + (sorted[upperIndex] * weight);\n}\n\n/** The median (50th percentile). `undefined` for an empty input. */\nexport function median(values: number[]): number | undefined {\n\treturn percentile(values, 0.5);\n}\n\n/** Summarize a numeric sample set. Returns `undefined` for an empty input. */\nexport function summarize(values: number[]): StatsSummary | undefined {\n\tif (values.length === 0) return undefined;\n\n\tlet min = values[0];\n\tlet max = values[0];\n\tlet sum = 0;\n\n\tfor (const value of values) {\n\t\tif (value < min) min = value;\n\t\tif (max < value) max = value;\n\t\tsum += value;\n\t}\n\n\treturn {\n\t\tcount: values.length,\n\t\tmin,\n\t\tmax,\n\t\tmean: sum / values.length,\n\t\tmedian: percentile(values, 0.5) as number,\n\t\tp75: percentile(values, 0.75) as number,\n\t\tp95: percentile(values, 0.95) as number,\n\t};\n}\n\n/**\n * A counter-reset-safe delta: the increase of a cumulative counter between two observations.\n *\n * Returns `0` when the counter went backwards (reset / SSRC reuse) or when either side is missing.\n * NOTE the guard is `>=` on **defined** values — a previous value of `0` is a perfectly valid\n * baseline, so `0 -> 5` correctly yields `5` (using a truthiness check here silently drops the\n * first interval of every counter, which is exactly when the first loss/freeze event happens).\n */\nexport function counterDelta(previous: number | undefined, current: number | undefined): number {\n\tif (previous === undefined || current === undefined) return 0;\n\tif (current < previous) return 0;\n\n\treturn current - previous;\n}\n\n/** An entry retained by {@link SlidingWindow}. */\nexport type SlidingWindowEntry<T> = {\n\ttimestamp: number;\n\tvalue: T;\n};\n\n/**\n * A time-bounded ring buffer used by detectors that reason over a window (\"N of M clients degraded\n * within 10 s\"). Entries older than `windowMs` are evicted on write and on read.\n */\nexport class SlidingWindow<T> {\n\tprivate _entries: SlidingWindowEntry<T>[] = [];\n\n\tpublic constructor(\n\t\tpublic readonly windowMs: number,\n\n\t\t/** Optional hard cap on retained entries, to bound memory on very chatty inputs. */\n\t\tpublic readonly maxEntries = 1024,\n\t) {\n\t}\n\n\t/** Add an entry (defaults to `Date.now()`), then evict anything outside the window. */\n\tpublic add(value: T, timestamp = Date.now()): void {\n\t\tthis._entries.push({ timestamp, value });\n\t\tthis._evict(timestamp);\n\t}\n\n\t/** The entries still inside the window, oldest first. */\n\tpublic entries(now = Date.now()): SlidingWindowEntry<T>[] {\n\t\tthis._evict(now);\n\n\t\treturn this._entries;\n\t}\n\n\t/** The values still inside the window, oldest first. */\n\tpublic values(now = Date.now()): T[] {\n\t\treturn this.entries(now).map((entry) => entry.value);\n\t}\n\n\tpublic get size(): number {\n\t\treturn this._entries.length;\n\t}\n\n\tpublic clear(): void {\n\t\tthis._entries = [];\n\t}\n\n\tprivate _evict(now: number) {\n\t\tconst oldest = now - this.windowMs;\n\n\t\twhile (0 < this._entries.length && this._entries[0].timestamp < oldest) {\n\t\t\tthis._entries.shift();\n\t\t}\n\t\twhile (this.maxEntries < this._entries.length) {\n\t\t\tthis._entries.shift();\n\t\t}\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { InboundRtpStats } from './schema/ClientSample';\nimport { counterDelta } from './utils/stats';\n\nexport class ObservedInboundRtp implements InboundRtpStats {\n\tpublic appData?: Record<string, unknown>;\n\n\tprivate _visited = false;\n\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsReceived?: number | undefined;\n\tpacketsLost?: number | undefined;\n\tmid?: string | undefined;\n\tremoteId?: string | undefined;\n\tframesDecoded?: number | undefined;\n\tkeyFramesDecoded?: number | undefined;\n\tframesRendered?: number | undefined;\n\tframesDropped?: number | undefined;\n\tframeWidth?: number | undefined;\n\tframeHeight?: number | undefined;\n\tframesPerSecond?: number | undefined;\n\tqpSum?: number | undefined;\n\ttotalDecodeTime?: number | undefined;\n\ttotalInterFrameDelay?: number | undefined;\n\ttotalSquaredInterFrameDelay?: number | undefined;\n\tpauseCount?: number | undefined;\n\ttotalPausesDuration?: number | undefined;\n\tfreezeCount?: number | undefined;\n\ttotalFreezesDuration?: number | undefined;\n\tlastPacketReceivedTimestamp?: number | undefined;\n\theaderBytesReceived?: number | undefined;\n\tpacketsDiscarded?: number | undefined;\n\tfecBytesReceived?: number | undefined;\n\tfecPacketsReceived?: number | undefined;\n\tfecPacketsDiscarded?: number | undefined;\n\tbytesReceived?: number | undefined;\n\tnackCount?: number | undefined;\n\tfirCount?: number | undefined;\n\tpliCount?: number | undefined;\n\ttotalProcessingDelay?: number | undefined;\n\testimatedPlayoutTimestamp?: number | undefined;\n\tjitterBufferDelay?: number | undefined;\n\tjitterBufferTargetDelay?: number | undefined;\n\tjitterBufferEmittedCount?: number | undefined;\n\tjitterBufferMinimumDelay?: number | undefined;\n\ttotalSamplesReceived?: number | undefined;\n\tconcealedSamples?: number | undefined;\n\tsilentConcealedSamples?: number | undefined;\n\tconcealmentEvents?: number | undefined;\n\tinsertedSamplesForDeceleration?: number | undefined;\n\tremovedSamplesForAcceleration?: number | undefined;\n\taudioLevel?: number | undefined;\n\ttotalAudioEnergy?: number | undefined;\n\ttotalSamplesDuration?: number | undefined;\n\tframesReceived?: number | undefined;\n\tdecoderImplementation?: string | undefined;\n\tplayoutId?: string | undefined;\n\tpowerEfficientDecoder?: boolean | undefined;\n\tframesAssembledFromMultiplePackets?: number | undefined;\n\ttotalAssemblyTime?: number | undefined;\n\tretransmittedPacketsReceived?: number | undefined;\n\tretransmittedBytesReceived?: number | undefined;\n\trtxSsrc?: number | undefined;\n\tfecSsrc?: number | undefined;\n\ttotalCorruptionProbability?: number | undefined;\n\ttotalSquaredCorruptionProbability?: number | undefined;\n\tcorruptionMeasurements?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\tjitter?: number | undefined;\n\t\n\tpublic bitrate = 0;\n\tpublic fractionLost?: number;\n\tpublic bitPerPixel = 0;\n\n\tpublic deltaLostPackets = 0;\n\tpublic deltaReceivedPackets = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaReceivedSamples = 0;\n\tpublic deltaSilentConcealedSamples = 0;\n\n\t// Per-tick, counter-reset-safe deltas of the cumulative RTCStats counters. These are what\n\t// detectors need (\"how many freezes/PLIs in THIS tick\"), as opposed to the lifetime totals.\n\tpublic deltaConcealedSamples = 0;\n\tpublic deltaConcealmentEvents = 0;\n\tpublic deltaFreezeCount = 0;\n\tpublic deltaFreezesDuration = 0;\n\tpublic deltaPliCount = 0;\n\tpublic deltaNackCount = 0;\n\tpublic deltaFirCount = 0;\n\tpublic deltaPacketsDiscarded = 0;\n\tpublic deltaFramesDecoded = 0;\n\tpublic deltaFramesReceived = 0;\n\tpublic deltaFramesRendered = 0;\n\tpublic deltaFramesDropped = 0;\n\tpublic deltaKeyFramesDecoded = 0;\n\tpublic deltaDecodeTime = 0;\n\tpublic deltaJitterBufferDelay = 0;\n\tpublic deltaJitterBufferEmittedCount = 0;\n\tpublic deltaRetransmittedPacketsReceived = 0;\n\tpublic deltaFecPacketsReceived = 0;\n\tpublic deltaFecPacketsDiscarded = 0;\n\tpublic deltaPausesDuration = 0;\n\n\t/**\n\t * Mean jitter-buffer delay for the frames/samples emitted in this tick (seconds), derived from\n\t * the cumulative `jitterBufferDelay` / `jitterBufferEmittedCount` pair — the only correct way to\n\t * read those two counters.\n\t */\n\tpublic jitterBufferDelayInMs?: number;\n\n\t/** Fraction of the samples received in this tick that were concealed (0..1). */\n\tpublic concealmentRatio?: number;\n\n\t/** Fraction of the frames received in this tick that were dropped before rendering (0..1). */\n\tpublic framesDroppedRatio?: number;\n\n\t/**\n\t * `true` when the codec or decoder implementation changed in this tick.\n\t *\n\t * Chrome resets `packetsReceived`/`bytesReceived` on an SSRC when the codec switches\n\t * (crbug.com/webrtc/5361, open since 2015), which shows up as a sawtooth spike or a negative\n\t * rate. Every delta in this tick is therefore suppressed to `0` rather than reported as traffic\n\t * — otherwise a room-wide codec rollout produces a synchronized fake-degradation alert across\n\t * every participant at once.\n\t */\n\tpublic counterResetBoundary = false;\n\n\t// Derived from the corresponding remote-outbound-rtp (sender report), when present.\n\tpublic remoteRttInMs?: number;\n\tpublic remoteBytesSent?: number;\n\tpublic remotePacketsSent?: number;\n\tpublic remoteTimestamp?: number;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tpublic trackIdentifier: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getRemoteOutboundRtp() {\n\t\treturn this._peerConnection.observedRemoteOutboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic getMediaPlayout() {\n\t\treturn this._peerConnection.observedMediaPlayouts.get(this.playoutId ?? '');\n\t}\n\n\tpublic getTrack() {\n\t\treturn this._peerConnection.observedInboundTracks.get(this.trackIdentifier);\n\t}\n\n\tpublic update(stats: InboundRtpStats) {\n\t\tthis._visited = true;\n\t\tthis.deltaBytesReceived = 0;\n\t\tthis.deltaLostPackets = 0;\n\t\tthis.deltaReceivedPackets = 0;\n\t\tthis.deltaReceivedSamples = 0;\n\t\tthis.deltaSilentConcealedSamples = 0;\n\t\tthis.remoteRttInMs = undefined;\n\t\tthis.remoteBytesSent = undefined;\n\t\tthis.remotePacketsSent = undefined;\n\t\tthis.remoteTimestamp = undefined;\n\t\tthis.bitrate = 0;\n\t\tthis.fractionLost = undefined;\n\t\tthis.bitPerPixel = 0;\n\n\t\tthis.deltaConcealedSamples = 0;\n\t\tthis.deltaConcealmentEvents = 0;\n\t\tthis.deltaFreezeCount = 0;\n\t\tthis.deltaFreezesDuration = 0;\n\t\tthis.deltaPausesDuration = 0;\n\t\tthis.deltaPliCount = 0;\n\t\tthis.deltaNackCount = 0;\n\t\tthis.deltaFirCount = 0;\n\t\tthis.deltaPacketsDiscarded = 0;\n\t\tthis.deltaFramesDecoded = 0;\n\t\tthis.deltaFramesReceived = 0;\n\t\tthis.deltaFramesRendered = 0;\n\t\tthis.deltaFramesDropped = 0;\n\t\tthis.deltaKeyFramesDecoded = 0;\n\t\tthis.deltaDecodeTime = 0;\n\t\tthis.deltaJitterBufferDelay = 0;\n\t\tthis.deltaJitterBufferEmittedCount = 0;\n\t\tthis.deltaRetransmittedPacketsReceived = 0;\n\t\tthis.deltaFecPacketsReceived = 0;\n\t\tthis.deltaFecPacketsDiscarded = 0;\n\t\tthis.jitterBufferDelayInMs = undefined;\n\t\tthis.concealmentRatio = undefined;\n\t\tthis.framesDroppedRatio = undefined;\n\n\t\tconst elapsedTimeInMs = stats.timestamp - this.timestamp;\n\n\t\t// crbug.com/webrtc/5361: a codec switch resets the cumulative counters on the SSRC. Treat the\n\t\t// tick as a boundary and derive nothing from it, instead of reporting a phantom spike.\n\t\tthis.counterResetBoundary = (this.codecId !== undefined && stats.codecId !== undefined && this.codecId !== stats.codecId)\n\t\t\t|| (this.decoderImplementation !== undefined && stats.decoderImplementation !== undefined\n\t\t\t\t&& this.decoderImplementation !== stats.decoderImplementation);\n\n\t\tif (0 < elapsedTimeInMs && !this.counterResetBoundary) {\n\t\t\tconst elapsedInSeconds = elapsedTimeInMs / 1000;\n\n\t\t\t// All deltas are counter-reset-safe and treat a previous value of `0` as a valid baseline\n\t\t\t// (a truthiness guard here silently drops the first interval of every counter).\n\t\t\tthis.deltaBytesReceived = counterDelta(this.bytesReceived, stats.bytesReceived);\n\t\t\tthis.deltaLostPackets = counterDelta(this.packetsLost, stats.packetsLost);\n\t\t\tthis.deltaReceivedPackets = counterDelta(this.packetsReceived, stats.packetsReceived);\n\t\t\tthis.deltaReceivedSamples = counterDelta(this.totalSamplesReceived, stats.totalSamplesReceived);\n\t\t\tthis.deltaSilentConcealedSamples = counterDelta(this.silentConcealedSamples, stats.silentConcealedSamples);\n\n\t\t\tthis.deltaConcealedSamples = counterDelta(this.concealedSamples, stats.concealedSamples);\n\t\t\tthis.deltaConcealmentEvents = counterDelta(this.concealmentEvents, stats.concealmentEvents);\n\t\t\tthis.deltaFreezeCount = counterDelta(this.freezeCount, stats.freezeCount);\n\t\t\tthis.deltaFreezesDuration = counterDelta(this.totalFreezesDuration, stats.totalFreezesDuration);\n\t\t\tthis.deltaPausesDuration = counterDelta(this.totalPausesDuration, stats.totalPausesDuration);\n\t\t\tthis.deltaPliCount = counterDelta(this.pliCount, stats.pliCount);\n\t\t\tthis.deltaNackCount = counterDelta(this.nackCount, stats.nackCount);\n\t\t\tthis.deltaFirCount = counterDelta(this.firCount, stats.firCount);\n\t\t\tthis.deltaPacketsDiscarded = counterDelta(this.packetsDiscarded, stats.packetsDiscarded);\n\t\t\tthis.deltaFramesDecoded = counterDelta(this.framesDecoded, stats.framesDecoded);\n\t\t\tthis.deltaFramesReceived = counterDelta(this.framesReceived, stats.framesReceived);\n\t\t\tthis.deltaFramesRendered = counterDelta(this.framesRendered, stats.framesRendered);\n\t\t\tthis.deltaFramesDropped = counterDelta(this.framesDropped, stats.framesDropped);\n\t\t\tthis.deltaKeyFramesDecoded = counterDelta(this.keyFramesDecoded, stats.keyFramesDecoded);\n\t\t\tthis.deltaDecodeTime = counterDelta(this.totalDecodeTime, stats.totalDecodeTime);\n\t\t\tthis.deltaJitterBufferDelay = counterDelta(this.jitterBufferDelay, stats.jitterBufferDelay);\n\t\t\tthis.deltaJitterBufferEmittedCount = counterDelta(this.jitterBufferEmittedCount, stats.jitterBufferEmittedCount);\n\t\t\tthis.deltaRetransmittedPacketsReceived = counterDelta(this.retransmittedPacketsReceived, stats.retransmittedPacketsReceived);\n\t\t\tthis.deltaFecPacketsReceived = counterDelta(this.fecPacketsReceived, stats.fecPacketsReceived);\n\t\t\tthis.deltaFecPacketsDiscarded = counterDelta(this.fecPacketsDiscarded, stats.fecPacketsDiscarded);\n\n\t\t\t// bits per second (matches ObservedOutboundRtp.bitrate and the client-level bitrates).\n\t\t\tthis.bitrate = (this.deltaBytesReceived * 8) / elapsedInSeconds;\n\n\t\t\t// bits per pixel of the frames decoded in this tick.\n\t\t\tconst pixels = (stats.frameWidth ?? 0) * (stats.frameHeight ?? 0);\n\n\t\t\tif (0 < pixels && 0 < this.deltaFramesReceived) {\n\t\t\t\tthis.bitPerPixel = (this.deltaBytesReceived * 8) / (this.deltaFramesReceived * pixels);\n\t\t\t}\n\n\t\t\t// Report 0 (not `undefined`) when there was traffic but no loss, so detectors can tell\n\t\t\t// \"healthy\" apart from \"no data\".\n\t\t\tif (0 < this.deltaReceivedPackets || 0 < this.deltaLostPackets) {\n\t\t\t\tthis.fractionLost = this.deltaLostPackets / (this.deltaLostPackets + this.deltaReceivedPackets);\n\t\t\t}\n\t\t\tif (0 < this.deltaJitterBufferEmittedCount) {\n\t\t\t\tthis.jitterBufferDelayInMs = (this.deltaJitterBufferDelay / this.deltaJitterBufferEmittedCount) * 1000;\n\t\t\t}\n\t\t\tif (0 < this.deltaReceivedSamples) {\n\t\t\t\tthis.concealmentRatio = this.deltaConcealedSamples / this.deltaReceivedSamples;\n\t\t\t}\n\t\t\tif (0 < this.deltaFramesReceived) {\n\t\t\t\tthis.framesDroppedRatio = this.deltaFramesDropped / this.deltaFramesReceived;\n\t\t\t}\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.packetsLost = stats.packetsLost;\n\t\tthis.mid = stats.mid;\n\t\tthis.remoteId = stats.remoteId;\n\t\tthis.framesDecoded = stats.framesDecoded;\n\t\tthis.keyFramesDecoded = stats.keyFramesDecoded;\n\t\tthis.framesRendered = stats.framesRendered;\n\t\tthis.framesDropped = stats.framesDropped;\n\t\tthis.frameWidth = stats.frameWidth;\n\t\tthis.frameHeight = stats.frameHeight;\n\t\tthis.framesPerSecond = stats.framesPerSecond;\n\t\tthis.qpSum = stats.qpSum;\n\t\tthis.totalDecodeTime = stats.totalDecodeTime;\n\t\tthis.totalInterFrameDelay = stats.totalInterFrameDelay;\n\t\tthis.totalSquaredInterFrameDelay = stats.totalSquaredInterFrameDelay;\n\t\tthis.pauseCount = stats.pauseCount;\n\t\tthis.totalPausesDuration = stats.totalPausesDuration;\n\t\tthis.freezeCount = stats.freezeCount;\n\t\tthis.totalFreezesDuration = stats.totalFreezesDuration;\n\t\tthis.lastPacketReceivedTimestamp = stats.lastPacketReceivedTimestamp;\n\t\tthis.headerBytesReceived = stats.headerBytesReceived;\n\t\tthis.packetsDiscarded = stats.packetsDiscarded;\n\t\tthis.fecBytesReceived = stats.fecBytesReceived;\n\t\tthis.fecPacketsReceived = stats.fecPacketsReceived;\n\t\tthis.fecPacketsDiscarded = stats.fecPacketsDiscarded;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.nackCount = stats.nackCount;\n\t\tthis.firCount = stats.firCount;\n\t\tthis.pliCount = stats.pliCount;\n\t\tthis.totalProcessingDelay = stats.totalProcessingDelay;\n\t\tthis.estimatedPlayoutTimestamp = stats.estimatedPlayoutTimestamp;\n\t\tthis.jitterBufferDelay = stats.jitterBufferDelay;\n\t\tthis.jitterBufferTargetDelay = stats.jitterBufferTargetDelay;\n\t\tthis.jitterBufferEmittedCount = stats.jitterBufferEmittedCount;\n\t\tthis.jitterBufferMinimumDelay = stats.jitterBufferMinimumDelay;\n\t\tthis.totalSamplesReceived = stats.totalSamplesReceived;\n\t\tthis.concealedSamples = stats.concealedSamples;\n\t\tthis.silentConcealedSamples = stats.silentConcealedSamples;\n\t\tthis.concealmentEvents = stats.concealmentEvents;\n\t\t// Previously reset to `undefined` at the top of update() but never assigned, so `jitter`\n\t\t// was permanently undefined on every inbound RTP.\n\t\tthis.jitter = stats.jitter;\n\t\tthis.framesReceived = stats.framesReceived;\n\t\tthis.retransmittedPacketsReceived = stats.retransmittedPacketsReceived;\n\t\tthis.retransmittedBytesReceived = stats.retransmittedBytesReceived;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { OutboundRtpStats, QualityLimitationDurations } from './schema/ClientSample';\nimport { counterDelta } from './utils/stats';\n\nexport class ObservedOutboundRtp implements OutboundRtpStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsSent?: number | undefined;\n\tbytesSent?: number | undefined;\n\tmid?: string | undefined;\n\tmediaSourceId?: string | undefined;\n\tremoteId?: string | undefined;\n\trid?: string | undefined;\n\theaderBytesSent?: number | undefined;\n\tretransmittedPacketsSent?: number | undefined;\n\tretransmittedBytesSent?: number | undefined;\n\trtxSsrc?: number | undefined;\n\ttargetBitrate?: number | undefined;\n\ttotalEncodedBytesTarget?: number | undefined;\n\tframeWidth?: number | undefined;\n\tframeHeight?: number | undefined;\n\tframesPerSecond?: number | undefined;\n\tframesSent?: number | undefined;\n\thugeFramesSent?: number | undefined;\n\tframesEncoded?: number | undefined;\n\tkeyFramesEncoded?: number | undefined;\n\tqpSum?: number | undefined;\n\ttotalEncodeTime?: number | undefined;\n\ttotalPacketSendDelay?: number | undefined;\n\tqualityLimitationReason?: string | undefined;\n\tqualityLimitationResolutionChanges?: number | undefined;\n\tnackCount?: number | undefined;\n\tfirCount?: number | undefined;\n\tpliCount?: number | undefined;\n\tencoderImplementation?: string | undefined;\n\tpowerEfficientEncoder?: boolean | undefined;\n\tactive?: boolean | undefined;\n\tscalabilityMode?: string | undefined;\n\tqualityLimitationDurations?: QualityLimitationDurations | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\t// derived fields\n\tpublic bitrate = 0;\n\tpublic payloadBitrate = 0;\n\tpublic packetRate = 0;\n\tpublic bitPerPixel = 0;\n\t\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaBytesSent = 0;\n\n\t// Per-tick, counter-reset-safe deltas of the cumulative RTCStats counters.\n\tpublic deltaFramesSent = 0;\n\tpublic deltaFramesEncoded = 0;\n\tpublic deltaKeyFramesEncoded = 0;\n\tpublic deltaNackCount = 0;\n\tpublic deltaPliCount = 0;\n\tpublic deltaFirCount = 0;\n\tpublic deltaRetransmittedPacketsSent = 0;\n\tpublic deltaRetransmittedBytesSent = 0;\n\tpublic deltaEncodeTime = 0;\n\tpublic deltaQualityLimitationResolutionChanges = 0;\n\n\t/**\n\t * `true` when the codec, encoder implementation or scalability mode changed in this tick.\n\t *\n\t * Chrome resets `packetsSent`/`bytesSent` on the SSRC when the codec switches\n\t * (crbug.com/webrtc/5361), producing sawtooth spikes and negative bitrates. All deltas for the\n\t * tick are suppressed so a codec change is never mistaken for a traffic event.\n\t */\n\tpublic counterResetBoundary = false;\n\n\t// Derived from the corresponding remote-inbound-rtp (receiver report), when present.\n\tpublic remoteRttInMs?: number;\n\tpublic remoteFractionLost?: number;\n\tpublic remoteJitter?: number;\n\tpublic remotePacketsLost?: number;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t) {\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\t\n\t\tthis._visited = false;\n\t\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getRemoteInboundRtp() {\n\t\treturn this._peerConnection.observedRemoteInboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic getMediaSource() {\n\t\treturn this._peerConnection.observedMediaSources.get(this.mediaSourceId ?? '');\n\t}\n\n\tpublic getTrack() {\n\t\treturn this.getMediaSource()?.getTrack();\n\t}\n\n\tpublic update(stats: OutboundRtpStats) {\n\t\tthis._visited = true;\n\t\tthis.bitPerPixel = 0;\n\t\tthis.bitrate = 0;\n\t\tthis.payloadBitrate = 0;\n\t\tthis.packetRate = 0;\n\t\tthis.deltaPacketsSent = 0;\n\t\tthis.deltaBytesSent = 0;\n\t\tthis.deltaFramesSent = 0;\n\t\tthis.deltaFramesEncoded = 0;\n\t\tthis.deltaKeyFramesEncoded = 0;\n\t\tthis.deltaNackCount = 0;\n\t\tthis.deltaPliCount = 0;\n\t\tthis.deltaFirCount = 0;\n\t\tthis.deltaRetransmittedPacketsSent = 0;\n\t\tthis.deltaRetransmittedBytesSent = 0;\n\t\tthis.deltaEncodeTime = 0;\n\t\tthis.deltaQualityLimitationResolutionChanges = 0;\n\t\tthis.remoteRttInMs = undefined;\n\t\tthis.remoteFractionLost = undefined;\n\t\tthis.remoteJitter = undefined;\n\t\tthis.remotePacketsLost = undefined;\n\n\t\tconst elapsedTimeInMs = stats.timestamp - this.timestamp;\n\n\t\t// crbug.com/webrtc/5361: the cumulative counters reset on a codec/encoder switch.\n\t\tconst changed = (a?: string, b?: string) => a !== undefined && b !== undefined && a !== b;\n\n\t\tthis.counterResetBoundary = changed(this.codecId, stats.codecId)\n\t\t\t|| changed(this.encoderImplementation, stats.encoderImplementation)\n\t\t\t|| changed(this.scalabilityMode, stats.scalabilityMode);\n\n\t\tif (elapsedTimeInMs && !this.counterResetBoundary) {\n\t\t\t// Guard against counter resets / SSRC reuse: only accept a non-negative delta.\n\t\t\tif (stats.packetsSent !== undefined && this.packetsSent !== undefined && stats.packetsSent >= this.packetsSent) {\n\t\t\t\tthis.deltaPacketsSent = stats.packetsSent - this.packetsSent;\n\t\t\t\tthis.packetRate = this.deltaPacketsSent / (elapsedTimeInMs / 1000);\n\t\t\t}\n\t\t\tif (stats.bytesSent !== undefined && this.bytesSent !== undefined && stats.bytesSent >= this.bytesSent) {\n\t\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t\t\tthis.bitrate = (this.deltaBytesSent * 8) / (elapsedTimeInMs / 1000);\n\t\t\t}\n\t\t\t// NOTE `??` binds looser than `-`, so the previous expression parsed as\n\t\t\t// `deltaBytesSent ?? (0 - headerDelta)` and always yielded `deltaBytesSent` — i.e.\n\t\t\t// payloadBitrate silently equalled bitrate and never subtracted the header bytes.\n\t\t\tconst deltaHeaderBytesSent = counterDelta(this.headerBytesSent, stats.headerBytesSent);\n\n\t\t\tthis.payloadBitrate = (Math.max(0, this.deltaBytesSent - deltaHeaderBytesSent) * 8) / (elapsedTimeInMs / 1000);\n\n\t\t\tthis.deltaFramesSent = counterDelta(this.framesSent, stats.framesSent);\n\t\t\tthis.deltaFramesEncoded = counterDelta(this.framesEncoded, stats.framesEncoded);\n\t\t\tthis.deltaKeyFramesEncoded = counterDelta(this.keyFramesEncoded, stats.keyFramesEncoded);\n\t\t\tthis.deltaNackCount = counterDelta(this.nackCount, stats.nackCount);\n\t\t\tthis.deltaPliCount = counterDelta(this.pliCount, stats.pliCount);\n\t\t\tthis.deltaFirCount = counterDelta(this.firCount, stats.firCount);\n\t\t\tthis.deltaRetransmittedPacketsSent = counterDelta(this.retransmittedPacketsSent, stats.retransmittedPacketsSent);\n\t\t\tthis.deltaRetransmittedBytesSent = counterDelta(this.retransmittedBytesSent, stats.retransmittedBytesSent);\n\t\t\tthis.deltaEncodeTime = counterDelta(this.totalEncodeTime, stats.totalEncodeTime);\n\t\t\tthis.deltaQualityLimitationResolutionChanges = counterDelta(\n\t\t\t\tthis.qualityLimitationResolutionChanges, stats.qualityLimitationResolutionChanges,\n\t\t\t);\n\n\t\t\t// bits per pixel of the frames sent in this tick. (The previous expression subtracted in\n\t\t\t// reverse — `previous - current` — so it was always negative, and divided by frames, not pixels.)\n\t\t\tconst pixels = (stats.frameWidth ?? 0) * (stats.frameHeight ?? 0);\n\n\t\t\tif (0 < pixels && 0 < this.deltaFramesSent) {\n\t\t\t\tthis.bitPerPixel = (this.deltaBytesSent * 8) / (this.deltaFramesSent * pixels);\n\t\t\t}\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.mid = stats.mid;\n\t\tthis.mediaSourceId = stats.mediaSourceId;\n\t\tthis.remoteId = stats.remoteId;\n\t\tthis.rid = stats.rid;\n\t\tthis.headerBytesSent = stats.headerBytesSent;\n\t\tthis.retransmittedPacketsSent = stats.retransmittedPacketsSent;\n\t\tthis.retransmittedBytesSent = stats.retransmittedBytesSent;\n\t\tthis.rtxSsrc = stats.rtxSsrc;\n\t\tthis.targetBitrate = stats.targetBitrate;\n\t\tthis.totalEncodedBytesTarget = stats.totalEncodedBytesTarget;\n\t\tthis.frameWidth = stats.frameWidth;\n\t\tthis.frameHeight = stats.frameHeight;\n\t\tthis.framesPerSecond = stats.framesPerSecond;\n\t\tthis.framesSent = stats.framesSent;\n\t\tthis.hugeFramesSent = stats.hugeFramesSent;\n\t\tthis.framesEncoded = stats.framesEncoded;\n\t\tthis.keyFramesEncoded = stats.keyFramesEncoded;\n\t\tthis.qpSum = stats.qpSum;\n\t\tthis.totalEncodeTime = stats.totalEncodeTime;\n\t\tthis.totalPacketSendDelay = stats.totalPacketSendDelay;\n\t\tthis.qualityLimitationReason = stats.qualityLimitationReason;\n\t\tthis.qualityLimitationResolutionChanges = stats.qualityLimitationResolutionChanges;\n\t\tthis.nackCount = stats.nackCount;\n\t\tthis.firCount = stats.firCount;\n\t\tthis.pliCount = stats.pliCount;\n\t\tthis.encoderImplementation = stats.encoderImplementation;\n\t\tthis.powerEfficientEncoder = stats.powerEfficientEncoder;\n\t\tthis.active = stats.active;\n\t\tthis.scalabilityMode = stats.scalabilityMode;\n\t\tthis.qualityLimitationDurations = stats.qualityLimitationDurations;\n\t\tthis.attachments = stats.attachments;\n\t}\n}","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { CertificateStats } from './schema/ClientSample';\n\nexport class ObservedCertificate implements CertificateStats {\n\tpublic appData?: Record<string, unknown>;\n\n\tprivate _visited = false;\n\n\tfingerprint?: string;\n\tfingerprintAlgorithm?: string;\n\tbase64Certificate?: string;\n\tissuerCertificateId?: string;\n\tattachments?: Record<string, unknown>;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: CertificateStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.fingerprint = stats.fingerprint;\n\t\tthis.fingerprintAlgorithm = stats.fingerprintAlgorithm;\n\t\tthis.base64Certificate = stats.base64Certificate;\n\t\tthis.issuerCertificateId = stats.issuerCertificateId;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { CodecStats } from './schema/ClientSample';\n\nexport class ObservedCodec implements CodecStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tpayloadType?: number | undefined;\n\ttransportId?: string | undefined;\n\tclockRate?: number | undefined;\n\tchannels?: number | undefined;\n\tsdpFmtpLine?: string | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic mimeType: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic update(stats: CodecStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.payloadType = stats.payloadType;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.clockRate = stats.clockRate;\n\t\tthis.channels = stats.channels;\n\t\tthis.sdpFmtpLine = stats.sdpFmtpLine;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { DataChannelStats } from './schema/ClientSample';\n\nexport type ObservedDataChannelState = 'connecting' | 'open' | 'closing' | 'closed';\n\nexport class ObservedDataChannel implements DataChannelStats\t{\n\tprivate _visited = false;\n\t\n\tlabel?: string | undefined;\n\tprotocol?: string | undefined;\n\tdataChannelIdentifier?: number | undefined;\n\tstate?: string | undefined;\n\tmessagesSent?: number | undefined;\n\tbytesSent?: number | undefined;\n\tmessagesReceived?: number | undefined;\n\tbytesReceived?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic addedAt?: number | undefined;\n\tpublic removedAt?: number | undefined;\n\t\n\tpublic deltaBytesSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaMessagesSent = 0;\n\tpublic deltaMessagesReceived = 0;\n\n\tpublic appData?: Record<string, unknown>;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t) {\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\t\n\t\tthis._visited = false;\n\t\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: DataChannelStats) {\n\t\tthis._visited = true;\n\n\t\tif (this.messagesSent && stats.messagesSent && stats.messagesSent >= this.messagesSent) {\n\t\t\tthis.deltaMessagesSent = stats.messagesSent - this.messagesSent;\n\t\t} else {\n\t\t\tthis.deltaMessagesSent = 0;\n\t\t}\n\n\t\tif (this.messagesReceived && stats.messagesReceived && stats.messagesReceived >= this.messagesReceived) {\n\t\t\tthis.deltaMessagesReceived = stats.messagesReceived - this.messagesReceived;\n\t\t} else {\n\t\t\tthis.deltaMessagesReceived = 0;\n\t\t}\n\n\t\tif (this.bytesSent && stats.bytesSent && stats.bytesSent >= this.bytesSent) {\n\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t} else {\n\t\t\tthis.deltaBytesSent = 0;\n\t\t}\n\n\t\tif (this.bytesReceived && stats.bytesReceived && stats.bytesReceived >= this.bytesReceived) {\n\t\t\tthis.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;\n\t\t} else {\n\t\t\tthis.deltaBytesReceived = 0;\n\t\t}\n\n\t\tthis.label = stats.label;\n\t\tthis.protocol = stats.protocol;\n\t\tthis.dataChannelIdentifier = stats.dataChannelIdentifier;\n\t\tthis.state = stats.state;\n\t\tthis.messagesSent = stats.messagesSent;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.messagesReceived = stats.messagesReceived;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { IceCandidateStats } from './schema/ClientSample';\n\nexport class ObservedIceCandidate implements IceCandidateStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\taddress?: string | undefined;\n\tport?: number | undefined;\n\tprotocol?: string | undefined;\n\tcandidateType?: string | undefined;\n\tpriority?: number | undefined;\n\turl?: string | undefined;\n\trelayProtocol?: string | undefined;\n\tfoundation?: string | undefined;\n\trelatedAddress?: string | undefined;\n\trelatedPort?: number | undefined;\n\tusernameFragment?: string | undefined;\n\ttcpType?: string | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic update(stats: IceCandidateStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.address = stats.address;\n\t\tthis.port = stats.port;\n\t\tthis.protocol = stats.protocol;\n\t\tthis.candidateType = stats.candidateType;\n\t\tthis.priority = stats.priority;\n\t\tthis.url = stats.url;\n\t\tthis.relayProtocol = stats.relayProtocol;\n\t\tthis.foundation = stats.foundation;\n\t\tthis.relatedAddress = stats.relatedAddress;\n\t\tthis.relatedPort = stats.relatedPort;\n\t\tthis.usernameFragment = stats.usernameFragment;\n\t\tthis.tcpType = stats.tcpType;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { IceCandidatePairStats } from './schema/ClientSample';\n\nexport class ObservedIceCandidatePair implements IceCandidatePairStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\tlocalCandidateId?: string | undefined;\n\tremoteCandidateId?: string | undefined;\n\tstate?: 'new' | 'in-progress' | 'waiting' | 'failed' | 'succeeded' | undefined;\n\tnominated?: boolean | undefined;\n\tpacketsSent?: number | undefined;\n\tpacketsReceived?: number | undefined;\n\tbytesSent?: number | undefined;\n\tbytesReceived?: number | undefined;\n\tlastPacketSentTimestamp?: number | undefined;\n\tlastPacketReceivedTimestamp?: number | undefined;\n\ttotalRoundTripTime?: number | undefined;\n\tcurrentRoundTripTime?: number | undefined;\n\tavailableOutgoingBitrate?: number | undefined;\n\tavailableIncomingBitrate?: number | undefined;\n\trequestsReceived?: number | undefined;\n\trequestsSent?: number | undefined;\n\tresponsesReceived?: number | undefined;\n\tresponsesSent?: number | undefined;\n\tconsentRequestsSent?: number | undefined;\n\tpacketsDiscardedOnSend?: number | undefined;\n\tbytesDiscardedOnSend?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic deltaBytesSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaPacketsReceived = 0;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t) {\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\t\n\t\tthis._visited = false;\n\t\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getIceTransport() {\n\t\treturn this._peerConnection.observedIceTransports.get(this.transportId ?? '');\n\t}\n\n\tpublic getLocalCandidate() {\n\t\treturn this._peerConnection.observedIceCandidates.get(this.localCandidateId ?? '');\n\t}\n\n\tpublic getRemoteCandidate() {\n\t\treturn this._peerConnection.observedIceCandidates.get(this.remoteCandidateId ?? '');\n\t}\n\n\tpublic update(stats: IceCandidatePairStats) {\n\t\tthis._visited = true;\n\n\t\tif (this.packetsSent && stats.packetsSent && stats.packetsSent >= this.packetsSent) {\n\t\t\tthis.deltaPacketsSent = stats.packetsSent - this.packetsSent;\n\t\t} else {\n\t\t\tthis.deltaPacketsSent = 0;\n\t\t}\n\t\tif (this.packetsReceived && stats.packetsReceived && stats.packetsReceived >= this.packetsReceived) {\n\t\t\tthis.deltaPacketsReceived = stats.packetsReceived - this.packetsReceived;\n\t\t} else {\n\t\t\tthis.deltaPacketsReceived = 0;\n\t\t}\n\t\tif (this.bytesSent && stats.bytesSent && stats.bytesSent >= this.bytesSent) {\n\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t} else {\n\t\t\tthis.deltaBytesSent = 0;\n\t\t}\n\t\tif (this.bytesReceived && stats.bytesReceived && stats.bytesReceived >= this.bytesReceived) {\n\t\t\tthis.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;\n\t\t} else {\n\t\t\tthis.deltaBytesReceived = 0;\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.localCandidateId = stats.localCandidateId;\n\t\tthis.remoteCandidateId = stats.remoteCandidateId;\n\t\tthis.state = this._convertState(stats.state);\n\t\tthis.nominated = stats.nominated;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.lastPacketSentTimestamp = stats.lastPacketSentTimestamp;\n\t\tthis.lastPacketReceivedTimestamp = stats.lastPacketReceivedTimestamp;\n\t\tthis.totalRoundTripTime = stats.totalRoundTripTime;\n\t\tthis.currentRoundTripTime = stats.currentRoundTripTime;\n\t\tthis.availableOutgoingBitrate = stats.availableOutgoingBitrate;\n\t\tthis.availableIncomingBitrate = stats.availableIncomingBitrate;\n\t\tthis.requestsReceived = stats.requestsReceived;\n\t\tthis.requestsSent = stats.requestsSent;\n\t\tthis.responsesReceived = stats.responsesReceived;\n\t\tthis.responsesSent = stats.responsesSent;\n\t\tthis.consentRequestsSent = stats.consentRequestsSent;\n\t\tthis.packetsDiscardedOnSend = stats.packetsDiscardedOnSend;\n\t\tthis.bytesDiscardedOnSend = stats.bytesDiscardedOnSend;\n\t\tthis.attachments = stats.attachments;\n\t}\n\n\tprivate _convertState(state: string | undefined) {\n\t\tswitch (state) {\n\t\t\tcase 'new':\n\t\t\tcase 'in-progress':\n\t\t\tcase 'waiting':\n\t\t\tcase 'failed':\n\t\t\tcase 'succeeded':\n\t\t\t\treturn state;\n\t\t\tcase 'cancelled':\n\t\t\t\treturn 'failed';\n\t\t\tcase 'inprogress':\n\t\t\t\treturn 'in-progress';\n\t\t\tdefault:\n\t\t\t\treturn undefined;\n\t\t}\n\t}\n}","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { IceTransportStats } from './schema/ClientSample';\n\nexport class ObservedIceTransport implements IceTransportStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tpacketsSent?: number | undefined;\n\tpacketsReceived?: number | undefined;\n\tbytesSent?: number | undefined;\n\tbytesReceived?: number | undefined;\n\ticeRole?: string | undefined;\n\ticeLocalUsernameFragment?: string | undefined;\n\tdtlsState?: string | undefined;\n\ticeState?: string | undefined;\n\tselectedCandidatePairId?: string | undefined;\n\tlocalCertificateId?: string | undefined;\n\tremoteCertificateId?: string | undefined;\n\ttlsVersion?: string | undefined;\n\tdtlsCipher?: string | undefined;\n\tdtlsRole?: string | undefined;\n\tsrtpCipher?: string | undefined;\n\tselectedCandidatePairChanges?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic deltaPacketsReceived = 0;\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaBytesSent = 0;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getSelectedCandidatePair() {\n\t\treturn this._peerConnection.observedIceCandidatesPair.get(this.selectedCandidatePairId ?? '');\n\t}\n\n\tpublic update(stats: IceTransportStats) {\n\t\tthis._visited = true;\n\n\t\tif (this.bytesReceived !== undefined && stats.bytesReceived !== undefined && this.bytesReceived <= stats.bytesReceived) {\n\t\t\tthis.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;\n\t\t} else {\n\t\t\tthis.deltaBytesReceived = 0;\n\t\t}\n\t\t\n\t\tif (this.bytesSent !== undefined && stats.bytesSent !== undefined && this.bytesSent <= stats.bytesSent) {\n\t\t\tthis.deltaBytesSent = stats.bytesSent - this.bytesSent;\n\t\t} else {\n\t\t\tthis.deltaBytesSent = 0;\n\t\t}\n\n\t\tif (this.packetsReceived !== undefined && stats.packetsReceived !== undefined && this.packetsReceived <= stats.packetsReceived) {\n\t\t\tthis.deltaPacketsReceived = stats.packetsReceived - this.packetsReceived;\n\t\t} else {\n\t\t\tthis.deltaPacketsReceived = 0;\n\t\t}\n\t\t\n\t\tif (this.packetsSent !== undefined && stats.packetsSent !== undefined && this.packetsSent <= stats.packetsSent) {\n\t\t\tthis.deltaPacketsSent = stats.packetsSent - this.packetsSent;\n\t\t} else {\n\t\t\tthis.deltaPacketsSent = 0;\n\t\t}\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.bytesReceived = stats.bytesReceived;\n\t\tthis.iceRole = stats.iceRole;\n\t\tthis.iceLocalUsernameFragment = stats.iceLocalUsernameFragment;\n\t\tthis.dtlsState = stats.dtlsState;\n\t\tthis.iceState = stats.iceState;\n\t\tthis.selectedCandidatePairId = stats.selectedCandidatePairId;\n\t\tthis.localCertificateId = stats.localCertificateId;\n\t\tthis.remoteCertificateId = stats.remoteCertificateId;\n\t\tthis.tlsVersion = stats.tlsVersion;\n\t\tthis.dtlsCipher = stats.dtlsCipher;\n\t\tthis.dtlsRole = stats.dtlsRole;\n\t\tthis.srtpCipher = stats.srtpCipher;\n\t\tthis.selectedCandidatePairChanges = stats.selectedCandidatePairChanges;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { MediaSourceStats } from './schema/ClientSample';\n\nexport class ObservedMediaSource implements MediaSourceStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttrackIdentifier?: string | undefined;\n\taudioLevel?: number | undefined;\n\ttotalAudioEnergy?: number | undefined;\n\ttotalSamplesDuration?: number | undefined;\n\techoReturnLoss?: number | undefined;\n\techoReturnLossEnhancement?: number | undefined;\n\twidth?: number | undefined;\n\theight?: number | undefined;\n\tframes?: number | undefined;\n\tframesPerSecond?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getTrack() {\n\t\treturn this._peerConnection.observedOutboundTracks.get(this.trackIdentifier ?? '');\n\t}\n\n\tpublic update(stats: MediaSourceStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.trackIdentifier = stats.trackIdentifier;\n\t\tthis.audioLevel = stats.audioLevel;\n\t\tthis.totalAudioEnergy = stats.totalAudioEnergy;\n\t\tthis.totalSamplesDuration = stats.totalSamplesDuration;\n\t\tthis.echoReturnLoss = stats.echoReturnLoss;\n\t\tthis.echoReturnLossEnhancement = stats.echoReturnLossEnhancement;\n\t\tthis.width = stats.width;\n\t\tthis.height = stats.height;\n\t\tthis.frames = stats.frames;\n\t\tthis.framesPerSecond = stats.framesPerSecond;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { PeerConnectionTransportStats } from './schema/ClientSample';\n\nexport class ObservedPeerConnectionTransport implements PeerConnectionTransportStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tdataChannelsOpened?: number | undefined;\n\tdataChannelsClosed?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: PeerConnectionTransportStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.dataChannelsOpened = stats.dataChannelsOpened;\n\t\tthis.dataChannelsClosed = stats.dataChannelsClosed;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { MediaPlayoutStats } from './schema/ClientSample';\n\nexport class ObservedMediaPlayout implements MediaPlayoutStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tsynthesizedSamplesDuration?: number | undefined;\n\tsynthesizedSamplesEvents?: number | undefined;\n\ttotalSamplesDuration?: number | undefined;\n\ttotalPlayoutDelay?: number | undefined;\n\ttotalSamplesCount?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic update(stats: MediaPlayoutStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.synthesizedSamplesDuration = stats.synthesizedSamplesDuration;\n\t\tthis.synthesizedSamplesEvents = stats.synthesizedSamplesEvents;\n\t\tthis.totalSamplesDuration = stats.totalSamplesDuration;\n\t\tthis.totalPlayoutDelay = stats.totalPlayoutDelay;\n\t\tthis.totalSamplesCount = stats.totalSamplesCount;\n\t\tthis.attachments = stats.attachments;\n\t\t\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { RemoteInboundRtpStats } from './schema/ClientSample';\n\nexport class ObservedRemoteInboundRtp implements RemoteInboundRtpStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsReceived?: number | undefined;\n\tpacketsLost?: number | undefined;\n\tjitter?: number | undefined;\n\tlocalId?: string | undefined;\n\troundTripTime?: number | undefined;\n\ttotalRoundTripTime?: number | undefined;\n\tfractionLost?: number | undefined;\n\troundTripTimeMeasurements?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getOutboundRtp() {\n\t\treturn this._peerConnection.observedOutboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic update(stats: RemoteInboundRtpStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsReceived = stats.packetsReceived;\n\t\tthis.packetsLost = stats.packetsLost;\n\t\tthis.jitter = stats.jitter;\n\t\tthis.localId = stats.localId;\n\t\tthis.roundTripTime = stats.roundTripTime;\n\t\tthis.totalRoundTripTime = stats.totalRoundTripTime;\n\t\tthis.fractionLost = stats.fractionLost;\n\t\tthis.roundTripTimeMeasurements = stats.roundTripTimeMeasurements;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { MediaKind } from './common/types';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { RemoteOutboundRtpStats } from './schema/ClientSample';\n\nexport class ObservedRemoteOutboundRtp implements RemoteOutboundRtpStats {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\ttransportId?: string | undefined;\n\tcodecId?: string | undefined;\n\tpacketsSent?: number | undefined;\n\tbytesSent?: number | undefined;\n\tlocalId?: string | undefined;\n\tremoteTimestamp?: number | undefined;\n\treportsSent?: number | undefined;\n\troundTripTime?: number | undefined;\n\ttotalRoundTripTime?: number | undefined;\n\troundTripTimeMeasurements?: number | undefined;\n\tattachments?: Record<string, unknown> | undefined;\n\n\tpublic constructor(\n\t\tpublic timestamp: number,\n\t\tpublic id: string,\n\t\tpublic ssrc: number,\n\t\tpublic kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection\n\t) {}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getInboundRtp() {\n\t\treturn this._peerConnection.observedInboundRtps.get(this.ssrc);\n\t}\n\n\tpublic getCodec() {\n\t\treturn this._peerConnection.observedCodecs.get(this.codecId ?? '');\n\t}\n\n\tpublic update(stats: RemoteOutboundRtpStats) {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.transportId = stats.transportId;\n\t\tthis.codecId = stats.codecId;\n\t\tthis.packetsSent = stats.packetsSent;\n\t\tthis.bytesSent = stats.bytesSent;\n\t\tthis.localId = stats.localId;\n\t\tthis.remoteTimestamp = stats.remoteTimestamp;\n\t\tthis.reportsSent = stats.reportsSent;\n\t\tthis.roundTripTime = stats.roundTripTime;\n\t\tthis.totalRoundTripTime = stats.totalRoundTripTime;\n\t\tthis.roundTripTimeMeasurements = stats.roundTripTimeMeasurements;\n\t\tthis.attachments = stats.attachments;\n\t}\n}\n","import { CalculatedScore } from './scores/CalculatedScore';\nimport { MediaKind } from './common/types';\nimport { InboundTrackSample } from './schema/ClientSample';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedInboundRtp } from './ObservedInboundRtp';\nimport { ObservedMediaPlayout } from './ObservedMediaPlayout';\nimport { ObservedOutboundTrack } from './ObservedOutboundTrack';\n\nexport class ObservedInboundTrack implements InboundTrackSample {\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\tpublic appData?: Record<string, unknown>;\n\tpublic remoteOutboundTrack?: ObservedOutboundTrack | undefined;\n\n\tprivate _visited = false;\n\n\tpublic addedAt?: number | undefined;\n\tpublic removedAt?: number | undefined;\n\n\tpublic muted?: boolean;\n\n\tattachments?: Record<string, unknown> | undefined;\n\n\tconstructor(\n\t\tpublic timestamp: number,\n\t\tpublic readonly id: string,\n\t\tpublic readonly kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t\tprivate readonly _inboundRtp?: ObservedInboundRtp,\n\t\tprivate readonly _mediaPlayout?: ObservedMediaPlayout,\n\t) {\n\t\t// no-op\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getInboundRtp() {\n\t\treturn this._inboundRtp;\n\t}\n\n\tpublic getMediaPlayout() {\n\t\treturn this._mediaPlayout;\n\t}\n\n\tpublic update(stats: InboundTrackSample): void {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.calculatedScore.value = stats.score;\n\t\tthis.attachments = stats.attachments;\n\t}\n}","import { CalculatedScore } from './scores/CalculatedScore';\nimport { MediaKind } from './common/types';\nimport { OutboundTrackSample } from './schema/ClientSample';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedOutboundRtp } from './ObservedOutboundRtp';\nimport { ObservedMediaSource } from './ObservedMediaSource';\nimport { ObservedInboundTrack } from './ObservedInboundTrack';\n\nexport class ObservedOutboundTrack implements OutboundTrackSample {\n\tprivate _visited = false;\n\tpublic appData?: Record<string, unknown>;\n\n\tpublic readonly remoteInboundTracks = new Set<ObservedInboundTrack>();\n\tpublic readonly calculatedScore: CalculatedScore = {\n\t\tweight: 1,\n\t\tvalue: undefined,\n\t};\n\n\tpublic addedAt?: number | undefined;\n\tpublic removedAt?: number | undefined;\n\n\tpublic muted?: boolean;\n\n\tattachments?: Record<string, unknown> | undefined;\n\n\tconstructor(\n\t\tpublic timestamp: number,\n\t\tpublic readonly id: string,\n\t\tpublic readonly kind: MediaKind,\n\t\tprivate readonly _peerConnection: ObservedPeerConnection,\n\t\tprivate readonly _outboundRtps?: ObservedOutboundRtp[],\n\t\tprivate readonly _mediaSource?: ObservedMediaSource,\n\t) {\n\t\t// no-op\n\t}\n\n\tpublic get score() {\n\t\treturn this.calculatedScore.value;\n\t}\n\n\tpublic get visited() {\n\t\tconst visited = this._visited;\n\n\t\tthis._visited = false;\n\n\t\treturn visited;\n\t}\n\n\tpublic getPeerConnection() {\n\t\treturn this._peerConnection;\n\t}\n\n\tpublic getOutboundRtps() {\n\t\treturn this._outboundRtps;\n\t}\n\n\tpublic getMediaSource() {\n\t\treturn this._mediaSource;\n\t}\n\n\tpublic update(stats: OutboundTrackSample): void {\n\t\tthis._visited = true;\n\n\t\tthis.timestamp = stats.timestamp;\n\t\tthis.calculatedScore.value = stats.score;\n\t\tthis.attachments = stats.attachments;\n\t}\n}","export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\nexport type Writable<T> = T extends object ? { -readonly [K in keyof T]: Writable<T[K]> } : T;\n\nexport function iteratorConverter<T>(generator: Generator<T, void, undefined>): IterableIterator<T> {\n\treturn {\n\t\t[Symbol.iterator](): IterableIterator<T> {\n\t\t\treturn this;\n\t\t},\n\t\tnext(): IteratorResult<T> {\n\t\t\treturn generator.next();\n\t\t},\n\t};\n}\n\nexport function asyncIteratorConverter<T>(generator: AsyncGenerator<T, void, undefined>): AsyncIterableIterator<T> {\n\treturn {\n\t\t[Symbol.asyncIterator](): AsyncIterableIterator<T> {\n\t\t\treturn this;\n\t\t},\n\t\tnext(): Promise<IteratorResult<T>> {\n\t\t\treturn generator.next();\n\t\t},\n\t};\n}\n\nexport function isValidUuid(str: string): boolean {\n\tconst regexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n\treturn regexp.test(str);\n}\n\nexport function getAverage(arr: number[], defaultAvgIfArrLengthIs0 = 0): number {\n\tif (arr.length === 0) return defaultAvgIfArrLengthIs0;\n\t\n\treturn arr.reduce((a, b) => a + b, 0) / arr.length;\n}\n\nexport function getMedian(arr: number[], copyArrayForSorting = true): number {\n\t// Sort the array in ascending order\n\tconst sortedArr = copyArrayForSorting \n\t\t? arr.slice().sort((a, b) => a - b)\n\t\t: arr.sort((a, b) => a-b)\n\n\t;\n\n\t// Calculate the middle index\n\tconst mid = Math.floor(sortedArr.length / 2);\n\n\t// If the array length is odd, return the middle element\n\tif (sortedArr.length % 2 !== 0) {\n\t\treturn sortedArr[mid];\n\t}\n\n\t// If the array length is even, return the average of the two middle elements\n\treturn (sortedArr[mid - 1] + sortedArr[mid]) / 2;\n}\n\nexport function parseJsonAs<T>(json?: string): T | undefined {\n\tif (!json) {\n\t\treturn undefined;\n\t}\n\t\n\ttry {\n\t\treturn JSON.parse(json) as T;\n\t} catch (error) {\n\t\treturn undefined;\n\t}\n}","/* eslint-disable no-shadow */\n\nexport enum ClientEventTypes {\n\tCLIENT_JOINED = 'CLIENT_JOINED',\n\tCLIENT_LEFT = 'CLIENT_LEFT',\n\tPEER_CONNECTION_OPENED = 'PEER_CONNECTION_OPENED',\n\tPEER_CONNECTION_CLOSED = 'PEER_CONNECTION_CLOSED',\n\tMEDIA_TRACK_ADDED = 'MEDIA_TRACK_ADDED',\n\tMEDIA_TRACK_REMOVED = 'MEDIA_TRACK_REMOVED',\n\tMEDIA_TRACK_RESUMED = 'MEDIA_TRACK_RESUMED',\n\tMEDIA_TRACK_MUTED = 'MEDIA_TRACK_MUTED',\n\tMEDIA_TRACK_UNMUTED = 'MEDIA_TRACK_UNMUTED',\n\tICE_GATHERING_STATE_CHANGED = 'ICE_GATHERING_STATE_CHANGED',\n\tPEER_CONNECTION_STATE_CHANGED = 'PEER_CONNECTION_STATE_CHANGED',\n\tICE_CONNECTION_STATE_CHANGED = 'ICE_CONNECTION_STATE_CHANGED',\n\tDATA_CHANNEL_OPEN = 'DATA_CHANNEL_OPEN',\n\tDATA_CHANNEL_CLOSED = 'DATA_CHANNEL_CLOSED',\n\tDATA_CHANNEL_ERROR = 'DATA_CHANNEL_ERROR',\n\tNEGOTIATION_NEEDED = 'NEGOTIATION_NEEDED',\n\tSIGNALING_STATE_CHANGE = 'SIGNALING_STATE_CHANGE',\n\t// ICE_GATHERING_STATE_CHANGE = 'ICE_GATHERING_STATE_CHANGE',\n\t// ICE_CONNECTION_STATE_CHANGE = 'ICE_CONNECTION_STATE_CHANGE',\n\tICE_CANDIDATE = 'ICE_CANDIDATE',\n\tICE_CANDIDATE_ERROR = 'ICE_CANDIDATE_ERROR',\n\t\n\t// mediasoup events\n\tPRODUCER_ADDED = 'PRODUCER_ADDED',\n\tPRODUCER_REMOVED = 'PRODUCER_REMOVED',\n\tPRODUCER_PAUSED = 'PRODUCER_PAUSED',\n\tPRODUCER_RESUMED = 'PRODUCER_RESUMED',\n\tCONSUMER_ADDED = 'CONSUMER_ADDED',\n\tCONSUMER_REMOVED = 'CONSUMER_REMOVED',\n\tCONSUMER_PAUSED = 'CONSUMER_PAUSED',\n\tCONSUMER_RESUMED = 'CONSUMER_RESUMED',\n\tDATA_PRODUCER_CREATED = 'DATA_PRODUCER_CREATED',\n\tDATA_PRODUCER_CLOSED = 'DATA_PRODUCER_CLOSED',\n\tDATA_CONSUMER_CREATED = 'DATA_CONSUMER_CREATED',\n\tDATA_CONSUMER_CLOSED = 'DATA_CONSUMER_CLOSED',\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface ClientJoinedEventPayload extends Record<string, unknown> {\n\t// empty\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface ClientLeftEventPayload extends Record<string, unknown> {\n}\n\nexport interface PeerConnectionOpenedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeConnectionState?: string;\n\ticeGatheringState?: string;\n\tsignalingState?: string;\n}\n\nexport interface PeerConnectionClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeConnectionState?: string;\n\ticeGatheringState?: string;\n\tsignalingState?: string;\n}\n\nexport interface MediaTrackAddedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n\tconstraints: MediaTrackConstraints,\n\tcapabilities: MediaTrackCapabilities,\n\tsettings: MediaTrackSettings,\n}\n\nexport interface MediaTrackRemovedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n}\n\nexport interface MediaTrackMutedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n}\n\nexport interface MediaTrackUnmutedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ttrackId: string;\n\tkind: 'audio' | 'video';\n\tlabel?: string;\n\tmuted: boolean;\n\tenabled: boolean;\n\treadyState: string;\n\tcontentHint?: string;\n}\n\nexport interface IceGatheringStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeGatheringState: string;\n}\n\nexport interface PeerConnectionStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tconnectionState: string;\n}\n\nexport interface IceConnectionStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\ticeConnectionState: string;\n}\n\nexport interface DataChannelErrorEventPayload extends Record<string, unknown> {\n\tlabel: string;\n\tpeerConnectionId: string;\n\treadyState: string;\n\tdataChannelId: string | number | null,\n\terror: string | null,\n}\n\nexport interface DataChannelOpenEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tlabel: string;\n\treadyState: string;\n\tdataChannelId: string | number | null,\n}\n\nexport interface DataChannelClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tlabel: string;\n\treadyState: string;\n\tdataChannelId: string | number | null,\n}\n\nexport interface NegotiationNeededEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n}\n\nexport interface IceCandidateEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/address) */\n\taddress?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/candidate) */\n\tcandidate?: string;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/component) */\n\tcomponent?: RTCIceComponent | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/foundation) */\n\tfoundation?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/port) */\n\tport?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/priority) */\n\tpriority?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/protocol) */\n\tprotocol?: RTCIceProtocol | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/relatedAddress) */\n\trelatedAddress?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/relatedPort) */\n\trelatedPort?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/sdpMLineIndex) */\n\tsdpMLineIndex?: number | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/sdpMid) */\n\tsdpMid?: string | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/tcpType) */\n\ttcpType?: RTCIceTcpCandidateType | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/type) */\n\ttype?: RTCIceCandidateType | null;\n\n\t/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/RTCIceCandidate/usernameFragment) */\n\tusernameFragment?: string | null;\n}\n\nexport interface IceCandidateErrorEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\terrorCode?: number;\n\terrorText?: string;\n\taddress?: string | null;\n\tport?: number | null;\n\turl?: string | null;\n}\n\nexport interface SignalingStateChangedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tsignalingState: string;\n}\n\nexport interface ProducerAddedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ProducerRemovedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ProducerPausedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ProducerResumedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n}\n\nexport interface ConsumerAddedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface ConsumerRemovedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface ConsumerPausedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface ConsumerResumedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tproducerId: string;\n\tconsumerId: string;\n\ttrackId: string;\n}\n\nexport interface DataProducerCreatedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n}\n\nexport interface DataProducerClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n}\n\nexport interface DataConsumerCreatedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n\tdataConsumerId: string;\n}\n\nexport interface DataConsumerClosedEventPayload extends Record<string, unknown> {\n\tpeerConnectionId: string;\n\tdataProducerId: string;\n\tdataConsumerId: string;\n}","/* eslint-disable no-shadow */\n\nexport enum ClientMetaTypes {\n\tMEDIA_CONSTRAINT = 'MEDIA_CONSTRAINT',\n\tMEDIA_DEVICE = 'MEDIA_DEVICE',\n\tMEDIA_DEVICES_SUPPORTED_CONSTRAINTS = 'MEDIA_DEVICES_SUPPORTED_CONSTRAINTS',\n\tUSER_MEDIA_ERROR = 'USER_MEDIA_ERROR',\n\tLOCAL_SDP = 'LOCAL_SDP',\n\n\tOPERATION_SYSTEM = 'OPERATION_SYSTEM',\n\tENGINE = 'ENGINE',\n\tPLATFORM = 'PLATFORM',\n\tBROWSER = 'BROWSER',\n}\n\nexport type MediaDeviceInfo = {\n\tdeviceId: string;\n\tlabel: string;\n\tkind: string;\n\tgroupId: string;\n}\n\nexport type Browser = {\n\tname: string;\n\tversion: string;\n}\n\nexport type Platform = {\n\tname: string;\n\tversion: string;\n}\n\nexport type Engine = {\n\tname: string;\n\tversion: string;\n}\n\nexport type OperationSystem = {\n\tname: string;\n\tversion: string;\n}","import type { ClientIssue } from '../schema/ClientSample';\n\n/** The suffix client-monitor-js appends to the type of a resolution entry. */\nexport const RESOLVED_ISSUE_SUFFIX = '-resolved';\n\n/**\n * A **stateful** client issue the server currently believes to be open.\n *\n * client-monitor-js (>= 4.6.0, `sendResolvedIssuesToServer`) puts an issue's whole lifecycle on the\n * wire as two entries sharing a `key`:\n *\n * ```\n * raise: { type: 'stuck-decoder', key, payload, timestamp: raisedAt }\n * resolution: { type: 'stuck-decoder-resolved', key, payload: { raisedAt, comment, …final }, timestamp: resolvedAt }\n * ```\n *\n * The observer opens an `ActiveClientIssue` on the raise and closes it on the matching key, which\n * turns a stream of point-in-time symptom reports into **intervals**. That is what makes the\n * difference between \"several clients reported congestion in the last 10 seconds\" (a guess built on\n * an arbitrary window) and \"several clients are congested *right now, simultaneously*\" — the latter\n * being real evidence of a shared cause.\n *\n * Issues still active when the client monitor closes are auto-resolved by the client, so a clean\n * departure does not leak. An unclean one (crash, network death) can, which is why the registry\n * also expires entries — see `IssueRegistry`.\n */\nexport type ActiveClientIssue = {\n\n\t/** Identity shared by the raise and its resolution. Unique per client. */\n\tkey: string;\n\n\t/** The issue type **without** the `-resolved` suffix (e.g. `'congestion'`). */\n\ttype: string;\n\n\t/** The client that reported it. */\n\tclientId: string;\n\n\t/** When the client raised it (client clock). */\n\traisedAt: number;\n\n\t/** When the observer first saw it (server clock) — skew-free, use this for cross-client timing. */\n\tobservedAt: number;\n\n\t/** Parsed raise payload, when it was JSON. */\n\tpayload?: Record<string, unknown>;\n\n\t/** `payload.peerConnectionId`, when present — most client detectors report it. */\n\tpeerConnectionId?: string;\n\n\t/** `payload.trackId`, when present — the join key to a track (and thus to a publisher). */\n\ttrackId?: string;\n};\n\n/** A closed interval: an {@link ActiveClientIssue} plus how it ended. */\nexport type ResolvedClientIssue = ActiveClientIssue & {\n\n\t/** When the client resolved it (client clock). */\n\tresolvedAt: number;\n\n\t/** Observer-clock resolution time. */\n\tobservedResolvedAt: number;\n\n\t/** `resolvedAt - raisedAt` as reported by the client, else derived from observer clocks. */\n\tdurationInMs: number;\n\n\t/** Free-form note passed to `resolveIssue`. */\n\tcomment?: string;\n\n\t/** Payload explicitly passed at resolution (the built-in detectors pass their final payload). */\n\tresolutionPayload?: Record<string, unknown>;\n\n\t/**\n\t * How the interval ended: the client said so, the observer expired it, or the client left\n\t * without resolving.\n\t */\n\tresolvedBy: 'client' | 'timeout' | 'client-closed';\n};\n\n/** `true` when the entry is a resolution companion rather than a raise. */\nexport function isResolutionEntry(issue: ClientIssue): boolean {\n\treturn issue.type.endsWith(RESOLVED_ISSUE_SUFFIX);\n}\n\n/** Strip the `-resolved` suffix, so both entries of a lifecycle share one logical type. */\nexport function baseIssueType(type: string): string {\n\treturn type.endsWith(RESOLVED_ISSUE_SUFFIX) ? type.slice(0, -RESOLVED_ISSUE_SUFFIX.length) : type;\n}\n\n/** Best-effort parse of the JSON-string payload the schema carries. */\nexport function parseIssuePayload(payload?: string): Record<string, unknown> | undefined {\n\tif (!payload) return undefined;\n\n\ttry {\n\t\tconst parsed = JSON.parse(payload);\n\n\t\treturn parsed && typeof parsed === 'object' ? parsed as Record<string, unknown> : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n","import { ObservedCall } from '../ObservedCall';\n\nexport class DefaultCallScoreCalculator {\n\n\tpublic constructor(\n\t\tpublic readonly observedCall: ObservedCall,\n\t) {\n\t}\n\n\tpublic update() {\n\t\tlet totalScore = 0;\n\t\tlet totalWeight = 0;\n\n\t\tfor (const client of this.observedCall.observedClients.values()) {\n\t\t\tif (client.score === undefined) continue;\n\n\t\t\ttotalScore += client.score * client.calculatedScore.weight;\n\t\t\ttotalWeight += client.calculatedScore.weight;\n\t\t}\n\n\t\tthis.observedCall.calculatedScore.value = totalWeight ? totalScore / totalWeight : undefined;\n\t}\n}","import { ObservedCall } from '../ObservedCall';\nimport { ObservedClient, ObservedClientEvents } from '../ObservedClient';\nimport type { AcceptContext } from '../Observer';\nimport { Updater } from './Updater';\n \nexport class OnAllClientCallUpdater implements Updater {\n\treadonly name = 'OnAllClientCallUpdater';\n\treadonly description = 'Call the update() method of the ObservedCall once all client has been updated';\n\n\tprivate readonly _updatedClients = new Set<string>();\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate _observedCall: ObservedCall\n\t) {\n\t\tthis._onNewObservedClient = this._onNewObservedClient.bind(this);\n\n\t\tthis._observedCall.once('close', () => {\n\t\t\tthis._observedCall.off('newclient', this._onNewObservedClient);\n\t\t});\n\t\tthis._observedCall.on('newclient', this._onNewObservedClient);\n\t}\n\t\n\tpublic close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\t// do nothing, as close once emitted unsubscription happened\n\t\tthis._updatedClients.clear();\n\t}\n\n\tprivate _onNewObservedClient(observedClient: ObservedClient) {\n\t\tif (this.closed) return;\n\t\t\n\t\tconst onUpdate = (...args: ObservedClientEvents['update']) => this._onClientUpdate(observedClient, args[2]);\n\n\t\tobservedClient.once('close', () => {\n\t\t\tobservedClient.off('update', onUpdate);\n\t\t\tthis._updatedClients.delete(observedClient.clientId);\n\t\t\tthis._updateIfEveryClientUpdated();\n\t\t});\n\t\tobservedClient.on('update', onUpdate);\n\t}\n\n\tprivate _onClientUpdate(observedClient: ObservedClient, context?: AcceptContext) {\n\t\tif (observedClient.closed) return;\n\n\t\tthis._updatedClients.add(observedClient.clientId);\n\t\tthis._updateIfEveryClientUpdated(context);\n\t}\n\n\tprivate _updateIfEveryClientUpdated(context?: AcceptContext) {\n\t\tif (this._updatedClients.size < this._observedCall.observedClients.size) {\n\t\t\treturn;\n\t\t} else if (this.closed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._updatedClients.clear();\n\t\tthis._observedCall.update(context);\n\t}\n\n}\t","import { ObservedCall } from '../ObservedCall';\nimport { ObservedClient, ObservedClientEvents } from '../ObservedClient';\nimport { Updater } from './Updater';\n \nexport class OnAnyClientCallUpdater implements Updater {\n\treadonly name = 'OnAnyClientCallUpdater';\n\treadonly description = 'Call the update() method of the ObservedCall when any of the client has been updated';\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate _observedCall: ObservedCall\n\t) {\n\t\tthis._onNewObservedClient = this._onNewObservedClient.bind(this);\n\n\t\tthis._observedCall.once('close', () => {\n\t\t\tthis._observedCall.off('newclient', this._onNewObservedClient);\n\t\t});\n\t\tthis._observedCall.on('newclient', this._onNewObservedClient);\n\t}\n\t\n\tpublic close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t}\n\n\tprivate _onNewObservedClient(observedClient: ObservedClient) {\n\t\tif (this.closed) return;\n\t\t\n\t\tconst onUpdate = (...args: ObservedClientEvents['update']) => {\n\t\t\tif (this.closed) return;\n\t\t\tthis._observedCall.update(args[2]);\n\t\t};\n\n\t\tobservedClient.once('close', () => {\n\t\t\tobservedClient.off('update', onUpdate);\n\t\t});\n\t\tobservedClient.on('update', onUpdate);\n\t}\n}","import { createLogger } from '../common/logger';\nimport { Detector } from './Detector';\n\nconst logger = createLogger('Detectors');\n\nexport class Detectors {\n\tprivate _detectors: Detector[];\n\n\tpublic constructor(...detectors: Detector[]) {\n\t\tthis._detectors = detectors;\n\t}\n\n\tpublic get listOfNames() {\n\t\treturn this._detectors.map((d) => d.name);\n\t}\n\n\tpublic add(detector: Detector) {\n\t\tthis._detectors.push(detector);\n\t}\n\n\tpublic remove(detector: Detector) {\n\t\tthis._detectors = this._detectors.filter((d) => d !== detector);\n\t\tthis._close(detector);\n\t}\n\n\tpublic update() {\n\t\tfor (const detector of this._detectors) {\n\t\t\ttry {\n\t\t\t\tdetector.update();\n\t\t\t} catch (err) {\n\t\t\t\tlogger.warn(`Error updating detector ${detector?.name}`, err);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic clear() {\n\t\tconst detectors = this._detectors;\n\n\t\tthis._detectors = [];\n\t\tfor (const detector of detectors) this._close(detector);\n\t}\n\n\tprivate _close(detector: Detector) {\n\t\ttry {\n\t\t\tdetector.close?.();\n\t\t} catch (err) {\n\t\t\tlogger.warn(`Error closing detector ${detector?.name}`, err);\n\t\t}\n\t}\n}\n","import { createLogger } from './common/logger';\nimport { ObservedCall, ObservedCallSettings } from './ObservedCall';\nimport { EventEmitter } from 'events';\nimport { ClientSample } from './schema/ClientSample';\nimport { ObservedTURN } from './ObservedTURN';\nimport { Updater } from './updaters/Updater';\nimport { OnAllCallObserverUpdater } from './updaters/OnAllCallObserverUpdater';\nimport { OnAnyCallObserverUpdater } from './updaters/OnAnyCallObserverUpdater';\nimport type { RemoteTrackResolverFactory } from './utils/RemoteTrackResolver';\nimport type { ObserverEvents, ObserverEventBase, ObservedMediasoupRouterScope } from './ObserverEvents';\nimport type { ClientSampleSinkFactory } from './sinks/ClientSampleSink';\nimport { Middleware, MiddlewareProcessor } from './common/Middleware';\nimport { ObservedMediasoupRouter, ObservedMediasoupRouterSettings } from './ObservedMediasoupRouter';\nimport { Detectors } from './detectors/Detectors';\nimport type { ClientIssue } from './schema/ClientSample';\n\nconst logger = createLogger('Observer');\n\nexport type SampleRejectedReason = 'observer-closed' | 'missing-callId' | 'missing-clientId';\n\nexport type { ObserverEvents } from './ObserverEvents';\n\n/**\n * Optional, free-form context supplied to `accept()`. A single context object is\n * threaded down the accept chain (Observer -> Client -> PeerConnection) and is\n * merged into the `appData` of entities created during the accept pass.\n */\nexport type AcceptContext = Record<string, unknown>;\n\n/** The payload threaded through `accept()` middlewares: the sample and its optional context. */\nexport type AcceptMiddlewarePayload = {\n\tsample: ClientSample,\n\tcontext?: AcceptContext,\n};\n\n/**\n * A global middleware run on every sample passed to `observer.accept()`, in registration order,\n * **before** the sample is dispatched to any call/client. It may inspect or mutate the sample\n * (e.g. set/normalize `callId`/`clientId`, enrich, redact) or the context, then call\n * `next(payload)` to continue the chain. Not calling `next` **drops** the sample.\n */\nexport type AcceptMiddleware = Middleware<AcceptMiddlewarePayload>;\n\n// Updates are event-driven: triggered when any/all calls have updated. `'none'` disables the\n// automatic trigger entirely — the application must call `observer.update()` itself.\n// (Apps wanting a fixed cadence can call `observer.update()` on their own timer.)\ntype ObserverUpdateConfig = {\n\tupdatePolicy?: 'update-on-any-call-updated' | 'update-when-all-call-updated' | 'none',\n};\n\n/** Produces the initial `appData` for a call created without an explicit `appData`. */\nexport type CallAppDataFactory = (params: { callId: string, observer: Observer }) => Record<string, unknown>;\n\n/** Produces the initial `appData` for a client created without an explicit `appData`. */\nexport type ClientAppDataFactory = (params: { clientId: string, observedCall: ObservedCall }) => Record<string, unknown>;\n\nexport type ObserverConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = ObserverUpdateConfig & {\n\tdefaultCallUpdatePolicy?: ObservedCallSettings['updatePolicy'],\n\tappData?: AppData,\n\tcloseClientIfIdleForMs?: number,\n\tcloseCallIfEmptyForMs?: number,\n\n\t/**\n\t * Optional factory invoked when a call is created without an explicit `appData`\n\t * (e.g. lazily by `accept()`), so apps can enrich appData without pre-creating the\n\t * entity. `appData` is application-owned; it is never modified by the `accept()` context.\n\t */\n\tcreateCallAppData?: CallAppDataFactory,\n\n\t/** Same as `createCallAppData`, for clients. Receives the (already-created) parent call. */\n\tcreateClientAppData?: ClientAppDataFactory,\n\n\t/**\n\t * Optional factory invoked when a client is created, producing a per-client sink that\n\t * receives every sample the client accepts (or `undefined` for no sink). The destination\n\t * can be derived from `callId` / `clientId`.\n\t */\n\tcreateClientSink?: ClientSampleSinkFactory,\n\n\t/**\n\t * Optional factory invoked when a call is created, producing the call's `RemoteTrackResolver`\n\t * (or `undefined` for none). Use the built-ins\n\t * (`createDefaultMediasoupRemoteTrackResolverFactory()` / `createP2pRemoteTrackResolverFactory()`)\n\t * or build a `RemoteTrackResolver` with custom publisher/subscriber id resolvers.\n\t */\n\tcreateRemoteTrackResolver?: RemoteTrackResolverFactory,\n}\n\nexport declare interface Observer {\n\ton<U extends keyof ObserverEvents>(event: U, listener: (...args: ObserverEvents[U]) => void): this;\n\toff<U extends keyof ObserverEvents>(event: U, listener: (...args: ObserverEvents[U]) => void): this;\n\tonce<U extends keyof ObserverEvents>(event: U, listener: (...args: ObserverEvents[U]) => void): this;\n\temit<U extends keyof ObserverEvents>(event: U, ...args: ObserverEvents[U]): boolean;\n}\n\nexport class Observer<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic readonly observedTURN = new ObservedTURN();\n\tpublic readonly observedCalls = new Map<string, ObservedCall>();\n\tpublic readonly observedMediasoupRouters = new Map<string, ObservedMediasoupRouter>();\n\n\tpublic updater?: Updater;\n\n\t/** Ancestry base shared by all Observer-bus events originating at the observer. */\n\tpublic readonly eventScope: ObserverEventBase = { observer: this };\n\n\tpublic closed = false;\n\n\tpublic totalAddedCall = 0;\n\tpublic totalRemovedCall = 0;\n\n\tpublic numberOfClientsUsingTurn = 0;\n\tpublic numberOfClients = 0;\n\tpublic numberOfInboundRtpStreams = 0;\n\tpublic numberOfOutboundRtpStreams = 0;\n\tpublic numberOfDataChannels = 0;\n\tpublic numberOfPeerConnections = 0;\n\n\t/** Global, pre-dispatch middleware chain run on every accepted sample. */\n\tpublic readonly acceptMiddlewares = new MiddlewareProcessor<AcceptMiddlewarePayload>();\n\n\t/**\n\t * Observer-scoped detector registry (ships empty), run on every `observer.update()` — the place\n\t * for findings that span **calls**, e.g. \"many calls on the same SFU degraded at once\". Detectors\n\t * raise findings with `observer.addIssue(...)`, surfaced on the bus as `observer-issue`.\n\t * (For findings within a single call use `observedCall.detectors`.)\n\t */\n\tpublic readonly detectors = new Detectors();\n\n\tpublic constructor(public readonly config: ObserverConfig<AppData> = {\n\t\tupdatePolicy: 'update-when-all-call-updated',\n\t\tappData: {} as AppData,\n\t}) {\n\t\tsuper();\n\t\tthis.setMaxListeners(Infinity);\n\t\tthis.update = this.update.bind(this);\n\n\t\tconst currentUpdatePolicy = (config?.updatePolicy) ?? 'update-when-all-call-updated';\n\n\t\tswitch (currentUpdatePolicy) {\n\t\t\tcase 'update-on-any-call-updated':\n\t\t\t\tthis.updater = new OnAnyCallObserverUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'update-when-all-call-updated':\n\t\t\t\tthis.updater = new OnAllCallObserverUpdater(this);\n\t\t\t\tbreak;\n\t\t\tcase 'none':\n\t\t\t\t// No automatic updater: `observer.update()` only runs when the app calls it.\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tpublic get numberOfCalls() {\n\t\treturn this.observedCalls.size;\n\t}\n\n\tpublic get appData() {\n\t\treturn this.config.appData;\n\t}\n\n\tpublic getObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(callId: string): ObservedCall<T> | undefined {\n\t\tif (this.closed || !this.observedCalls.has(callId)) return;\n\n\t\treturn this.observedCalls.get(callId) as ObservedCall<T>;\n\t}\n\n\tpublic createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedCallSettings<T>\n\t): ObservedCall<T> | undefined {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to create a call (callId: %s) on a closed observer', settings.callId);\n\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this.observedCalls.has(settings.callId)) {\n\t\t\tlogger.warn('Observed Call with id %s already exists; returning the existing instance', settings.callId);\n\n\t\t\treturn this.observedCalls.get(settings.callId) as ObservedCall<T>;\n\t\t}\n\n\t\t// Apply observer-level defaults without mutating the caller's (discriminated-union) settings object.\n\t\tconst callSettings = {\n\t\t\t...settings,\n\t\t\tupdatePolicy: settings.updatePolicy ?? this.config.defaultCallUpdatePolicy,\n\t\t\tcloseCallIfEmptyForMs: settings.closeCallIfEmptyForMs ?? this.config.closeCallIfEmptyForMs,\n\t\t\tappData: settings.appData ?? this.config.createCallAppData?.({ callId: settings.callId, observer: this }),\n\t\t} as ObservedCallSettings<T>;\n\n\t\tconst observedCall = new ObservedCall(callSettings, this);\n\n\t\t// Build the call's track resolver from the configured factory (if any).\n\t\tobservedCall.remoteTrackResolver = this.config.createRemoteTrackResolver?.(observedCall);\n\n\t\tobservedCall.once('close', () => {\n\t\t\tthis.observedCalls.delete(observedCall.callId);\n\t\t\t++this.totalRemovedCall;\n\t\t});\n\n\t\tthis.observedCalls.set(observedCall.callId, observedCall);\n\t\t++this.totalAddedCall;\n\n\t\tthis._notify('call-added', { ...this.eventScope, observedCall });\n\n\t\treturn observedCall;\n\t}\n\n\tpublic getOrCreateObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedCallSettings<T>\n\t): ObservedCall<T> | undefined {\n\t\treturn this.getObservedCall<T>(settings.callId) ?? this.createObservedCall<T>(settings);\n\t}\n\n\tpublic createObservedMediasoupRouter<T extends Record<string, unknown> = Record<string, unknown>>(\n\t\tsettings: ObservedMediasoupRouterSettings<T> & {\n\t\t\t// When `true`, the observer emits `mediasoup-router-matched-with-peer-connection` for every\n\t\t\t// observed peer connection whose id matches one of this router's WebRTC transport ids.\n\t\t\t// When `false` / omitted, no peer-connection matching is performed.\n\t\t\tmatchPeerConnectionByWebRtcTransportId?: boolean,\n\t\t},\n\t) {\n\t\tif (this.closed) {\n\t\t\tlogger.warn('Attempted to create mediasoup router (id: %d) on a closed observer', settings.router.id);\n\n\t\t\treturn undefined;\n\t\t}\n\t\tif (this.observedMediasoupRouters.has(settings.router.id)) {\n\t\t\tlogger.warn('Observed Mediasoup Router (id %s) already exists; returning the existing instance', settings.router.id);\n\n\t\t\treturn this.observedMediasoupRouters.get(settings.router.id);\n\t\t}\n\n\t\tconst observedMediasoupRouter = new ObservedMediasoupRouter(settings);\n\t\tconst observedMediasoupRouterScope: ObservedMediasoupRouterScope = {\n\t\t\tobservedMediasoupRouter,\n\t\t\tobserver: this,\n\t\t};\n\n\t\t// Peer-connection matching is opt-in (see `matchPeerConnectionByWebRtcTransportId`). When on,\n\t\t// emit `mediasoup-router-matched-with-peer-connection` for each peer connection whose id matches\n\t\t// one of the router's WebRTC transport ids; the observer stores nothing — the app owns the pairing.\n\t\tif (settings.matchPeerConnectionByWebRtcTransportId) {\n\t\t\tconst onPeerConnectionAdded = (observedPeerConnectionScope: ObserverEvents['peer-connection-added'][0]) => {\n\t\t\t\tif (!observedMediasoupRouter.webrtcTransportIds.has(observedPeerConnectionScope.observedPeerConnection.peerConnectionId)) return;\n\n\t\t\t\tthis.emit('mediasoup-router-matched-with-peer-connection', {\n\t\t\t\t\t...observedMediasoupRouterScope,\n\t\t\t\t\t...observedPeerConnectionScope,\n\t\t\t\t});\n\t\t\t};\n\t\t\tconst stopMatching = () => this.off('peer-connection-added', onPeerConnectionAdded);\n\n\t\t\tthis.on('peer-connection-added', onPeerConnectionAdded);\n\t\t\tthis.once('observer-closed', stopMatching);\n\t\t\tobservedMediasoupRouter.once('close', stopMatching);\n\t\t}\n\n\t\tobservedMediasoupRouter.once('close', () => {\n\t\t\tthis.observedMediasoupRouters.delete(observedMediasoupRouter.id);\n\n\t\t\tthis.emit('mediasoup-router-removed', observedMediasoupRouterScope);\n\t\t});\n\t\tthis.observedMediasoupRouters.set(observedMediasoupRouter.id, observedMediasoupRouter);\n\n\t\tthis.emit('mediasoup-router-added', observedMediasoupRouterScope);\n\n\t\treturn observedMediasoupRouter;\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) {\n\t\t\treturn logger.debug('Attempted to close twice');\n\t\t}\n\t\tthis.closed = true;\n\n\t\tthis.observedCalls.forEach((call) => call.close());\n\t\t// Release detectors (they may hold bus subscriptions) before announcing the close.\n\t\tthis.detectors.clear();\n\n\t\tthis._notify('observer-closed', { ...this.eventScope });\n\t}\n\n\tpublic accept(sample: ClientSample, context?: AcceptContext): void {\n\t\tif (this.closed) {\n\t\t\treturn this._notify('sample-rejected', { ...this.eventScope, reason: 'observer-closed', sample });\n\t\t}\n\n\t\ttry {\n\t\t\tthis.acceptMiddlewares.process({ sample, context });\n\t\t} catch (err) {\n\t\t\tlogger.warn('An accept middleware threw; dropping the sample. %o', err);\n\t\t}\n\n\t\tif (!sample.callId) {\n\t\t\tthis._notify('sample-rejected', { ...this.eventScope, reason: 'missing-callId', sample });\n\n\t\t\treturn;\n\t\t}\n\t\tif (!sample.clientId) {\n\t\t\tthis._notify('sample-rejected', { ...this.eventScope, reason: 'missing-clientId', sample });\n\n\t\t\treturn;\n\t\t}\n\n\t\tlet call = this.getObservedCall(sample.callId);\n\n\t\tif (!call) {\n\t\t\tcall = this.createObservedCall({\n\t\t\t\tcallId: sample.callId,\n\t\t\t\tappData: this.config.createCallAppData?.({ callId: sample.callId, observer: this }),\n\t\t\t});\n\t\t}\n\t\tif (!call) return;\n\n\t\tlet client = call.getObservedClient(sample.clientId);\n\n\t\tif (!client) {\n\t\t\tclient = call.createObservedClient({\n\t\t\t\tclientId: sample.clientId,\n\t\t\t\tappData: this.config.createClientAppData?.({ clientId: sample.clientId, observedCall: call }),\n\t\t\t});\n\t\t}\n\t\tif (!client) return;\n\n\t\tclient.accept(sample, context);\n\t}\n\n\tpublic update() {\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.numberOfInboundRtpStreams = 0;\n\t\tthis.numberOfOutboundRtpStreams = 0;\n\t\tthis.numberOfPeerConnections = 0;\n\t\tthis.numberOfDataChannels = 0;\n\t\tthis.numberOfClients = 0;\n\t\tthis.numberOfClientsUsingTurn = 0;\n\n\t\tfor (const call of this.observedCalls.values()) {\n\t\t\tthis.numberOfInboundRtpStreams += call.numberOfInboundRtpStreams;\n\t\t\tthis.numberOfOutboundRtpStreams += call.numberOfOutboundRtpStreams;\n\t\t\tthis.numberOfPeerConnections += call.numberOfPeerConnections;\n\t\t\tthis.numberOfDataChannels += call.numberOfDataChannels;\n\t\t\tthis.numberOfClients += call.numberOfClients;\n\t\t\tthis.numberOfClientsUsingTurn += call.clientsUsedTurn.size;\n\t\t}\n\n\t\tthis.observedTURN.update();\n\t\tthis.detectors.update();\n\n\t\tthis._notify('observer-updated', { ...this.eventScope });\n\t}\n\n\t/**\n\t * Raise an observer-scoped (cross-call / SFU-wide) finding. Emitted on the bus as\n\t * `observer-issue`. Intended for `observer.detectors`, but the application may call it too.\n\t */\n\tpublic addIssue(issue: ClientIssue) {\n\t\tif (this.closed) return;\n\n\t\tthis._notify('observer-issue', { ...this.eventScope, issue });\n\t}\n\n\t/** Emit an Observer-bus event. */\n\tprivate _notify<K extends keyof ObserverEvents>(type: K, ...args: ObserverEvents[K]): void {\n\t\tthis.emit(type, ...args);\n\t}\n}\n","import { EventEmitter } from 'events';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedTurnServer } from './ObservedTurnServer';\nimport { createLogger } from './common/logger';\n\nconst logger = createLogger('ObservedTURN');\n\nexport type ObservedTURNEventMap = {\n\t'update': [ObservedTURN];\n\t'close': [];\n}\n\nexport declare interface ObservedTURN {\n\ton<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;\n\toff<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;\n\tonce<U extends keyof ObservedTURNEventMap>(event: U, listener: (...args: ObservedTURNEventMap[U]) => void): this;\n\temit<U extends keyof ObservedTURNEventMap>(event: U, ...args: ObservedTURNEventMap[U]): boolean;\n}\n\nexport class ObservedTURN extends EventEmitter {\n\tpublic totalBytesSent = 0;\n\tpublic totalBytesReceived = 0;\n\tpublic totalPacketsSent = 0;\n\tpublic totalPacketsReceived = 0;\n\n\tpublic packetsSentPerSecond = 0;\n\tpublic packetsReceivedPerSecond = 0;\n\tpublic outboundBitrate = 0;\n\tpublic inboundBitrate = 0;\n\tpublic numberOfClients = 0;\n \n\tpublic readonly servers = new Map<string, ObservedTurnServer>();\n\n\tpublic constructor(\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic update() {\n\t\tconst clientIds = new Set<string>();\n \n\t\tthis.packetsReceivedPerSecond = 0;\n\t\tthis.packetsSentPerSecond = 0;\n\t\tthis.outboundBitrate = 0;\n\t\tthis.inboundBitrate = 0;\n\n\t\tfor (const server of this.servers.values()) {\n\t\t\tserver.update();\n\t\t\tserver.observedPeerConnections.forEach((pc) => clientIds.add(pc.client.clientId));\n\t\t}\n\n\t\tthis.numberOfClients = clientIds.size;\n\t}\n\n\tpublic addPeerConnection(peerConnection: ObservedPeerConnection) {\n\t\t// selected pairs whose *local* candidate is a relay candidate with a `turn(s):` url\n\t\t// (the ICE server url is only exposed on local candidates).\n\t\tconst turnPairs = peerConnection.selectedIceCandiadtePairForTurn;\n\n\t\tif (turnPairs.length !== 1) {\n\t\t\treturn (logger.warn(`Expected exactly one TURN pair, but found for peerconnection ${peerConnection.peerConnectionId}`, turnPairs.length), undefined);\n\t\t}\n\n\t\tconst candidatePair = turnPairs[0];\n\t\tconst rawUrl = candidatePair.getLocalCandidate()?.url;\n\n\t\tif (!rawUrl) {\n\t\t\treturn (logger.warn(`No local candidate URL found for peerconnection ${peerConnection.peerConnectionId}`), undefined);\n\t\t}\n\n\t\t// A TURN url looks like `turn(s):host[:port][?transport=udp|tcp]` (RFC 7065). The WHATWG\n\t\t// `URL` class parses these non-special schemes as opaque paths (empty hostname/port), so\n\t\t// derive the server key by stripping the query instead of using `new URL()`.\n\t\tconst turnServerUrl = rawUrl.split('?')[0];\n\t\tlet turnServer = this.servers.get(turnServerUrl);\n\n\t\tif (!turnServer) {\n\t\t\tturnServer = new ObservedTurnServer(turnServerUrl, this);\n\t\t\tthis.servers.set(turnServerUrl, turnServer);\n\t\t}\n\n\t\tturnServer.observedPeerConnections.set(peerConnection.peerConnectionId, peerConnection);\n\n\t\treturn turnServer;\n\t}\n\n\tpublic removePeerConnection(peerConnection: ObservedPeerConnection) {\n\t\tfor (const turnServer of this.servers.values()) {\n\t\t\tturnServer.observedPeerConnections.delete(peerConnection.peerConnectionId);\n\t\t}\n\t}\n\n}","import { ObservedIceCandidatePair } from './ObservedIceCandidatePair';\nimport { ObservedPeerConnection } from './ObservedPeerConnection';\nimport { ObservedTURN } from './ObservedTURN';\n\nexport class ObservedTurnServer {\n\tpublic totalBytesSent = 0;\n\tpublic totalBytesReceived = 0;\n\tpublic totalPacketsSent = 0;\n\tpublic totalPacketsReceived = 0;\n\n\tpublic packetsSentPerSecond = 0;\n\tpublic packetsReceivedPerSecond = 0;\n\tpublic outboundBitrate = 0;\n\tpublic inboundBitrate = 0;\n\n\tpublic deltaBytesSent = 0;\n\tpublic deltaBytesReceived = 0;\n\tpublic deltaPacketsSent = 0;\n\tpublic deltaPacketsReceived = 0;\n \n\tpublic readonly observedPeerConnections = new Map<string, ObservedPeerConnection>(); \n\n\tpublic updated = Date.now();\n\n\tpublic constructor(\n\t\tpublic readonly url: string,\n\t\tpublic readonly observedTURN: ObservedTURN,\n\t) {\n\n\t}\n\n\tpublic updateTurnUsage(...selectedcandidatepairs: ObservedIceCandidatePair[]) {\n\t\tfor (const selectedcandidatepair of selectedcandidatepairs) {\n\t\t\tthis.deltaBytesReceived += selectedcandidatepair.deltaBytesReceived;\n\t\t\tthis.deltaBytesSent += selectedcandidatepair.deltaBytesSent;\n\t\t\tthis.deltaPacketsReceived += selectedcandidatepair.deltaPacketsReceived;\n\t\t\tthis.deltaPacketsSent += selectedcandidatepair.deltaPacketsSent;\n\t\t}\n\t}\n\n\tpublic update() {\n\t\tconst now = Date.now();\n\t\tconst deltaInS = (now - this.updated) / 1000;\n \n\t\tthis.packetsSentPerSecond = this.deltaPacketsSent / deltaInS;\n\t\tthis.packetsReceivedPerSecond = this.deltaPacketsReceived / deltaInS; \n\t\tthis.outboundBitrate = (this.deltaBytesReceived * 8) / deltaInS;\n\t\tthis.inboundBitrate = (this.deltaBytesSent * 8) / deltaInS;\n \n\t\tthis.totalBytesSent += this.deltaBytesSent;\n\t\tthis.totalBytesReceived += this.deltaBytesReceived;\n\t\tthis.totalPacketsSent += this.deltaPacketsSent;\n\t\tthis.totalPacketsReceived += this.deltaPacketsReceived;\n\t\t\n\t\tthis.observedTURN.totalBytesSent += this.deltaBytesSent;\n\t\tthis.observedTURN.totalBytesReceived += this.deltaBytesReceived;\n\t\tthis.observedTURN.totalPacketsSent += this.deltaPacketsSent;\n\t\tthis.observedTURN.totalPacketsReceived += this.deltaPacketsReceived;\n \n\t\tthis.observedTURN.inboundBitrate += this.inboundBitrate;\n\t\tthis.observedTURN.outboundBitrate += this.outboundBitrate;\n\t\tthis.observedTURN.packetsReceivedPerSecond += this.packetsReceivedPerSecond;\n\t\tthis.observedTURN.packetsSentPerSecond += this.packetsSentPerSecond;\n \n\t\tthis.deltaBytesSent = 0;\n\t\tthis.deltaBytesReceived = 0;\n\t\tthis.deltaPacketsSent = 0;\n\t\tthis.deltaPacketsReceived = 0;\n\n\t\tthis.updated = now;\n\t}\n}","import { ObservedCall } from '../ObservedCall';\nimport { Observer } from '../Observer';\nimport type { ObservedCallScope } from '../ObserverEvents';\nimport { Updater } from './Updater';\n\nexport class OnAllCallObserverUpdater implements Updater {\n\tpublic readonly name = 'OnAllCallObserverUpdater';\n\tpublic readonly description = 'Call Observer\\'s update() method when all of the ObservedCalls are updated';\n\t\n\tprivate readonly _updatedCalls = new Set<string>();\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate observer: Observer\n\t) {\n\t\tthis._onNewObservedCall = this._onNewObservedCall.bind(this);\n\n\t\tthis.observer.once('observer-closed', () => {\n\t\t\tthis.observer.off('call-added', this._onNewObservedCall);\n\t\t});\n\t\tthis.observer.on('call-added', this._onNewObservedCall);\n\t}\n\n\tclose(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\n\t\tthis._updatedCalls.clear();\n\t}\n\n\tprivate _onNewObservedCall({ observedCall }: ObservedCallScope) {\n\t\tif (this.closed) return;\n\n\t\tconst onUpdate = () => this._onObservedCallUpdated(observedCall);\n\n\t\tobservedCall.once('close', () => {\n\t\t\tobservedCall.off('update', onUpdate);\n\t\t\tthis._updatedCalls.delete(observedCall.callId);\n\n\t\t\tthis._updateIfEveryCallUpdated();\n\t\t});\n\t\tobservedCall.on('update', onUpdate);\n\t}\n\n\tprivate _onObservedCallUpdated(observedCall: ObservedCall) {\n\t\tif (observedCall.closed) return;\n\n\t\tthis._updatedCalls.add(observedCall.callId);\n\n\t\tthis._updateIfEveryCallUpdated();\n\t}\n\n\tprivate _updateIfEveryCallUpdated() {\n\t\tif (this._updatedCalls.size < this.observer.observedCalls.size) return;\n\t\telse if (this.closed) return;\n\n\t\tthis._updatedCalls.clear();\n\t\tthis.observer.update();\n\t}\n}","import { Observer } from '../Observer';\nimport type { ObservedCallScope } from '../ObserverEvents';\nimport { Updater } from './Updater';\n\nexport class OnAnyCallObserverUpdater implements Updater {\n\tpublic readonly name = 'OnAnyCallObserverUpdater';\n\tpublic readonly description = 'Call Observer\\'s update() method on any of the ObservedCall is updated';\n\tpublic closed = false;\n\n\tpublic constructor(\n\t\tprivate observver: Observer\n\t) {\n\t\tthis._onNewObservedCall = this._onNewObservedCall.bind(this);\n\n\t\tthis.observver.once('observer-closed', () => {\n\t\t\tthis.observver.off('call-added', this._onNewObservedCall);\n\t\t});\n\t\tthis.observver.on('call-added', this._onNewObservedCall);\n\t}\n\n\tpublic close(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\t// do nothing, because we unsubscribe once close is emitted from observer\n\t}\n\n\tprivate _onNewObservedCall({ observedCall }: ObservedCallScope) {\n\t\tif (this.closed) return;\n\n\t\tconst onUpdate = () => {\n\t\t\tif (this.closed) return;\n\n\t\t\tthis.observver.update();\n\t\t};\n\n\t\tobservedCall.once('close', () => {\n\t\t\tobservedCall.off('update', onUpdate);\n\t\t});\n\t\tobservedCall.on('update', onUpdate);\n\t}\n}","export type Middleware<T> = (\n\tinput: T,\n\tnext: (nextInput: T) => void\n) => void;\n\nexport interface Processor<T> {\n\tfinalCallback?: Callback<T>;\n\tprocess(value: T): void;\n\taddMiddleware(...middlewares: Middleware<T>[]): Processor<T>;\n\tremoveMiddleware(...middlewares: Middleware<T>[]): Processor<T>;\n}\n\ntype Callback<T> = (input: T) => void;\n\nclass Executor<T> {\n\tpublic done = false;\n\tprivate index = 0;\n\tprivate prevIndex = -1;\n\n\tconstructor(\n\t\tprivate readonly stack: Middleware<T>[],\n\t\tprivate readonly finalCallback?: Callback<T>\n\t) {\n\t}\n\n\t// Executes the middleware stack\n\tpublic execute(input: T): void {\n\t\tif (this.index <= this.prevIndex) {\n\t\t\tthrow new Error('Middleware must call next() only once!');\n\t\t} else if (this.done) {\n\t\t\tthrow new Error('Middleware stack has already been executed!');\n\t\t}\n\n\t\tthis.prevIndex = this.index;\n\n\t\tconst middleware = this.stack[this.index];\n\n\t\tthis.index++;\n\n\t\tif (middleware) {\n\t\t\treturn middleware(input, (nextInput: T) => this.execute(nextInput));\n\t\t}\n\n\t\tthis.done = true;\n\t\tthis.finalCallback?.(input);\n\t}\n}\n\nexport class MiddlewareProcessor<T> implements Processor<T> {\n\tprivate stack: Middleware<T>[] = [];\n\tpublic finalCallback?: Callback<T>;\n\n\tpublic addMiddleware(...middlewares: Middleware<T>[]): Processor<T> {\n\t\tif (middlewares && middlewares.length > 0) {\n\t\t\tthis.stack.push(...middlewares);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic removeMiddleware(...middlewares: Middleware<T>[]): Processor<T> {\n\t\tif (middlewares && middlewares.length > 0) {\n\t\t\tfor (const middleware of middlewares) {\n\t\t\t\tconst index = this.stack.indexOf(middleware);\n\n\t\t\t\tif (index >= 0) {\n\t\t\t\t\tthis.stack.splice(index, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\tpublic process(value: T): void {\n\t\tif (this.stack.length === 0) {\n\t\t\treturn this.finalCallback?.(value);\n\t\t}\n\n\t\tconst executor = new Executor(this.stack, this.finalCallback);\n\n\t\texecutor.execute(value);\n\t}\n}\n","import { EventEmitter } from 'events';\nimport type { types } from 'mediasoup';\nimport {\n\tMediasoupRouterSample,\n\tMediasoupTransportSample,\n\tMediasoupProducerSample,\n\tMediasoupConsumerSample,\n\tMediasoupDataProducerSample,\n\tMediasoupDataConsumerSample,\n\tMediasoupWebRtcTransportSampleEventMap,\n\tMediasoupPlainTransportSampleEventMap,\n\tMediasoupPipeTransportSampleEventMap,\n} from './schema/MediasoupRouter';\nimport { createLogger } from './common/logger';\n\nconst logger = createLogger('ObservedMediasoupRouter');\n\n/**\n * Declarative enrichment: return the `attachments` to stamp onto an entity's sample the moment it is\n * created. Called once per entity, before the corresponding `*-sample-added` event.\n *\n * The mediasoup object is handed in, so the common case — mirroring mediasoup's own `appData`, where\n * applications already keep `participantId`, `purpose` and friends — is a one-liner. Returning\n * `undefined` attaches nothing.\n */\nexport type MediasoupSampleEnricher = {\n\ttransport?: (transport: types.Transport) => Record<string, unknown> | undefined;\n\tproducer?: (producer: types.Producer, transport: types.Transport) => Record<string, unknown> | undefined;\n\tconsumer?: (consumer: types.Consumer, transport: types.Transport) => Record<string, unknown> | undefined;\n\tdataProducer?: (dataProducer: types.DataProducer, transport: types.Transport) => Record<string, unknown> | undefined;\n\tdataConsumer?: (dataConsumer: types.DataConsumer, transport: types.Transport) => Record<string, unknown> | undefined;\n};\n\nexport type ObservedMediasoupRouterSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {\n\trouter: types.Router,\n\tappData?: AppData;\n\tattachments?: Record<string, unknown>,\n\n\t/** Stamp `attachments` onto each entity sample as it is created. See {@link MediasoupSampleEnricher}. */\n\tenrich?: MediasoupSampleEnricher,\n};\n\n/**\n * Lifecycle hooks for building your own report.\n *\n * Each entity announces itself as `<entity>-sample-added` when it appears and\n * `<entity>-sample-closed` when it goes away, carrying **the live sample object** plus the mediasoup\n * object it came from. Mutating `sample.attachments` inside a handler is the intended way to extend\n * a sample on the fly — the object you receive is the one held in `observedRouter.sample`, not a copy.\n */\nexport type ObservedMediasoupRouterEvents = {\n\tclose: [];\n\n\t'transport-sample-added': [{ sample: MediasoupTransportSample, transport: types.Transport }];\n\t'transport-sample-closed': [{ sample: MediasoupTransportSample, transport: types.Transport }];\n\n\t'producer-sample-added': [{ sample: MediasoupProducerSample, producer: types.Producer, transport: types.Transport }];\n\t'producer-sample-closed': [{ sample: MediasoupProducerSample, producer: types.Producer, transport: types.Transport }];\n\n\t'consumer-sample-added': [{ sample: MediasoupConsumerSample, consumer: types.Consumer, transport: types.Transport }];\n\t'consumer-sample-closed': [{ sample: MediasoupConsumerSample, consumer: types.Consumer, transport: types.Transport }];\n\n\t'data-producer-sample-added': [{ sample: MediasoupDataProducerSample, dataProducer: types.DataProducer, transport: types.Transport }];\n\t'data-producer-sample-closed': [{ sample: MediasoupDataProducerSample, dataProducer: types.DataProducer, transport: types.Transport }];\n\n\t'data-consumer-sample-added': [{ sample: MediasoupDataConsumerSample, dataConsumer: types.DataConsumer, transport: types.Transport }];\n\t'data-consumer-sample-closed': [{ sample: MediasoupDataConsumerSample, dataConsumer: types.DataConsumer, transport: types.Transport }];\n};\n\nexport declare interface ObservedMediasoupRouter {\n\ton<U extends keyof ObservedMediasoupRouterEvents>(event: U, listener: (...args: ObservedMediasoupRouterEvents[U]) => void): this;\n\toff<U extends keyof ObservedMediasoupRouterEvents>(event: U, listener: (...args: ObservedMediasoupRouterEvents[U]) => void): this;\n\tonce<U extends keyof ObservedMediasoupRouterEvents>(event: U, listener: (...args: ObservedMediasoupRouterEvents[U]) => void): this;\n\temit<U extends keyof ObservedMediasoupRouterEvents>(event: U, ...args: ObservedMediasoupRouterEvents[U]): boolean;\n}\n\n/**\n * Observes a live mediasoup `Router` by subscribing to its `observer` API and **accumulates** its\n * topology and lifecycle into an in-memory `MediasoupRouterSample` (`observedRouter.sample`):\n * transports, producers, consumers, data producers/consumers, their state-change history and\n * `createdAt` / `closedAt`. The sample grows for the life of the router (closed entities are kept,\n * with their `closedAt` set) and is yours to read, snapshot, or persist.\n *\n * NOTE: this is intentionally the simplest approach — everything is held in memory. For very large\n * routers (e.g. ~100 participants producing and consuming on one router, where consumers grow as\n * O(N²)) this can become substantial; in that case do your own periodic sampling/persistence and\n * discard what you don't need (see the README's \"Memory & large meetings\" note).\n */\nexport class ObservedMediasoupRouter<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {\n\tpublic readonly router: types.Router;\n\tpublic appData: AppData;\n\tpublic readonly sample: MediasoupRouterSample;\n\n\tpublic readonly webrtcTransportIds = new Set<string>();\n\tpublic closed = false;\n\n\t// Id -> sample indexes over the arrays in `this.sample`, so an entity can be reached in O(1)\n\t// instead of scanning (`sample.producers.find(...)`). They hold the *same* objects as the arrays.\n\tprivate readonly _transportSamples = new Map<string, MediasoupTransportSample>();\n\tprivate readonly _producerSamples = new Map<string, MediasoupProducerSample>();\n\tprivate readonly _consumerSamples = new Map<string, MediasoupConsumerSample>();\n\tprivate readonly _dataProducerSamples = new Map<string, MediasoupDataProducerSample>();\n\tprivate readonly _dataConsumerSamples = new Map<string, MediasoupDataConsumerSample>();\n\tprivate readonly _enrich?: MediasoupSampleEnricher;\n\n\tpublic constructor(\n\t\tsettings: ObservedMediasoupRouterSettings<AppData>,\n\t) {\n\t\tsuper();\n\n\t\tthis.router = settings.router;\n\t\tthis.appData = (settings.appData ?? {}) as AppData;\n\t\tthis._enrich = settings.enrich;\n\t\tthis.sample = {\n\t\t\trouterId: this.router.id,\n\t\t\tattachments: settings.attachments ?? {},\n\t\t\tcreatedAt: Date.now(),\n\t\t\tproducers: [],\n\t\t\tconsumers: [],\n\t\t\tdataProducers: [],\n\t\t\tdataConsumers: [],\n\t\t\ttransports: [],\n\t\t};\n\n\t\tthis.attachRouterListeners();\n\t}\n\n\tpublic get id() {\n\t\treturn this.router.id;\n\t}\n\n\tpublic get attachments() {\n\t\treturn this.sample.attachments;\n\t}\n\n\t/* ---------------------------------------------------------------------------------------------\n\t * Reaching individual entity samples.\n\t *\n\t * `sample.producers` (and friends) are arrays because that is the shape you want to serialize.\n\t * These accessors index the same objects by id, so annotating one entity is an O(1) lookup and a\n\t * mutation, rather than a scan that silently does nothing when the id is wrong.\n\t * ------------------------------------------------------------------------------------------- */\n\n\tpublic getTransportSample(id: string) {\n\t\treturn this._transportSamples.get(id);\n\t}\n\n\tpublic getProducerSample(id: string) {\n\t\treturn this._producerSamples.get(id);\n\t}\n\n\tpublic getConsumerSample(id: string) {\n\t\treturn this._consumerSamples.get(id);\n\t}\n\n\tpublic getDataProducerSample(id: string) {\n\t\treturn this._dataProducerSamples.get(id);\n\t}\n\n\tpublic getDataConsumerSample(id: string) {\n\t\treturn this._dataConsumerSamples.get(id);\n\t}\n\n\t/**\n\t * Merge `attachments` into an entity's sample, whichever kind it is.\n\t *\n\t * Ids are unique across mediasoup entity kinds, so one method covers all of them. Returns `false`\n\t * when the id is unknown — a real answer instead of failing quietly, which matters when the\n\t * annotation is driven by application events that may race the mediasoup ones.\n\t */\n\tpublic attachTo(id: string, attachments: Record<string, unknown>): boolean {\n\t\tconst sample = this._transportSamples.get(id)\n\t\t\t?? this._producerSamples.get(id)\n\t\t\t?? this._consumerSamples.get(id)\n\t\t\t?? this._dataProducerSamples.get(id)\n\t\t\t?? this._dataConsumerSamples.get(id);\n\n\t\tif (!sample) return false;\n\n\t\tsample.attachments = { ...sample.attachments, ...attachments };\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * A **detached deep copy** of the current sample — the basis for building your own report.\n\t *\n\t * `this.sample` is live: its arrays grow and its `history` entries are appended as the router\n\t * runs, so a report built directly on it keeps changing after you think you're done. This returns\n\t * a snapshot that never moves.\n\t */\n\tpublic snapshot(): MediasoupRouterSample {\n\t\t// `structuredClone` is a global that isn't guaranteed everywhere the library runs (older\n\t\t// runtimes, some test environments), so fall back to a JSON round-trip. The sample is plain\n\t\t// serializable data by construction, which is exactly what a report needs anyway.\n\t\tif (typeof structuredClone === 'function') return structuredClone(this.sample);\n\n\t\treturn JSON.parse(JSON.stringify(this.sample)) as MediasoupRouterSample;\n\t}\n\n\tpublic close() {\n\t\tif (this.closed) return;\n\n\t\tthis.closed = true;\n\t\tif (this.sample.closedAt === undefined) this.sample.closedAt = Date.now();\n\n\t\tthis.emit('close');\n\t}\n\n\tpublic addTransport = (transport: types.Transport) => {\n\t\tlet transportType = transport.type;\n\n\t\t// for backward compatibility\n\t\tif (!transportType) {\n\t\t\tif (transport.constructor.name === 'WebRtcTransport') transportType = 'webrtc';\n\t\t\telse if (transport.constructor.name === 'PlainTransport') transportType = 'plain';\n\t\t\telse if (transport.constructor.name === 'PipeTransport') transportType = 'pipe';\n\t\t\telse if (transport.constructor.name === 'DirectTransport') transportType = 'direct';\n\t\t}\n\n\t\tif (!transportType) return logger.warn(`Unknown transport type for transport ${transport.id}: ${transport.constructor.name}`);\n\n\t\tswitch (transportType) {\n\t\t\tcase 'webrtc':\n\t\t\t\treturn this.addWebRtcTransport(transport as types.WebRtcTransport);\n\t\t\tcase 'plain':\n\t\t\t\treturn this.addPlainTransport(transport as types.PlainTransport);\n\t\t\tcase 'pipe':\n\t\t\t\treturn this.addPipeTransport(transport as types.PipeTransport);\n\t\t\tcase 'direct':\n\t\t\t\treturn this.addDirectTransport(transport as types.DirectTransport);\n\t\t\tdefault:\n\t\t\t\treturn logger.warn(`Unsupported transport type for transport ${transport.id}: ${transportType}`);\n\t\t}\n\t};\n\n\tpublic addWebRtcTransport(transport: types.WebRtcTransport) {\n\t\tconst history: MediasoupWebRtcTransportSampleEventMap[] = [];\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'webrtc', createdAt: Date.now(), tuple: transport.iceSelectedTuple, history,\n\t\t};\n\n\t\tthis._addTransportSample(transportSample, transport);\n\t\tthis.webrtcTransportIds.add(transport.id);\n\n\t\tconst onIceStateChange = (iceState: types.IceState) =>\n\t\t\thistory.push({ type: `icestate-changed-to-${iceState}`, timestamp: Date.now() } as MediasoupWebRtcTransportSampleEventMap);\n\t\tconst onIceSelectedTupleChange = (tuple: types.TransportTuple) => {\n\t\t\ttransportSample.tuple = tuple;\n\t\t\thistory.push({ type: 'iceselectedtuple-changed', timestamp: Date.now(), ...tuple });\n\t\t};\n\t\tconst onDtlsStateChange = (dtlsState: types.DtlsState) => {\n\t\t\thistory.push({ type: `dtlsstate-changed-to-${dtlsState}`, timestamp: Date.now() } as MediasoupWebRtcTransportSampleEventMap);\n\t\t\tif (dtlsState === 'connected' && transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t};\n\t\tconst onSctpStateChange = (sctpState: types.SctpState) =>\n\t\t\thistory.push({ type: `sctpstate-changed-to-${sctpState}`, timestamp: Date.now() } as MediasoupWebRtcTransportSampleEventMap);\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample, () => {\n\t\t\ttransport.observer.off('icestatechange', onIceStateChange);\n\t\t\ttransport.observer.off('iceselectedtuplechange', onIceSelectedTupleChange);\n\t\t\ttransport.observer.off('dtlsstatechange', onDtlsStateChange);\n\t\t\ttransport.observer.off('sctpstatechange', onSctpStateChange);\n\n\t\t\tthis.webrtcTransportIds.delete(transport.id);\n\t\t});\n\n\t\ttransport.observer.on('icestatechange', onIceStateChange);\n\t\ttransport.observer.on('iceselectedtuplechange', onIceSelectedTupleChange);\n\t\ttransport.observer.on('dtlsstatechange', onDtlsStateChange);\n\t\ttransport.observer.on('sctpstatechange', onSctpStateChange);\n\t}\n\n\tpublic addPlainTransport(transport: types.PlainTransport) {\n\t\tconst history: MediasoupPlainTransportSampleEventMap[] = [];\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'plain', createdAt: Date.now(), tuple: transport.tuple, rtcpTuple: transport.rtcpTuple, history,\n\t\t};\n\n\t\tthis._addTransportSample(transportSample, transport);\n\n\t\tconst onTuple = (tuple: types.TransportTuple) => {\n\t\t\ttransportSample.tuple = tuple;\n\t\t\tif (transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t\thistory.push({ type: 'tuple-changed', timestamp: Date.now(), ...tuple });\n\t\t};\n\t\tconst onRtcpTuple = (rtcpTuple: types.TransportTuple) => {\n\t\t\ttransportSample.rtcpTuple = rtcpTuple;\n\t\t\thistory.push({ type: 'rtcptuple-changed', timestamp: Date.now(), ...rtcpTuple });\n\t\t};\n\t\tconst onSctpStateChange = (sctpState: types.SctpState) => {\n\t\t\tif (sctpState === 'connected' && transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t\thistory.push({ type: `sctpstate-changed-to-${sctpState}`, timestamp: Date.now() } as MediasoupPlainTransportSampleEventMap);\n\t\t};\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample, () => {\n\t\t\ttransport.observer.off('tuple', onTuple);\n\t\t\ttransport.observer.off('rtcptuple', onRtcpTuple);\n\t\t\ttransport.observer.off('sctpstatechange', onSctpStateChange);\n\t\t});\n\n\t\ttransport.observer.on('tuple', onTuple);\n\t\ttransport.observer.on('rtcptuple', onRtcpTuple);\n\t\ttransport.observer.on('sctpstatechange', onSctpStateChange);\n\t}\n\n\tpublic addPipeTransport(transport: types.PipeTransport) {\n\t\tconst history: MediasoupPipeTransportSampleEventMap[] = [];\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'pipe', createdAt: Date.now(), tuple: transport.tuple, history,\n\t\t};\n\n\t\tthis._addTransportSample(transportSample, transport);\n\n\t\tconst onSctpStateChange = (sctpState: types.SctpState) => {\n\t\t\tif (sctpState === 'connected' && transportSample.connectedAt === undefined) transportSample.connectedAt = Date.now();\n\t\t\thistory.push({ type: `sctpstate-changed-to-${sctpState}`, timestamp: Date.now() } as MediasoupPipeTransportSampleEventMap);\n\t\t};\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample, () => {\n\t\t\ttransport.observer.off('sctpstatechange', onSctpStateChange);\n\t\t});\n\n\t\ttransport.observer.on('sctpstatechange', onSctpStateChange);\n\t}\n\n\tpublic addDirectTransport(transport: types.DirectTransport) {\n\t\tconst now = Date.now();\n\t\tconst transportSample: MediasoupTransportSample = {\n\t\t\tid: transport.id, type: 'direct', createdAt: now, connectedAt: now, history: [],\n\t\t};\n\n\t\tthis._addTransportSample(transportSample, transport);\n\n\t\tthis._attachTransportObserverListeners(transport, transportSample);\n\t}\n\n\tpublic addProducer(transport: types.Transport, producer: types.Producer) {\n\t\tconst firstCodec = producer.rtpParameters.codecs[0];\n\t\tconst producerSample: MediasoupProducerSample = {\n\t\t\tid: producer.id,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tkind: producer.kind,\n\t\t\tcodecInfo: {\n\t\t\t\tmimeType: firstCodec?.mimeType ?? 'unknown/unknown',\n\t\t\t\tpayloadType: firstCodec?.payloadType ?? 0,\n\t\t\t\tclockRate: firstCodec?.clockRate ?? 0,\n\t\t\t\tchannels: firstCodec?.channels,\n\t\t\t\tparameters: firstCodec?.parameters,\n\t\t\t\trtcpFeedback: firstCodec?.rtcpFeedback,\n\t\t\t},\n\t\t\tssrcs: producer.rtpParameters.encodings?.map((e) => e.ssrc).filter((s): s is number => typeof s === 'number'),\n\t\t\trids: producer.rtpParameters.encodings?.map((e) => e.rid).filter((r): r is string => typeof r === 'string'),\n\t\t\thistory: [],\n\t\t};\n\n\t\tthis._addProducerSample(producerSample, producer, transport);\n\n\t\tconst onPause = () => producerSample.history.push({ type: 'pause', timestamp: Date.now() });\n\t\tconst onResume = () => producerSample.history.push({ type: 'resume', timestamp: Date.now() });\n\n\t\tproducer.observer.once('close', () => {\n\t\t\tproducer.observer.off('pause', onPause);\n\t\t\tproducer.observer.off('resume', onResume);\n\t\t\tproducerSample.closedAt = Date.now();\n\t\t\tthis.emit('producer-sample-closed', { sample: producerSample, producer, transport });\n\t\t});\n\t\tproducer.observer.on('pause', onPause);\n\t\tproducer.observer.on('resume', onResume);\n\t}\n\n\tpublic addConsumer(transport: types.Transport, consumer: types.Consumer) {\n\t\tconst consumerSample: MediasoupConsumerSample = {\n\t\t\tid: consumer.id,\n\t\t\tproducerId: consumer.producerId,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tkind: consumer.kind,\n\t\t\thistory: [],\n\t\t};\n\n\t\tthis._addConsumerSample(consumerSample, consumer, transport);\n\n\t\tconst onPause = () => consumerSample.history.push({ type: 'pause', timestamp: Date.now() });\n\t\tconst onResume = () => consumerSample.history.push({ type: 'resume', timestamp: Date.now() });\n\t\tconst onProducerPause = () => consumerSample.history.push({ type: 'producerPaused', timestamp: Date.now() });\n\t\tconst onProducerResume = () => consumerSample.history.push({ type: 'producerResumed', timestamp: Date.now() });\n\n\t\tconsumer.observer.once('close', () => {\n\t\t\tconsumer.observer.off('pause', onPause);\n\t\t\tconsumer.observer.off('resume', onResume);\n\t\t\tconsumer.off('producerresume', onProducerResume);\n\t\t\tconsumer.off('producerpause', onProducerPause);\n\t\t\tconsumerSample.closedAt = Date.now();\n\t\t\tthis.emit('consumer-sample-closed', { sample: consumerSample, consumer, transport });\n\t\t});\n\n\t\tconsumer.observer.on('pause', onPause);\n\t\tconsumer.observer.on('resume', onResume);\n\t\tconsumer.on('producerpause', onProducerPause);\n\t\tconsumer.on('producerresume', onProducerResume);\n\t}\n\n\tpublic addDataProducer(transport: types.Transport, dataProducer: types.DataProducer) {\n\t\tconst dataProducerSample: MediasoupDataProducerSample = {\n\t\t\tid: dataProducer.id,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tlabel: dataProducer.label,\n\t\t\tprotocol: dataProducer.protocol,\n\t\t};\n\n\t\tthis._addDataProducerSample(dataProducerSample, dataProducer, transport);\n\n\t\tdataProducer.observer.once('close', () => {\n\t\t\tdataProducerSample.closedAt = Date.now();\n\t\t\tthis.emit('data-producer-sample-closed', { sample: dataProducerSample, dataProducer, transport });\n\t\t});\n\t}\n\n\tpublic addDataConsumer(transport: types.Transport, dataConsumer: types.DataConsumer) {\n\t\tconst dataConsumerSample: MediasoupDataConsumerSample = {\n\t\t\tid: dataConsumer.id,\n\t\t\tdataProducerId: dataConsumer.dataProducerId,\n\t\t\ttransportId: transport.id,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tlabel: dataConsumer.label,\n\t\t\tprotocol: dataConsumer.protocol,\n\t\t};\n\n\t\tthis._addDataConsumerSample(dataConsumerSample, dataConsumer, transport);\n\n\t\tdataConsumer.observer.once('close', () => {\n\t\t\tdataConsumerSample.closedAt = Date.now();\n\t\t\tthis.emit('data-consumer-sample-closed', { sample: dataConsumerSample, dataConsumer, transport });\n\t\t});\n\t}\n\n\tprivate attachRouterListeners() {\n\t\tthis.router.observer.once('close', () => {\n\t\t\tthis.router.observer.off('newtransport', this.addTransport);\n\n\t\t\tthis.sample.closedAt = Date.now();\n\t\t\tthis.close();\n\t\t});\n\t\tthis.router.observer.on('newtransport', this.addTransport);\n\t}\n\n\t/* ---------------------------------------------------------------------------------------------\n\t * Registration: push into the sample array, index by id, run the enricher, announce.\n\t * The order matters — enrichment lands *before* the event, so a listener always sees the\n\t * declaratively-attached data and can build on it rather than race it.\n\t * ------------------------------------------------------------------------------------------- */\n\n\tprivate _addTransportSample(sample: MediasoupTransportSample, transport: types.Transport) {\n\t\tthis.sample.transports.push(sample);\n\t\tthis._transportSamples.set(sample.id, sample);\n\t\tthis._applyEnrichment(sample, this._enrich?.transport && (() => this._enrich?.transport?.(transport)));\n\t\tthis.emit('transport-sample-added', { sample, transport });\n\t}\n\n\tprivate _addProducerSample(sample: MediasoupProducerSample, producer: types.Producer, transport: types.Transport) {\n\t\tthis.sample.producers.push(sample);\n\t\tthis._producerSamples.set(sample.id, sample);\n\t\tthis._applyEnrichment(sample, this._enrich?.producer && (() => this._enrich?.producer?.(producer, transport)));\n\t\tthis.emit('producer-sample-added', { sample, producer, transport });\n\t}\n\n\tprivate _addConsumerSample(sample: MediasoupConsumerSample, consumer: types.Consumer, transport: types.Transport) {\n\t\tthis.sample.consumers.push(sample);\n\t\tthis._consumerSamples.set(sample.id, sample);\n\t\tthis._applyEnrichment(sample, this._enrich?.consumer && (() => this._enrich?.consumer?.(consumer, transport)));\n\t\tthis.emit('consumer-sample-added', { sample, consumer, transport });\n\t}\n\n\tprivate _addDataProducerSample(sample: MediasoupDataProducerSample, dataProducer: types.DataProducer, transport: types.Transport) {\n\t\tthis.sample.dataProducers.push(sample);\n\t\tthis._dataProducerSamples.set(sample.id, sample);\n\t\tthis._applyEnrichment(sample, this._enrich?.dataProducer && (() => this._enrich?.dataProducer?.(dataProducer, transport)));\n\t\tthis.emit('data-producer-sample-added', { sample, dataProducer, transport });\n\t}\n\n\tprivate _addDataConsumerSample(sample: MediasoupDataConsumerSample, dataConsumer: types.DataConsumer, transport: types.Transport) {\n\t\tthis.sample.dataConsumers.push(sample);\n\t\tthis._dataConsumerSamples.set(sample.id, sample);\n\t\tthis._applyEnrichment(sample, this._enrich?.dataConsumer && (() => this._enrich?.dataConsumer?.(dataConsumer, transport)));\n\t\tthis.emit('data-consumer-sample-added', { sample, dataConsumer, transport });\n\t}\n\n\t/**\n\t * Run an enricher and merge what it returns.\n\t *\n\t * Takes a thunk rather than a value so the **invocation** is inside the guard — application code\n\t * runs here, and a throwing enricher must not take the router's bookkeeping down with it.\n\t */\n\tprivate _applyEnrichment(\n\t\tsample: { attachments?: Record<string, unknown> },\n\t\tenrich?: () => Record<string, unknown> | undefined,\n\t) {\n\t\tif (!enrich) return;\n\n\t\ttry {\n\t\t\tconst attachments = enrich();\n\n\t\t\tif (attachments) sample.attachments = { ...sample.attachments, ...attachments };\n\t\t} catch (err) {\n\t\t\tlogger.warn('Mediasoup sample enricher threw for router %s: %o', this.id, err);\n\t\t}\n\t}\n\n\tprivate _attachTransportObserverListeners(\n\t\ttransport: types.Transport,\n\t\ttransportSample: MediasoupTransportSample,\n\t\tonClose?: () => void,\n\t) {\n\t\tconst onNewProducer = (producer: types.Producer) => this.addProducer(transport, producer);\n\t\tconst onNewConsumer = (consumer: types.Consumer) => this.addConsumer(transport, consumer);\n\t\tconst onNewDataProducer = (dataProducer: types.DataProducer) => this.addDataProducer(transport, dataProducer);\n\t\tconst onNewDataConsumer = (dataConsumer: types.DataConsumer) => this.addDataConsumer(transport, dataConsumer);\n\n\t\ttransport.observer.once('close', () => {\n\t\t\ttransport.observer.off('newproducer', onNewProducer);\n\t\t\ttransport.observer.off('newconsumer', onNewConsumer);\n\t\t\ttransport.observer.off('newdataproducer', onNewDataProducer);\n\t\t\ttransport.observer.off('newdataconsumer', onNewDataConsumer);\n\n\t\t\tonClose?.();\n\n\t\t\ttransportSample.closedAt = Date.now();\n\t\t\tthis.emit('transport-sample-closed', { sample: transportSample, transport });\n\t\t});\n\n\t\ttransport.observer.on('newproducer', onNewProducer);\n\t\ttransport.observer.on('newconsumer', onNewConsumer);\n\t\ttransport.observer.on('newdataproducer', onNewDataProducer);\n\t\ttransport.observer.on('newdataconsumer', onNewDataConsumer);\n\t}\n}\n","import type { ObservedOutboundTrack } from '../ObservedOutboundTrack';\nimport type { ObservedInboundTrack } from '../ObservedInboundTrack';\nimport type { ObservedCall } from '../ObservedCall';\nimport { StatsSummary, summarize } from './stats';\n\n/**\n * Thresholds deciding when a single receiver counts as \"degraded\". A receiver is degraded when it\n * trips **any** of these in the current tick.\n */\nexport type ReceiverHealthThresholds = {\n\n\t/** Fraction of packets lost in the tick (0..1). */\n\tfractionLost: number;\n\n\t/** Freezes observed in the tick. */\n\tfreezeCount: number;\n\n\t/** Fraction of received frames dropped before rendering (0..1). */\n\tframesDroppedRatio: number;\n\n\t/** Fraction of received audio samples concealed (0..1). */\n\tconcealmentRatio: number;\n\n\t/** Mean jitter-buffer delay of the tick (ms). */\n\tjitterBufferDelayInMs: number;\n\n\t/** Round-trip time reported for the receiving peer connection (ms). */\n\trttInMs: number;\n};\n\nexport const defaultReceiverHealthThresholds: ReceiverHealthThresholds = {\n\tfractionLost: 0.03,\n\tfreezeCount: 1,\n\tframesDroppedRatio: 0.05,\n\tconcealmentRatio: 0.1,\n\tjitterBufferDelayInMs: 500,\n\trttInMs: 400,\n};\n\n/** The per-receiver view the aggregator builds for one subscribed track. */\nexport type ReceiverDistributionEntry = {\n\tobservedInboundTrack: ObservedInboundTrack;\n\tclientId: string;\n\tpeerConnectionId: string;\n\tdegraded: boolean;\n\n\t/** Why it was marked degraded (empty when healthy). */\n\treasons: string[];\n\n\tbitrate: number;\n\tfractionLost?: number;\n\tjitter?: number;\n\trttInMs?: number;\n\tjitterBufferDelayInMs?: number;\n\tconcealmentRatio?: number;\n\tframesDroppedRatio?: number;\n\tdeltaFreezeCount: number;\n\tdeltaPliCount: number;\n\tdeltaNackCount: number;\n\tdeltaPacketsReceived: number;\n};\n\n/** The publisher side of the distribution. */\nexport type PublisherDistributionEntry = {\n\tobservedOutboundTrack: ObservedOutboundTrack;\n\tclientId: string;\n\tpeerConnectionId: string;\n\n\t/** `true` when the publisher's own egress looks fine (so degradation is downstream). */\n\thealthy: boolean;\n\treasons: string[];\n\n\tbitrate: number;\n\n\t/** Loss reported back by the SFU/remote via RTCP (0..1). */\n\tremoteFractionLost?: number;\n\tremoteRttInMs?: number;\n\tqualityLimitationReason?: string;\n\tdeltaPacketsSent: number;\n};\n\n/**\n * One published track and everything observed about how it was delivered to its subscribers.\n * This is the primitive most cross-client detectors are built on.\n */\nexport type ObservedTrackDistribution = {\n\ttrackId: string;\n\tkind: string;\n\tpublisher: PublisherDistributionEntry;\n\treceivers: ReceiverDistributionEntry[];\n\n\tnumberOfReceivers: number;\n\tnumberOfHealthyReceivers: number;\n\tnumberOfDegradedReceivers: number;\n\n\t/** degradedReceivers / receivers (0..1); `0` when there are no receivers. */\n\tdegradedRatio: number;\n\n\t/** Distribution summaries across receivers (undefined when no receiver reported the metric). */\n\tbitrate?: StatsSummary;\n\tfractionLost?: StatsSummary;\n\tjitter?: StatsSummary;\n\trttInMs?: StatsSummary;\n\tjitterBufferDelayInMs?: StatsSummary;\n\tconcealmentRatio?: StatsSummary;\n\n\t/** Fan-out counters: how many receivers saw the symptom, and the total across them. */\n\tfreezes: { affectedReceivers: number, total: number };\n\tplis: { affectedReceivers: number, total: number };\n\tconcealment: { affectedReceivers: number };\n};\n\n/**\n * Builds {@link ObservedTrackDistribution}s by walking\n * `ObservedOutboundTrack.remoteInboundTracks` — the publisher → subscribers links maintained by a\n * `RemoteTrackResolver`. Without a configured resolver there are no links and the aggregator\n * yields nothing.\n *\n * It is stateless per call: build it once and call `aggregate()` on each `call.update()`.\n */\nexport class TrackDistributionAggregator {\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tpublic readonly thresholds: ReceiverHealthThresholds = defaultReceiverHealthThresholds,\n\t) {\n\t}\n\n\t/** Aggregate every published track in the call that currently has linked subscribers. */\n\tpublic aggregate(): ObservedTrackDistribution[] {\n\t\tconst result: ObservedTrackDistribution[] = [];\n\n\t\tfor (const client of this._call.observedClients.values()) {\n\t\t\tfor (const peerConnection of client.observedPeerConnections.values()) {\n\t\t\t\tfor (const outboundTrack of peerConnection.observedOutboundTracks.values()) {\n\t\t\t\t\tconst distribution = this.aggregateTrack(outboundTrack);\n\n\t\t\t\t\tif (distribution) result.push(distribution);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/** Aggregate a single published track, or `undefined` when it has no linked subscribers. */\n\tpublic aggregateTrack(outboundTrack: ObservedOutboundTrack): ObservedTrackDistribution | undefined {\n\t\tif (outboundTrack.remoteInboundTracks.size === 0) return undefined;\n\n\t\tconst publisher = this._publisherEntry(outboundTrack);\n\t\tconst receivers: ReceiverDistributionEntry[] = [];\n\n\t\tfor (const inboundTrack of outboundTrack.remoteInboundTracks) {\n\t\t\treceivers.push(this._receiverEntry(inboundTrack));\n\t\t}\n\n\t\tconst degraded = receivers.filter((receiver) => receiver.degraded);\n\t\tconst collect = (pick: (r: ReceiverDistributionEntry) => number | undefined) =>\n\t\t\tsummarize(receivers.map(pick).filter((v): v is number => typeof v === 'number' && Number.isFinite(v)));\n\n\t\treturn {\n\t\t\ttrackId: outboundTrack.id,\n\t\t\tkind: outboundTrack.kind,\n\t\t\tpublisher,\n\t\t\treceivers,\n\t\t\tnumberOfReceivers: receivers.length,\n\t\t\tnumberOfHealthyReceivers: receivers.length - degraded.length,\n\t\t\tnumberOfDegradedReceivers: degraded.length,\n\t\t\tdegradedRatio: 0 < receivers.length ? degraded.length / receivers.length : 0,\n\n\t\t\tbitrate: collect((r) => r.bitrate),\n\t\t\tfractionLost: collect((r) => r.fractionLost),\n\t\t\tjitter: collect((r) => r.jitter),\n\t\t\trttInMs: collect((r) => r.rttInMs),\n\t\t\tjitterBufferDelayInMs: collect((r) => r.jitterBufferDelayInMs),\n\t\t\tconcealmentRatio: collect((r) => r.concealmentRatio),\n\n\t\t\tfreezes: {\n\t\t\t\taffectedReceivers: receivers.filter((r) => 0 < r.deltaFreezeCount).length,\n\t\t\t\ttotal: receivers.reduce((sum, r) => sum + r.deltaFreezeCount, 0),\n\t\t\t},\n\t\t\tplis: {\n\t\t\t\taffectedReceivers: receivers.filter((r) => 0 < r.deltaPliCount).length,\n\t\t\t\ttotal: receivers.reduce((sum, r) => sum + r.deltaPliCount, 0),\n\t\t\t},\n\t\t\tconcealment: {\n\t\t\t\taffectedReceivers: receivers.filter((r) => this.thresholds.concealmentRatio <= (r.concealmentRatio ?? 0)).length,\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate _publisherEntry(outboundTrack: ObservedOutboundTrack): PublisherDistributionEntry {\n\t\tconst peerConnection = outboundTrack.getPeerConnection();\n\t\tconst rtps = outboundTrack.getOutboundRtps() ?? [];\n\n\t\tlet bitrate = 0;\n\t\tlet deltaPacketsSent = 0;\n\t\tlet remoteFractionLost: number | undefined;\n\t\tlet remoteRttInMs: number | undefined;\n\t\tlet qualityLimitationReason: string | undefined;\n\n\t\tfor (const rtp of rtps) {\n\t\t\tbitrate += rtp.bitrate;\n\t\t\tdeltaPacketsSent += rtp.deltaPacketsSent;\n\n\t\t\tif (rtp.remoteFractionLost !== undefined) {\n\t\t\t\tremoteFractionLost = Math.max(remoteFractionLost ?? 0, rtp.remoteFractionLost);\n\t\t\t}\n\t\t\tif (rtp.remoteRttInMs !== undefined) {\n\t\t\t\tremoteRttInMs = Math.max(remoteRttInMs ?? 0, rtp.remoteRttInMs);\n\t\t\t}\n\t\t\tif (rtp.qualityLimitationReason && rtp.qualityLimitationReason !== 'none') {\n\t\t\t\tqualityLimitationReason = rtp.qualityLimitationReason;\n\t\t\t}\n\t\t}\n\n\t\tconst reasons: string[] = [];\n\n\t\tif (this.thresholds.fractionLost < (remoteFractionLost ?? 0)) reasons.push('remote-fraction-lost');\n\t\tif (this.thresholds.rttInMs < (remoteRttInMs ?? 0)) reasons.push('remote-rtt');\n\t\tif (qualityLimitationReason) reasons.push(`quality-limited-${qualityLimitationReason}`);\n\t\tif (outboundTrack.muted !== true && deltaPacketsSent === 0) reasons.push('no-packets-sent');\n\n\t\treturn {\n\t\t\tobservedOutboundTrack: outboundTrack,\n\t\t\tclientId: peerConnection?.client.clientId ?? 'unknown',\n\t\t\tpeerConnectionId: peerConnection?.peerConnectionId ?? 'unknown',\n\t\t\thealthy: reasons.length === 0,\n\t\t\treasons,\n\t\t\tbitrate,\n\t\t\tremoteFractionLost,\n\t\t\tremoteRttInMs,\n\t\t\tqualityLimitationReason,\n\t\t\tdeltaPacketsSent,\n\t\t};\n\t}\n\n\tprivate _receiverEntry(inboundTrack: ObservedInboundTrack): ReceiverDistributionEntry {\n\t\tconst peerConnection = inboundTrack.getPeerConnection();\n\t\tconst rtp = inboundTrack.getInboundRtp();\n\t\tconst reasons: string[] = [];\n\n\t\tconst fractionLost = rtp?.fractionLost;\n\t\tconst deltaFreezeCount = rtp?.deltaFreezeCount ?? 0;\n\t\tconst framesDroppedRatio = rtp?.framesDroppedRatio;\n\t\tconst concealmentRatio = rtp?.concealmentRatio;\n\t\tconst jitterBufferDelayInMs = rtp?.jitterBufferDelayInMs;\n\t\tconst rttInMs = peerConnection?.currentRttInMs;\n\n\t\tif (this.thresholds.fractionLost < (fractionLost ?? 0)) reasons.push('fraction-lost');\n\t\tif (this.thresholds.freezeCount <= deltaFreezeCount) reasons.push('freezes');\n\t\tif (this.thresholds.framesDroppedRatio < (framesDroppedRatio ?? 0)) reasons.push('frames-dropped');\n\t\tif (this.thresholds.concealmentRatio < (concealmentRatio ?? 0)) reasons.push('concealment');\n\t\tif (this.thresholds.jitterBufferDelayInMs < (jitterBufferDelayInMs ?? 0)) reasons.push('jitter-buffer-delay');\n\t\tif (this.thresholds.rttInMs < (rttInMs ?? 0)) reasons.push('rtt');\n\n\t\treturn {\n\t\t\tobservedInboundTrack: inboundTrack,\n\t\t\tclientId: peerConnection?.client.clientId ?? 'unknown',\n\t\t\tpeerConnectionId: peerConnection?.peerConnectionId ?? 'unknown',\n\t\t\tdegraded: 0 < reasons.length,\n\t\t\treasons,\n\t\t\tbitrate: rtp?.bitrate ?? 0,\n\t\t\tfractionLost,\n\t\t\tjitter: rtp?.jitter,\n\t\t\trttInMs,\n\t\t\tjitterBufferDelayInMs,\n\t\t\tconcealmentRatio,\n\t\t\tframesDroppedRatio,\n\t\t\tdeltaFreezeCount,\n\t\t\tdeltaPliCount: rtp?.deltaPliCount ?? 0,\n\t\t\tdeltaNackCount: rtp?.deltaNackCount ?? 0,\n\t\t\tdeltaPacketsReceived: rtp?.deltaReceivedPackets ?? 0,\n\t\t};\n\t}\n}\n","import type { ObservedCall } from '../ObservedCall';\nimport type { ObservedClient } from '../ObservedClient';\nimport { StatsSummary, summarize } from './stats';\n\n/** Thresholds deciding when a client counts as degraded on the receiving / sending side. */\nexport type ClientHealthThresholds = {\n\n\t/** Inbound loss fraction across the client's received streams (0..1). */\n\tinboundFractionLost: number;\n\n\t/** Loss fraction reported back about the client's sent streams via RTCP (0..1). */\n\toutboundFractionLost: number;\n\n\t/** Round-trip time (ms). */\n\trttInMs: number;\n\n\t/** Freezes observed across the client's inbound video in the tick. */\n\tfreezeCount: number;\n\n\t/** Concealment fraction across the client's inbound audio (0..1). */\n\tconcealmentRatio: number;\n};\n\nexport const defaultClientHealthThresholds: ClientHealthThresholds = {\n\tinboundFractionLost: 0.03,\n\toutboundFractionLost: 0.03,\n\trttInMs: 400,\n\tfreezeCount: 1,\n\tconcealmentRatio: 0.1,\n};\n\n/** The per-client health view, split by direction. */\nexport type ClientHealth = {\n\tobservedClient: ObservedClient;\n\tclientId: string;\n\n\t/** Receiving (download) side is impaired. */\n\tinboundDegraded: boolean;\n\n\t/** Sending (upload) side is impaired. */\n\toutboundDegraded: boolean;\n\n\t/** `inboundDegraded || outboundDegraded`. */\n\tdegraded: boolean;\n\treasons: string[];\n\n\tinboundFractionLost?: number;\n\toutboundFractionLost?: number;\n\trttInMs?: number;\n\tdeltaFreezeCount: number;\n\tconcealmentRatio?: number;\n\n\t/** Quality-limitation reasons seen on this client's outbound video ('cpu' | 'bandwidth' | …). */\n\tqualityLimitationReasons: string[];\n\n\tusingTURN: boolean;\n\tusingTCP: boolean;\n};\n\n/** Call-level rollup of the per-client health, using percentiles rather than means. */\nexport type CallHealth = {\n\tcallId: string;\n\tclients: ClientHealth[];\n\n\tnumberOfClients: number;\n\tnumberOfDegradedClients: number;\n\tnumberOfInboundDegradedClients: number;\n\tnumberOfOutboundDegradedClients: number;\n\n\t/** degradedClients / clients (0..1). */\n\tdegradedRatio: number;\n\tinboundDegradedRatio: number;\n\toutboundDegradedRatio: number;\n\n\trttInMs?: StatsSummary;\n\tinboundFractionLost?: StatsSummary;\n\tconcealmentRatio?: StatsSummary;\n\n\t/** How many clients reported each quality-limitation reason on their outbound video. */\n\tqualityLimitation: { cpu: number, bandwidth: number, other: number };\n\n\tfreezes: { affectedClients: number, total: number };\n};\n\n/**\n * Aggregates a call along the **client** axis (as `TrackDistributionAggregator` does along the\n * publisher→subscriber axis): per-client health split into sending vs receiving, plus percentile\n * rollups and \"affected ratio\" counts for the whole call.\n *\n * Build once per call and call `aggregate()` on each `call.update()`.\n */\nexport class CallHealthAggregator {\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tpublic readonly thresholds: ClientHealthThresholds = defaultClientHealthThresholds,\n\t) {\n\t}\n\n\tpublic aggregate(): CallHealth {\n\t\tconst clients: ClientHealth[] = [];\n\n\t\tfor (const client of this._call.observedClients.values()) {\n\t\t\tclients.push(this._clientHealth(client));\n\t\t}\n\n\t\tconst degraded = clients.filter((c) => c.degraded);\n\t\tconst inboundDegraded = clients.filter((c) => c.inboundDegraded);\n\t\tconst outboundDegraded = clients.filter((c) => c.outboundDegraded);\n\t\tconst collect = (pick: (c: ClientHealth) => number | undefined) =>\n\t\t\tsummarize(clients.map(pick).filter((v): v is number => typeof v === 'number' && Number.isFinite(v)));\n\n\t\tconst qualityLimitation = { cpu: 0, bandwidth: 0, other: 0 };\n\n\t\tfor (const client of clients) {\n\t\t\tif (client.qualityLimitationReasons.includes('cpu')) qualityLimitation.cpu += 1;\n\t\t\tif (client.qualityLimitationReasons.includes('bandwidth')) qualityLimitation.bandwidth += 1;\n\t\t\tif (client.qualityLimitationReasons.some((r) => r !== 'cpu' && r !== 'bandwidth')) qualityLimitation.other += 1;\n\t\t}\n\n\t\tconst ratio = (n: number) => (0 < clients.length ? n / clients.length : 0);\n\n\t\treturn {\n\t\t\tcallId: this._call.callId,\n\t\t\tclients,\n\t\t\tnumberOfClients: clients.length,\n\t\t\tnumberOfDegradedClients: degraded.length,\n\t\t\tnumberOfInboundDegradedClients: inboundDegraded.length,\n\t\t\tnumberOfOutboundDegradedClients: outboundDegraded.length,\n\t\t\tdegradedRatio: ratio(degraded.length),\n\t\t\tinboundDegradedRatio: ratio(inboundDegraded.length),\n\t\t\toutboundDegradedRatio: ratio(outboundDegraded.length),\n\t\t\trttInMs: collect((c) => c.rttInMs),\n\t\t\tinboundFractionLost: collect((c) => c.inboundFractionLost),\n\t\t\tconcealmentRatio: collect((c) => c.concealmentRatio),\n\t\t\tqualityLimitation,\n\t\t\tfreezes: {\n\t\t\t\taffectedClients: clients.filter((c) => 0 < c.deltaFreezeCount).length,\n\t\t\t\ttotal: clients.reduce((sum, c) => sum + c.deltaFreezeCount, 0),\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate _clientHealth(client: ObservedClient): ClientHealth {\n\t\tlet deltaFreezeCount = 0;\n\t\tlet concealedSamples = 0;\n\t\tlet receivedSamples = 0;\n\t\tlet remoteLostPackets = 0;\n\t\tlet remoteSentPackets = 0;\n\t\tconst qualityLimitationReasons = new Set<string>();\n\n\t\tfor (const peerConnection of client.observedPeerConnections.values()) {\n\t\t\tfor (const rtp of peerConnection.observedInboundRtps.values()) {\n\t\t\t\tdeltaFreezeCount += rtp.deltaFreezeCount;\n\t\t\t\tconcealedSamples += rtp.deltaConcealedSamples;\n\t\t\t\treceivedSamples += rtp.deltaReceivedSamples;\n\t\t\t}\n\t\t\tfor (const rtp of peerConnection.observedOutboundRtps.values()) {\n\t\t\t\tif (rtp.qualityLimitationReason && rtp.qualityLimitationReason !== 'none') {\n\t\t\t\t\tqualityLimitationReasons.add(rtp.qualityLimitationReason);\n\t\t\t\t}\n\t\t\t\t// Loss about our *sent* streams comes back in the receiver report.\n\t\t\t\tif (rtp.remoteFractionLost !== undefined) {\n\t\t\t\t\tremoteLostPackets += rtp.remoteFractionLost * rtp.deltaPacketsSent;\n\t\t\t\t\tremoteSentPackets += rtp.deltaPacketsSent;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst inboundTotal = client.deltaInboundPacketsLost + client.deltaInboundPacketsReceived;\n\t\tconst inboundFractionLost = 0 < inboundTotal ? client.deltaInboundPacketsLost / inboundTotal : undefined;\n\t\tconst outboundFractionLost = 0 < remoteSentPackets ? remoteLostPackets / remoteSentPackets : undefined;\n\t\tconst concealmentRatio = 0 < receivedSamples ? concealedSamples / receivedSamples : undefined;\n\t\tconst rttInMs = client.currentAvgRttInMs;\n\n\t\tconst reasons: string[] = [];\n\n\t\tif (this.thresholds.inboundFractionLost < (inboundFractionLost ?? 0)) reasons.push('inbound-fraction-lost');\n\t\tif (this.thresholds.freezeCount <= deltaFreezeCount) reasons.push('freezes');\n\t\tif (this.thresholds.concealmentRatio < (concealmentRatio ?? 0)) reasons.push('concealment');\n\t\tif (this.thresholds.rttInMs < (rttInMs ?? 0)) reasons.push('rtt');\n\n\t\tconst outboundReasons: string[] = [];\n\n\t\tif (this.thresholds.outboundFractionLost < (outboundFractionLost ?? 0)) outboundReasons.push('outbound-fraction-lost');\n\t\tif (0 < qualityLimitationReasons.size) {\n\t\t\toutboundReasons.push(...[ ...qualityLimitationReasons ].map((r) => `quality-limited-${r}`));\n\t\t}\n\n\t\tconst inboundDegraded = 0 < reasons.length;\n\t\tconst outboundDegraded = 0 < outboundReasons.length;\n\n\t\treturn {\n\t\t\tobservedClient: client,\n\t\t\tclientId: client.clientId,\n\t\t\tinboundDegraded,\n\t\t\toutboundDegraded,\n\t\t\tdegraded: inboundDegraded || outboundDegraded,\n\t\t\treasons: [ ...reasons, ...outboundReasons ],\n\t\t\tinboundFractionLost,\n\t\t\toutboundFractionLost,\n\t\t\trttInMs,\n\t\t\tdeltaFreezeCount,\n\t\t\tconcealmentRatio,\n\t\t\tqualityLimitationReasons: [ ...qualityLimitationReasons ],\n\t\t\tusingTURN: client.usingTURN,\n\t\t\tusingTCP: client.usingTCP,\n\t\t};\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport {\n\tdefaultReceiverHealthThresholds,\n\tObservedTrackDistribution,\n\tReceiverHealthThresholds,\n\tTrackDistributionAggregator,\n} from '../utils/TrackDistributionAggregator';\n\n/** The finding types this detector raises (as `call-issue.type`). */\nexport const CommonSourceDegradationTypes = {\n\t/** The publisher's egress looks fine, yet most subscribers are degraded → downstream/SFU suspected. */\n\tpublisherHealthySubscribersDegraded: 'PUBLISHER_HEALTHY_SUBSCRIBERS_DEGRADED',\n\n\t/** The publisher itself is impaired and every subscriber sees it → source-side problem. */\n\tpublisherDegradedForAllSubscribers: 'PUBLISHER_DEGRADED_FOR_ALL_SUBSCRIBERS',\n\n\t/** Exactly one subscriber is degraded while the rest are fine → that receiver's own problem. */\n\tsingleSubscriberDegraded: 'SINGLE_SUBSCRIBER_DEGRADED',\n\n\t/** Several (but not most) subscribers degraded on the same source. */\n\tmultipleSubscribersDegraded: 'MULTIPLE_SUBSCRIBERS_DEGRADED',\n} as const;\n\nexport type CommonSourceDegradationDetectorConfig = {\n\n\t/** Minimum subscribers before a ratio is meaningful. Default `3`. */\n\tminReceivers: number;\n\n\t/** degradedRatio at/above which the problem is treated as common to the source. Default `0.6`. */\n\tdegradedRatioThreshold: number;\n\n\t/** Per-receiver health thresholds (forwarded to the aggregator). */\n\tthresholds?: Partial<ReceiverHealthThresholds>;\n\n\t/**\n\t * Consecutive ticks a condition must hold before an issue is raised, to avoid flapping on a\n\t * single bad sample. Default `2`.\n\t */\n\tconsecutiveTicks: number;\n};\n\nconst defaultConfig: CommonSourceDegradationDetectorConfig = {\n\tminReceivers: 3,\n\tdegradedRatioThreshold: 0.6,\n\tconsecutiveTicks: 2,\n};\n\n/**\n * Compares a published track against **all** of its subscribers and decides where the fault lies.\n *\n * This is the detector that only a server-side observer can run: a single browser cannot know\n * whether the other participants receiving the same source see the same thing. Requires a\n * `RemoteTrackResolver` (`ObserverConfig.createTrackResolver`) — without publisher↔subscriber links\n * there is nothing to compare and the detector stays silent.\n */\nexport class CommonSourceDegradationDetector implements Detector {\n\tpublic readonly name = 'common-source-degradation-detector';\n\n\tprivate readonly _config: CommonSourceDegradationDetectorConfig;\n\tprivate readonly _aggregator: TrackDistributionAggregator;\n\n\t/** trackId -> consecutive ticks the same finding held. */\n\tprivate readonly _streaks = new Map<string, { type: string, ticks: number }>();\n\n\t/** The distributions computed on the most recent `update()` (handy for dashboards). */\n\tpublic lastDistributions: ObservedTrackDistribution[] = [];\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<CommonSourceDegradationDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._aggregator = new TrackDistributionAggregator(\n\t\t\t_call,\n\t\t\t{ ...defaultReceiverHealthThresholds, ...config.thresholds },\n\t\t);\n\t}\n\n\tpublic update(): void {\n\t\tthis.lastDistributions = this._aggregator.aggregate();\n\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const distribution of this.lastDistributions) {\n\t\t\tseen.add(distribution.trackId);\n\n\t\t\tconst type = this._classify(distribution);\n\n\t\t\tif (!type) {\n\t\t\t\tthis._streaks.delete(distribution.trackId);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst streak = this._streaks.get(distribution.trackId);\n\t\t\tconst ticks = streak?.type === type ? streak.ticks + 1 : 1;\n\n\t\t\tthis._streaks.set(distribution.trackId, { type, ticks });\n\n\t\t\t// Raise once, when the streak first reaches the threshold.\n\t\t\tif (ticks === this._config.consecutiveTicks) {\n\t\t\t\tthis._call.addIssue({\n\t\t\t\t\ttype,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\tpayload: JSON.stringify(this._payload(distribution, type)),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// forget tracks that no longer distribute\n\t\tfor (const trackId of [ ...this._streaks.keys() ]) {\n\t\t\tif (!seen.has(trackId)) this._streaks.delete(trackId);\n\t\t}\n\t}\n\n\tprivate _classify(distribution: ObservedTrackDistribution): string | undefined {\n\t\tconst { numberOfReceivers, numberOfDegradedReceivers, degradedRatio, publisher } = distribution;\n\n\t\tif (numberOfDegradedReceivers === 0) return undefined;\n\n\t\t// A single degraded receiver among healthy ones is that receiver's own problem — report it\n\t\t// regardless of `minReceivers`, as long as there is something to compare against.\n\t\tif (numberOfDegradedReceivers === 1 && 1 < numberOfReceivers) {\n\t\t\treturn CommonSourceDegradationTypes.singleSubscriberDegraded;\n\t\t}\n\n\t\tif (numberOfReceivers < this._config.minReceivers) return undefined;\n\n\t\tif (this._config.degradedRatioThreshold <= degradedRatio) {\n\t\t\treturn publisher.healthy\n\t\t\t\t? CommonSourceDegradationTypes.publisherHealthySubscribersDegraded\n\t\t\t\t: CommonSourceDegradationTypes.publisherDegradedForAllSubscribers;\n\t\t}\n\n\t\treturn CommonSourceDegradationTypes.multipleSubscribersDegraded;\n\t}\n\n\tprivate _payload(distribution: ObservedTrackDistribution, type: string) {\n\t\treturn {\n\t\t\ttype,\n\t\t\ttrackId: distribution.trackId,\n\t\t\tkind: distribution.kind,\n\t\t\tpublisher: {\n\t\t\t\tclientId: distribution.publisher.clientId,\n\t\t\t\thealthy: distribution.publisher.healthy,\n\t\t\t\treasons: distribution.publisher.reasons,\n\t\t\t\tbitrate: distribution.publisher.bitrate,\n\t\t\t\tremoteFractionLost: distribution.publisher.remoteFractionLost,\n\t\t\t\tqualityLimitationReason: distribution.publisher.qualityLimitationReason,\n\t\t\t},\n\t\t\treceivers: distribution.numberOfReceivers,\n\t\t\tdegradedReceivers: distribution.numberOfDegradedReceivers,\n\t\t\tdegradedRatio: distribution.degradedRatio,\n\t\t\taffectedClientIds: distribution.receivers.filter((r) => r.degraded).map((r) => r.clientId),\n\t\t\tfreezes: distribution.freezes,\n\t\t\tplis: distribution.plis,\n\t\t\tfractionLost: distribution.fractionLost,\n\t\t\tbitrate: distribution.bitrate,\n\t\t};\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport {\n\tCallHealth,\n\tCallHealthAggregator,\n\tClientHealthThresholds,\n\tdefaultClientHealthThresholds,\n} from '../utils/CallHealthAggregator';\n\nexport const CallWideDegradationTypes = {\n\t/** Most participants degraded at once → shared cause (call/SFU/network), not individual endpoints. */\n\tcallWideQualityDegradation: 'CALL_WIDE_QUALITY_DEGRADATION',\n\n\t/** Most participants' **receiving** side degraded → downstream/egress suspected. */\n\tcallWideInboundDegradation: 'CALL_WIDE_INBOUND_DEGRADATION',\n\n\t/** Most participants' **sending** side degraded → ingress suspected. */\n\tcallWideOutboundDegradation: 'CALL_WIDE_OUTBOUND_DEGRADATION',\n} as const;\n\nexport type CallWideDegradationDetectorConfig = {\n\n\t/** Minimum participants before a ratio means anything. Default `3`. */\n\tminClients: number;\n\n\t/** Affected-client ratio at/above which the call is considered call-wide degraded. Default `0.5`. */\n\tdegradedRatioThreshold: number;\n\n\t/** Per-client health thresholds. */\n\tthresholds?: Partial<ClientHealthThresholds>;\n\n\t/** Consecutive ticks the condition must hold before raising. Default `2`. */\n\tconsecutiveTicks: number;\n};\n\nconst defaultConfig: CallWideDegradationDetectorConfig = {\n\tminClients: 3,\n\tdegradedRatioThreshold: 0.5,\n\tconsecutiveTicks: 2,\n};\n\n/**\n * Raises a call-level finding when a **majority of participants** are degraded in the same window —\n * the signal that something shared is wrong rather than one person's Wi-Fi.\n *\n * It also splits by direction, because that is what makes the finding actionable: if most clients'\n * receiving side is bad the suspicion is egress/downstream; if most clients' sending side is bad it\n * points at ingress. Reported with medians/percentiles, never means, so a single 1500 ms outlier\n * can't manufacture (or mask) a call-wide alert.\n */\nexport class CallWideDegradationDetector implements Detector {\n\tpublic readonly name = 'call-wide-degradation-detector';\n\n\tprivate readonly _config: CallWideDegradationDetectorConfig;\n\tprivate readonly _aggregator: CallHealthAggregator;\n\tprivate _streak?: { type: string, ticks: number };\n\n\t/** The health rollup computed on the most recent `update()`. */\n\tpublic lastHealth?: CallHealth;\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<CallWideDegradationDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._aggregator = new CallHealthAggregator(\n\t\t\t_call,\n\t\t\t{ ...defaultClientHealthThresholds, ...config.thresholds },\n\t\t);\n\t}\n\n\tpublic update(): void {\n\t\tconst health = this._aggregator.aggregate();\n\n\t\tthis.lastHealth = health;\n\n\t\tconst type = this._classify(health);\n\n\t\tif (!type) {\n\t\t\tthis._streak = undefined;\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst ticks = this._streak?.type === type ? this._streak.ticks + 1 : 1;\n\n\t\tthis._streak = { type, ticks };\n\n\t\tif (ticks === this._config.consecutiveTicks) {\n\t\t\tthis._call.addIssue({\n\t\t\t\ttype,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\tpayload: JSON.stringify(this._payload(health, type)),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _classify(health: CallHealth): string | undefined {\n\t\tif (health.numberOfClients < this._config.minClients) return undefined;\n\n\t\tconst threshold = this._config.degradedRatioThreshold;\n\n\t\tif (health.degradedRatio < threshold) return undefined;\n\n\t\t// Prefer the more specific, directional finding when one side clearly dominates.\n\t\tif (threshold <= health.inboundDegradedRatio && health.outboundDegradedRatio < threshold) {\n\t\t\treturn CallWideDegradationTypes.callWideInboundDegradation;\n\t\t}\n\t\tif (threshold <= health.outboundDegradedRatio && health.inboundDegradedRatio < threshold) {\n\t\t\treturn CallWideDegradationTypes.callWideOutboundDegradation;\n\t\t}\n\n\t\treturn CallWideDegradationTypes.callWideQualityDegradation;\n\t}\n\n\tprivate _payload(health: CallHealth, type: string) {\n\t\treturn {\n\t\t\ttype,\n\t\t\tcallId: health.callId,\n\t\t\tclients: health.numberOfClients,\n\t\t\tdegradedClients: health.numberOfDegradedClients,\n\t\t\tdegradedRatio: health.degradedRatio,\n\t\t\tinboundDegradedRatio: health.inboundDegradedRatio,\n\t\t\toutboundDegradedRatio: health.outboundDegradedRatio,\n\t\t\taffectedClientIds: health.clients.filter((c) => c.degraded).map((c) => c.clientId),\n\t\t\trttInMs: health.rttInMs,\n\t\t\tinboundFractionLost: health.inboundFractionLost,\n\t\t\tconcealmentRatio: health.concealmentRatio,\n\t\t\tfreezes: health.freezes,\n\t\t\tqualityLimitation: health.qualityLimitation,\n\t\t};\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport {\n\tdefaultReceiverHealthThresholds,\n\tObservedTrackDistribution,\n\tReceiverHealthThresholds,\n\tTrackDistributionAggregator,\n} from '../utils/TrackDistributionAggregator';\nimport { SlidingWindow } from '../utils/stats';\n\nexport const PliAndFreezeFanOutTypes = {\n\t/** Many receivers of the same publisher requested keyframes at once. */\n\tpublisherPliStorm: 'PUBLISHER_PLI_STORM',\n\n\t/** Many receivers of the same publisher froze at once. */\n\tpublishedVideoFrozenForMultipleReceivers: 'PUBLISHED_VIDEO_FROZEN_FOR_MULTIPLE_RECEIVERS',\n} as const;\n\nexport type PliAndFreezeFanOutDetectorConfig = {\n\n\t/** Minimum receivers of the track before a fan-out ratio is meaningful. Default `3`. */\n\tminReceivers: number;\n\n\t/** Fraction of receivers that must be affected within the window. Default `0.5`. */\n\taffectedRatioThreshold: number;\n\n\t/** The correlation window (ms) symptoms are counted over. Default `10_000`. */\n\twindowMs: number;\n\n\t/** Minimum PLIs across receivers inside the window before a storm is declared. Default `5`. */\n\tminPliCount: number;\n\n\t/** Re-arm time (ms) before the same finding can be raised again for a track. Default `30_000`. */\n\tcooldownMs: number;\n\n\tthresholds?: Partial<ReceiverHealthThresholds>;\n};\n\nconst defaultConfig: PliAndFreezeFanOutDetectorConfig = {\n\tminReceivers: 3,\n\taffectedRatioThreshold: 0.5,\n\twindowMs: 10_000,\n\tminPliCount: 5,\n\tcooldownMs: 30_000,\n};\n\ntype TrackWindow = {\n\n\t/** Per-tick samples of which receivers were affected, inside the window. */\n\tpli: SlidingWindow<{ receivers: string[], count: number }>;\n\tfreeze: SlidingWindow<{ receivers: string[], count: number }>;\n\tlastRaisedAt: Map<string, number>;\n};\n\n/**\n * Detects **fan-out** symptoms: one publisher's stream causing many receivers to request keyframes\n * (PLI) or to freeze within the same window.\n *\n * A single receiver sending PLIs is unremarkable — it lost some packets. Nineteen of twenty\n * receivers of the *same* source doing it inside ten seconds is not twenty coincidental network\n * faults; it points at the source's output, the SFU's forwarding, or a keyframe/burst problem\n * upstream. That distinction requires seeing every subscriber of a track at once, which is why this\n * belongs server-side.\n *\n * Symptoms are accumulated in a sliding window rather than judged per tick, because a burst is\n * spread over a few samples.\n */\nexport class PliAndFreezeFanOutDetector implements Detector {\n\tpublic readonly name = 'pli-and-freeze-fan-out-detector';\n\n\tprivate readonly _config: PliAndFreezeFanOutDetectorConfig;\n\tprivate readonly _aggregator: TrackDistributionAggregator;\n\tprivate readonly _windows = new Map<string, TrackWindow>();\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<PliAndFreezeFanOutDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._aggregator = new TrackDistributionAggregator(\n\t\t\t_call,\n\t\t\t{ ...defaultReceiverHealthThresholds, ...config.thresholds },\n\t\t);\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\t\tconst distributions = this._aggregator.aggregate();\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const distribution of distributions) {\n\t\t\tseen.add(distribution.trackId);\n\n\t\t\tconst window = this._windowOf(distribution.trackId);\n\t\t\tconst pliReceivers = distribution.receivers.filter((r) => 0 < r.deltaPliCount);\n\t\t\tconst freezeReceivers = distribution.receivers.filter((r) => 0 < r.deltaFreezeCount);\n\n\t\t\tif (0 < pliReceivers.length) {\n\t\t\t\twindow.pli.add({ receivers: pliReceivers.map((r) => r.clientId), count: distribution.plis.total }, now);\n\t\t\t}\n\t\t\tif (0 < freezeReceivers.length) {\n\t\t\t\twindow.freeze.add({ receivers: freezeReceivers.map((r) => r.clientId), count: distribution.freezes.total }, now);\n\t\t\t}\n\n\t\t\tif (distribution.numberOfReceivers < this._config.minReceivers) continue;\n\n\t\t\tthis._evaluate(distribution, window, now, 'pli');\n\t\t\tthis._evaluate(distribution, window, now, 'freeze');\n\t\t}\n\n\t\t// drop state for tracks that no longer distribute\n\t\tfor (const trackId of [ ...this._windows.keys() ]) {\n\t\t\tif (!seen.has(trackId)) this._windows.delete(trackId);\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tthis._windows.clear();\n\t}\n\n\tprivate _evaluate(distribution: ObservedTrackDistribution, window: TrackWindow, now: number, kind: 'pli' | 'freeze') {\n\t\tconst samples = (kind === 'pli' ? window.pli : window.freeze).values(now);\n\n\t\tif (samples.length === 0) return;\n\n\t\tconst affected = new Set<string>();\n\t\tlet total = 0;\n\n\t\tfor (const sample of samples) {\n\t\t\tfor (const clientId of sample.receivers) affected.add(clientId);\n\t\t\ttotal += sample.count;\n\t\t}\n\n\t\tconst affectedRatio = affected.size / distribution.numberOfReceivers;\n\n\t\tif (affectedRatio < this._config.affectedRatioThreshold) return;\n\t\tif (kind === 'pli' && total < this._config.minPliCount) return;\n\n\t\tconst type = kind === 'pli'\n\t\t\t? PliAndFreezeFanOutTypes.publisherPliStorm\n\t\t\t: PliAndFreezeFanOutTypes.publishedVideoFrozenForMultipleReceivers;\n\n\t\tconst lastRaisedAt = window.lastRaisedAt.get(type) ?? 0;\n\n\t\tif (now - lastRaisedAt < this._config.cooldownMs) return;\n\n\t\twindow.lastRaisedAt.set(type, now);\n\n\t\tthis._call.addIssue({\n\t\t\ttype,\n\t\t\ttimestamp: now,\n\t\t\tpayload: JSON.stringify({\n\t\t\t\ttype,\n\t\t\t\ttrackId: distribution.trackId,\n\t\t\t\tkind: distribution.kind,\n\t\t\t\tpublisherClientId: distribution.publisher.clientId,\n\t\t\t\tpublisherHealthy: distribution.publisher.healthy,\n\t\t\t\tpublisherReasons: distribution.publisher.reasons,\n\t\t\t\treceivers: distribution.numberOfReceivers,\n\t\t\t\taffectedReceivers: affected.size,\n\t\t\t\taffectedRatio,\n\t\t\t\taffectedClientIds: [ ...affected ],\n\t\t\t\ttotal,\n\t\t\t\twindowMs: this._config.windowMs,\n\t\t\t}),\n\t\t});\n\t}\n\n\tprivate _windowOf(trackId: string): TrackWindow {\n\t\tlet window = this._windows.get(trackId);\n\n\t\tif (!window) {\n\t\t\twindow = {\n\t\t\t\tpli: new SlidingWindow(this._config.windowMs),\n\t\t\t\tfreeze: new SlidingWindow(this._config.windowMs),\n\t\t\t\tlastRaisedAt: new Map(),\n\t\t\t};\n\t\t\tthis._windows.set(trackId, window);\n\t\t}\n\n\t\treturn window;\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport {\n\tdefaultReceiverHealthThresholds,\n\tReceiverHealthThresholds,\n\tTrackDistributionAggregator,\n} from '../utils/TrackDistributionAggregator';\nimport { percentile } from '../utils/stats';\n\nexport const AudioImpairmentFanOutTypes = {\n\t/** Most receivers of one microphone are concealing audio → the problem follows that source. */\n\tpublishedAudioDegradedForMajority: 'PUBLISHED_AUDIO_DEGRADED_FOR_MAJORITY',\n\n\t/** Receivers across the call are under jitter-buffer pressure → shared delivery problem. */\n\tcallWideAudioJitterBufferStress: 'CALL_WIDE_AUDIO_JITTER_BUFFER_STRESS',\n} as const;\n\nexport type AudioImpairmentFanOutDetectorConfig = {\n\n\t/** Minimum receivers of a track before a ratio is meaningful. Default `3`. */\n\tminReceivers: number;\n\n\t/** Fraction of receivers that must be impaired. Default `0.6`. */\n\taffectedRatioThreshold: number;\n\n\t/** Jitter-buffer delay (ms) above which a receiver counts as stressed. Default `500`. */\n\tjitterBufferDelayInMs: number;\n\n\t/** Minimum audio receivers in the call before the call-wide check runs. Default `5`. */\n\tminCallReceivers: number;\n\n\t/** Consecutive ticks the condition must hold before raising. Default `2`. */\n\tconsecutiveTicks: number;\n\n\tthresholds?: Partial<ReceiverHealthThresholds>;\n};\n\nconst defaultConfig: AudioImpairmentFanOutDetectorConfig = {\n\tminReceivers: 3,\n\taffectedRatioThreshold: 0.6,\n\tjitterBufferDelayInMs: 500,\n\tminCallReceivers: 5,\n\tconsecutiveTicks: 2,\n};\n\n/**\n * Audio-side fan-out analysis, using the concealment / jitter-buffer metrics WebRTC exposes on the\n * receiver (NetEQ's own account of how hard it is working to keep audio smooth).\n *\n * Two questions a browser can't answer:\n *\n * 1. *Does the impairment follow the source?* If every receiver of Alice's microphone is concealing\n * ~20% of samples while every receiver of Bob's is at ~0.1%, the fault is on Alice's path, not on\n * the receivers.\n * 2. *Is the whole call's audio delivery under pressure?* One receiver with a huge jitter buffer is\n * their own network; fifteen of twenty at once is shared.\n */\nexport class AudioImpairmentFanOutDetector implements Detector {\n\tpublic readonly name = 'audio-impairment-fan-out-detector';\n\n\tprivate readonly _config: AudioImpairmentFanOutDetectorConfig;\n\tprivate readonly _aggregator: TrackDistributionAggregator;\n\tprivate readonly _trackStreaks = new Map<string, number>();\n\tprivate _callStreak = 0;\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<AudioImpairmentFanOutDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._aggregator = new TrackDistributionAggregator(\n\t\t\t_call,\n\t\t\t{ ...defaultReceiverHealthThresholds, ...config.thresholds },\n\t\t);\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\t\tconst distributions = this._aggregator.aggregate().filter((d) => d.kind === 'audio');\n\t\tconst seen = new Set<string>();\n\t\tconst callJitterBufferDelays: number[] = [];\n\t\tlet stressedReceivers = 0;\n\t\tlet totalReceivers = 0;\n\n\t\tfor (const distribution of distributions) {\n\t\t\tseen.add(distribution.trackId);\n\n\t\t\tfor (const receiver of distribution.receivers) {\n\t\t\t\ttotalReceivers += 1;\n\t\t\t\tif (receiver.jitterBufferDelayInMs !== undefined) {\n\t\t\t\t\tcallJitterBufferDelays.push(receiver.jitterBufferDelayInMs);\n\t\t\t\t\tif (this._config.jitterBufferDelayInMs < receiver.jitterBufferDelayInMs) stressedReceivers += 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (distribution.numberOfReceivers < this._config.minReceivers) {\n\t\t\t\tthis._trackStreaks.delete(distribution.trackId);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst affectedRatio = distribution.concealment.affectedReceivers / distribution.numberOfReceivers;\n\n\t\t\tif (affectedRatio < this._config.affectedRatioThreshold) {\n\t\t\t\tthis._trackStreaks.delete(distribution.trackId);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst ticks = (this._trackStreaks.get(distribution.trackId) ?? 0) + 1;\n\n\t\t\tthis._trackStreaks.set(distribution.trackId, ticks);\n\n\t\t\tif (ticks === this._config.consecutiveTicks) {\n\t\t\t\tthis._call.addIssue({\n\t\t\t\t\ttype: AudioImpairmentFanOutTypes.publishedAudioDegradedForMajority,\n\t\t\t\t\ttimestamp: now,\n\t\t\t\t\tpayload: JSON.stringify({\n\t\t\t\t\t\ttype: AudioImpairmentFanOutTypes.publishedAudioDegradedForMajority,\n\t\t\t\t\t\ttrackId: distribution.trackId,\n\t\t\t\t\t\tpublisherClientId: distribution.publisher.clientId,\n\t\t\t\t\t\tpublisherHealthy: distribution.publisher.healthy,\n\t\t\t\t\t\treceivers: distribution.numberOfReceivers,\n\t\t\t\t\t\taffectedReceivers: distribution.concealment.affectedReceivers,\n\t\t\t\t\t\taffectedRatio,\n\t\t\t\t\t\tconcealmentRatio: distribution.concealmentRatio,\n\t\t\t\t\t\tjitterBufferDelayInMs: distribution.jitterBufferDelayInMs,\n\t\t\t\t\t\taffectedClientIds: distribution.receivers\n\t\t\t\t\t\t\t.filter((r) => this._aggregator.thresholds.concealmentRatio <= (r.concealmentRatio ?? 0))\n\t\t\t\t\t\t\t.map((r) => r.clientId),\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const trackId of [ ...this._trackStreaks.keys() ]) {\n\t\t\tif (!seen.has(trackId)) this._trackStreaks.delete(trackId);\n\t\t}\n\n\t\tthis._evaluateCallWide(now, totalReceivers, stressedReceivers, callJitterBufferDelays);\n\t}\n\n\tpublic close(): void {\n\t\tthis._trackStreaks.clear();\n\t\tthis._callStreak = 0;\n\t}\n\n\tprivate _evaluateCallWide(now: number, totalReceivers: number, stressedReceivers: number, delays: number[]) {\n\t\tif (totalReceivers < this._config.minCallReceivers) {\n\t\t\tthis._callStreak = 0;\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst stressedRatio = stressedReceivers / totalReceivers;\n\n\t\tif (stressedRatio < this._config.affectedRatioThreshold) {\n\t\t\tthis._callStreak = 0;\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis._callStreak += 1;\n\n\t\tif (this._callStreak !== this._config.consecutiveTicks) return;\n\n\t\tthis._call.addIssue({\n\t\t\ttype: AudioImpairmentFanOutTypes.callWideAudioJitterBufferStress,\n\t\t\ttimestamp: now,\n\t\t\tpayload: JSON.stringify({\n\t\t\t\ttype: AudioImpairmentFanOutTypes.callWideAudioJitterBufferStress,\n\t\t\t\tcallId: this._call.callId,\n\t\t\t\taudioReceivers: totalReceivers,\n\t\t\t\tstressedReceivers,\n\t\t\t\tstressedRatio,\n\t\t\t\tjitterBufferDelayInMs: {\n\t\t\t\t\tmedian: percentile(delays, 0.5),\n\t\t\t\t\tp95: percentile(delays, 0.95),\n\t\t\t\t},\n\t\t\t}),\n\t\t});\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport type { ObserverEvents } from '../ObserverEvents';\nimport { SlidingWindow } from '../utils/stats';\n\nexport const IceDisruptionTypes = {\n\t/** Many participants lost/failed their ICE connection inside the same window. */\n\tcallIceDisruption: 'CALL_ICE_DISRUPTION',\n} as const;\n\nexport type IceDisruptionDetectorConfig = {\n\n\t/** Minimum participants before a ratio is meaningful. Default `3`. */\n\tminClients: number;\n\n\t/** Fraction of participants that must be disrupted within the window. Default `0.5`. */\n\taffectedRatioThreshold: number;\n\n\t/** Correlation window (ms). Default `10_000`. */\n\twindowMs: number;\n\n\t/** Re-arm time (ms) before raising again. Default `60_000`. */\n\tcooldownMs: number;\n};\n\nconst defaultConfig: IceDisruptionDetectorConfig = {\n\tminClients: 3,\n\taffectedRatioThreshold: 0.5,\n\twindowMs: 10_000,\n\tcooldownMs: 60_000,\n};\n\n/** The transitions treated as a disruption. */\nconst disruptedStates = new Set([ 'disconnected', 'failed' ]);\n\n/**\n * Detects an **ICE disruption storm**: many participants of a call losing connectivity inside the\n * same short window.\n *\n * One client losing ICE is routine (they walked out of Wi-Fi range). Twenty-eight of thirty-five\n * doing it within five seconds is an infrastructure event, and that conclusion is only reachable by\n * correlating clients — which is the whole point of doing it here rather than in the browser.\n *\n * ### Prefer the issue-driven path\n *\n * This detector works from **raw ICE state transitions**, which is the fallback for clients that do\n * not report issues. If your clients run client-monitor-js >= 4.6.0, prefer\n * `ConcurrentIssueDetector` configured with the ICE issue types instead:\n *\n * ```ts\n * new ConcurrentIssueDetector(observedCall, {\n * issueTypes: [ 'ice-disconnected', 'ice-connection-failed', 'ice-transport-stalled', 'unstable-ice-path' ],\n * });\n * ```\n *\n * The client's own detector is better at deciding *whether* a transport is really disrupted: it\n * raises `ice-disconnected` only once `disconnected` has persisted past a threshold, so the transient\n * blips ICE routinely heals on its own never produce an issue at all, and it distinguishes a terminal\n * `failed` from a stalled transport from an unstable path. This detector cannot make those\n * distinctions — a raw `disconnected` that recovers in 200 ms looks identical to one that never does.\n * It also gains resolution intervals, so \"they all recovered together\" becomes observable.\n *\n * ### Why this one subscribes to the bus\n *\n * ICE transitions are discrete events that can occur and revert between two `update()` ticks;\n * polling `iceConnectionState` per tick would miss short flaps. It therefore implements `close()`\n * to drop its listeners (called automatically when the call closes or the detector is removed).\n */\nexport class IceDisruptionDetector implements Detector {\n\tpublic readonly name = 'ice-disruption-detector';\n\n\tprivate readonly _config: IceDisruptionDetectorConfig;\n\n\t/** clientId -> the last time that client was seen disrupted, inside the window. */\n\tprivate readonly _disruptions: SlidingWindow<string>;\n\tprivate _lastRaisedAt = 0;\n\tprivate readonly _onIceStateChanged: (payload: ObserverEvents['ice-connection-state-changed'][0]) => void;\n\tprivate readonly _onConnectionStateChanged: (payload: ObserverEvents['connection-state-changed'][0]) => void;\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<IceDisruptionDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._disruptions = new SlidingWindow<string>(this._config.windowMs);\n\n\t\tconst record = ({ observedCall, observedClient, state }: { observedCall: ObservedCall, observedClient: { clientId: string }, state: string }) => {\n\t\t\t// The bus is observer-wide; only take events belonging to our call.\n\t\t\tif (observedCall !== this._call) return;\n\t\t\tif (!disruptedStates.has(state)) return;\n\n\t\t\tthis._disruptions.add(observedClient.clientId);\n\t\t};\n\n\t\tthis._onIceStateChanged = record;\n\t\tthis._onConnectionStateChanged = record;\n\n\t\t_call.observer.on('ice-connection-state-changed', this._onIceStateChanged);\n\t\t_call.observer.on('connection-state-changed', this._onConnectionStateChanged);\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\t\tconst affected = new Set(this._disruptions.values(now));\n\t\tconst numberOfClients = this._call.observedClients.size;\n\n\t\tif (numberOfClients < this._config.minClients) return;\n\t\tif (affected.size === 0) return;\n\n\t\tconst affectedRatio = affected.size / numberOfClients;\n\n\t\tif (affectedRatio < this._config.affectedRatioThreshold) return;\n\t\tif (now - this._lastRaisedAt < this._config.cooldownMs) return;\n\n\t\tthis._lastRaisedAt = now;\n\n\t\tthis._call.addIssue({\n\t\t\ttype: IceDisruptionTypes.callIceDisruption,\n\t\t\ttimestamp: now,\n\t\t\tpayload: JSON.stringify({\n\t\t\t\ttype: IceDisruptionTypes.callIceDisruption,\n\t\t\t\tcallId: this._call.callId,\n\t\t\t\tclients: numberOfClients,\n\t\t\t\taffectedClients: affected.size,\n\t\t\t\taffectedRatio,\n\t\t\t\taffectedClientIds: [ ...affected ],\n\t\t\t\twindowMs: this._config.windowMs,\n\t\t\t}),\n\t\t});\n\t}\n\n\tpublic close(): void {\n\t\tthis._call.observer.off('ice-connection-state-changed', this._onIceStateChanged);\n\t\tthis._call.observer.off('connection-state-changed', this._onConnectionStateChanged);\n\t\tthis._disruptions.clear();\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { Observer } from '../Observer';\nimport type { ObservedPeerConnection } from '../ObservedPeerConnection';\nimport { StatsSummary, summarize } from './../utils/stats';\n\nexport const TurnServerHealthTypes = {\n\t/** One TURN server's clients are degraded while other servers' clients are fine. */\n\tturnServerDegraded: 'TURN_SERVER_DEGRADED',\n} as const;\n\nexport type TurnServerHealthDetectorConfig = {\n\n\t/** Minimum clients on a server before a ratio is meaningful. Default `5`. */\n\tminClientsPerServer: number;\n\n\t/** Fraction of a server's clients that must be degraded. Default `0.5`. */\n\tdegradedRatioThreshold: number;\n\n\t/** RTT (ms) above which a relayed peer connection counts as degraded. Default `400`. */\n\trttInMs: number;\n\n\t/** Inbound loss fraction above which a relayed peer connection counts as degraded. Default `0.03`. */\n\tfractionLost: number;\n\n\t/** Consecutive ticks the condition must hold before raising. Default `2`. */\n\tconsecutiveTicks: number;\n\n\t/** Re-arm time (ms) before raising again for the same server. Default `60_000`. */\n\tcooldownMs: number;\n};\n\nconst defaultConfig: TurnServerHealthDetectorConfig = {\n\tminClientsPerServer: 5,\n\tdegradedRatioThreshold: 0.5,\n\trttInMs: 400,\n\tfractionLost: 0.03,\n\tconsecutiveTicks: 2,\n\tcooldownMs: 60_000,\n};\n\n/** The per-server view this detector builds. */\nexport type TurnServerHealth = {\n\tserverUrl: string;\n\tpeerConnections: number;\n\tdegradedPeerConnections: number;\n\tdegradedRatio: number;\n\trttInMs?: StatsSummary;\n\tfractionLost?: StatsSummary;\n\taffectedClientIds: string[];\n};\n\n/**\n * An **observer-level** detector that groups relayed peer connections by the TURN server carrying\n * them and compares the servers against each other.\n *\n * Counting TURN usage is not useful on its own; knowing that `turn-eu-1` has 22 of 30 clients in\n * trouble while `turn-eu-2` has 1 of 34 is. Because the comparison spans calls, it lives on\n * `observer.detectors` and raises `observer-issue` — a single actionable alert instead of fifty\n * per-client ones.\n */\nexport class TurnServerHealthDetector implements Detector {\n\tpublic readonly name = 'turn-server-health-detector';\n\n\tprivate readonly _config: TurnServerHealthDetectorConfig;\n\tprivate readonly _streaks = new Map<string, number>();\n\tprivate readonly _lastRaisedAt = new Map<string, number>();\n\n\t/** The per-server rollup computed on the most recent `update()`. */\n\tpublic lastServers: TurnServerHealth[] = [];\n\n\tpublic constructor(\n\t\tprivate readonly _observer: Observer,\n\t\tconfig: Partial<TurnServerHealthDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\n\t\t// Compute every server's health FIRST, so each finding can carry the full cross-server\n\t\t// comparison (evaluating while building the list would leave the first server without peers).\n\t\tthis.lastServers = [ ...this._observer.observedTURN.servers ]\n\t\t\t.map(([ serverUrl, server ]) => this._serverHealth(serverUrl, server.observedPeerConnections));\n\n\t\tfor (const health of this.lastServers) {\n\t\t\tconst serverUrl = health.serverUrl;\n\n\t\t\tif (health.peerConnections < this._config.minClientsPerServer) {\n\t\t\t\tthis._streaks.delete(serverUrl);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (health.degradedRatio < this._config.degradedRatioThreshold) {\n\t\t\t\tthis._streaks.delete(serverUrl);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst ticks = (this._streaks.get(serverUrl) ?? 0) + 1;\n\n\t\t\tthis._streaks.set(serverUrl, ticks);\n\n\t\t\tif (ticks < this._config.consecutiveTicks) continue;\n\t\t\tif (now - (this._lastRaisedAt.get(serverUrl) ?? 0) < this._config.cooldownMs) continue;\n\n\t\t\tthis._lastRaisedAt.set(serverUrl, now);\n\n\t\t\t// Comparison context: how the other servers are doing right now.\n\t\t\tconst peers = this.lastServers\n\t\t\t\t.filter((s) => s.serverUrl !== serverUrl)\n\t\t\t\t.map((s) => ({ serverUrl: s.serverUrl, peerConnections: s.peerConnections, degradedRatio: s.degradedRatio }));\n\n\t\t\tthis._observer.addIssue({\n\t\t\t\ttype: TurnServerHealthTypes.turnServerDegraded,\n\t\t\t\ttimestamp: now,\n\t\t\t\tpayload: JSON.stringify({ type: TurnServerHealthTypes.turnServerDegraded, ...health, otherServers: peers }),\n\t\t\t});\n\t\t}\n\n\t\t// forget servers that disappeared\n\t\tfor (const serverUrl of [ ...this._streaks.keys() ]) {\n\t\t\tif (!this.lastServers.some((s) => s.serverUrl === serverUrl)) this._streaks.delete(serverUrl);\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tthis._streaks.clear();\n\t\tthis._lastRaisedAt.clear();\n\t}\n\n\tprivate _serverHealth(serverUrl: string, peerConnections: Map<string, ObservedPeerConnection>): TurnServerHealth {\n\t\tconst rtts: number[] = [];\n\t\tconst losses: number[] = [];\n\t\tconst affectedClientIds = new Set<string>();\n\t\tlet degraded = 0;\n\n\t\tfor (const peerConnection of peerConnections.values()) {\n\t\t\tconst rttInMs = peerConnection.currentRttInMs;\n\t\t\tlet lostPackets = 0;\n\t\t\tlet receivedPackets = 0;\n\n\t\t\tfor (const rtp of peerConnection.observedInboundRtps.values()) {\n\t\t\t\tlostPackets += rtp.deltaLostPackets;\n\t\t\t\treceivedPackets += rtp.deltaReceivedPackets;\n\t\t\t}\n\n\t\t\tconst total = lostPackets + receivedPackets;\n\t\t\tconst fractionLost = 0 < total ? lostPackets / total : undefined;\n\n\t\t\tif (rttInMs !== undefined) rtts.push(rttInMs);\n\t\t\tif (fractionLost !== undefined) losses.push(fractionLost);\n\n\t\t\tif (this._config.rttInMs < (rttInMs ?? 0) || this._config.fractionLost < (fractionLost ?? 0)) {\n\t\t\t\tdegraded += 1;\n\t\t\t\taffectedClientIds.add(peerConnection.client.clientId);\n\t\t\t}\n\t\t}\n\n\t\tconst count = peerConnections.size;\n\n\t\treturn {\n\t\t\tserverUrl,\n\t\t\tpeerConnections: count,\n\t\t\tdegradedPeerConnections: degraded,\n\t\t\tdegradedRatio: 0 < count ? degraded / count : 0,\n\t\t\trttInMs: summarize(rtts),\n\t\t\tfractionLost: summarize(losses),\n\t\t\taffectedClientIds: [ ...affectedClientIds ],\n\t\t};\n\t}\n}\n","import type { ObservedCall } from '../ObservedCall';\nimport type { Observer } from '../Observer';\nimport type { ActiveClientIssue } from '../common/ActiveClientIssue';\n\n/** A snapshot of everyone currently reporting one issue type. */\nexport type IssueCohort = {\n\n\t/** The issue type, without the `-resolved` suffix. */\n\ttype: string;\n\n\t/** The open intervals of that type, one per (client, key). */\n\tissues: ActiveClientIssue[];\n\n\t/** Distinct clients with at least one open interval of this type. */\n\tclientIds: string[];\n\n\t/** `clientIds.length / totalClients` (0..1). */\n\taffectedRatio: number;\n\n\t/** Clients considered for the ratio. */\n\ttotalClients: number;\n\n\t/**\n\t * Spread of the onsets, in **observer** time (ms) — `max(observedAt) - min(observedAt)`.\n\t *\n\t * Measured on the observer clock on purpose: `raisedAt` comes from each client's own clock, and\n\t * comparing those across machines makes clock skew look like an infrastructure event. A small\n\t * spread means the issues began together, which is the signature of a shared cause.\n\t */\n\tonsetSpreadInMs: number;\n\n\t/** The earliest onset (observer clock). */\n\tfirstObservedAt: number;\n};\n\n/** Options controlling how long an unresolved issue is trusted. */\nexport type IssueRegistryConfig = {\n\n\t/**\n\t * Drop an active issue this long after it was opened, even without a resolution (ms).\n\t *\n\t * A safety net for the case the lifecycle can't cover: a client that dies without its monitor\n\t * running `close()` never sends the `-resolved` companion, and a stuck \"active\" issue would make\n\t * every concurrency detector fire forever. Default `120_000`.\n\t */\n\tmaxIssueAgeInMs: number;\n};\n\nconst defaultConfig: IssueRegistryConfig = {\n\tmaxIssueAgeInMs: 120_000,\n};\n\n/**\n * Read-side index over the **active** client issues in a call (or across an observer's calls).\n *\n * `ObservedClient.activeIssues` holds the raw per-client state; this puts the questions detectors\n * actually ask on top of it:\n *\n * - *who currently has issue X?* → {@link cohortOf}\n * - *which issue types are shared by several clients right now?* → {@link cohorts}\n * - *which receivers of this published track are broken?* → {@link byTrackIds}\n *\n * The distinction that matters is **concurrency**. A window-based count (\"N clients reported\n * congestion in the last 10 s\") is a heuristic that has to guess whether the symptoms are still\n * happening; an active-issue set is ground truth, because the client tells the server when the\n * episode ends. Overlapping intervals are much stronger evidence of a common cause than\n * near-in-time reports.\n *\n * It is a *view*, holding no state of its own beyond configuration, so it can be constructed per\n * detector and queried on every `update()`.\n */\nexport class IssueRegistry {\n\tprivate readonly _config: IssueRegistryConfig;\n\n\tpublic constructor(\n\t\tprivate readonly _source: ObservedCall | Observer,\n\t\tconfig: Partial<IssueRegistryConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t}\n\n\t/** Every open issue in scope, with stale entries filtered out. */\n\tpublic activeIssues(now = Date.now()): ActiveClientIssue[] {\n\t\tconst result: ActiveClientIssue[] = [];\n\n\t\tfor (const client of this._clients()) {\n\t\t\tfor (const issue of client.activeIssues.values()) {\n\t\t\t\tif (this._config.maxIssueAgeInMs < now - issue.observedAt) continue;\n\t\t\t\tresult.push(issue);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/** The number of clients in scope — the denominator for every ratio. */\n\tpublic get totalClients(): number {\n\t\tlet count = 0;\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\tfor (const client of this._clients()) count += 1;\n\n\t\treturn count;\n\t}\n\n\t/** The cohort for one issue type (empty `issues` when nobody has it open). */\n\tpublic cohortOf(type: string, now = Date.now()): IssueCohort {\n\t\treturn this._toCohort(type, this.activeIssues(now).filter((issue) => issue.type === type));\n\t}\n\n\t/** One cohort per issue type currently open somewhere in scope, largest first. */\n\tpublic cohorts(now = Date.now()): IssueCohort[] {\n\t\tconst byType = new Map<string, ActiveClientIssue[]>();\n\n\t\tfor (const issue of this.activeIssues(now)) {\n\t\t\tconst list = byType.get(issue.type);\n\n\t\t\tif (list) list.push(issue);\n\t\t\telse byType.set(issue.type, [ issue ]);\n\t\t}\n\n\t\treturn [ ...byType.entries() ]\n\t\t\t.map(([ type, issues ]) => this._toCohort(type, issues))\n\t\t\t.sort((a, b) => b.clientIds.length - a.clientIds.length);\n\t}\n\n\t/**\n\t * Open issues attributed to any of the given track ids — the join that turns a receiver-side\n\t * issue into a statement about a **published** track (`trackId` → inbound track →\n\t * `remoteOutboundTrack` → publisher).\n\t */\n\tpublic byTrackIds(trackIds: Iterable<string>, now = Date.now()): ActiveClientIssue[] {\n\t\tconst wanted = new Set(trackIds);\n\n\t\treturn this.activeIssues(now).filter((issue) => issue.trackId !== undefined && wanted.has(issue.trackId));\n\t}\n\n\t/** Open issues reported by one client. */\n\tpublic byClientId(clientId: string, now = Date.now()): ActiveClientIssue[] {\n\t\treturn this.activeIssues(now).filter((issue) => issue.clientId === clientId);\n\t}\n\n\tprivate _toCohort(type: string, issues: ActiveClientIssue[]): IssueCohort {\n\t\tconst clientIds = [ ...new Set(issues.map((issue) => issue.clientId)) ];\n\t\tconst onsets = issues.map((issue) => issue.observedAt);\n\t\tconst totalClients = this.totalClients;\n\n\t\treturn {\n\t\t\ttype,\n\t\t\tissues,\n\t\t\tclientIds,\n\t\t\ttotalClients,\n\t\t\taffectedRatio: 0 < totalClients ? clientIds.length / totalClients : 0,\n\t\t\tonsetSpreadInMs: 0 < onsets.length ? Math.max(...onsets) - Math.min(...onsets) : 0,\n\t\t\tfirstObservedAt: 0 < onsets.length ? Math.min(...onsets) : 0,\n\t\t};\n\t}\n\n\t/** Works for both scopes: a call yields its clients, an observer yields every call's clients. */\n\tprivate *_clients() {\n\t\tconst source = this._source as unknown as {\n\t\t\tobservedClients?: ObservedCall['observedClients'],\n\t\t\tobservedCalls?: Observer['observedCalls'],\n\t\t};\n\n\t\tif (source.observedClients) {\n\t\t\tyield* source.observedClients.values();\n\t\t} else if (source.observedCalls) {\n\t\t\tfor (const call of source.observedCalls.values()) yield* call.observedClients.values();\n\t\t}\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport type { Observer } from '../Observer';\nimport { IssueCohort, IssueRegistry, IssueRegistryConfig } from '../utils/IssueRegistry';\n\nexport const ConcurrentIssueTypes = {\n\t/** Several participants have the same issue open **at the same time**. */\n\tconcurrentClientIssues: 'CONCURRENT_CLIENT_ISSUES',\n\n\t/** Those issues also *began* together — the signature of one infrastructure event. */\n\tissueOnsetBurst: 'ISSUE_ONSET_BURST',\n} as const;\n\nexport type ConcurrentIssueDetectorConfig = {\n\n\t/**\n\t * Only consider these issue types. Empty (default) means every type the clients report — which\n\t * is usually what you want, since the detector is generic over the client's vocabulary.\n\t */\n\tissueTypes: string[];\n\n\t/** Minimum participants in scope before a ratio is meaningful. Default `3`. */\n\tminClients: number;\n\n\t/** Minimum distinct clients sharing the open issue. Default `3`. */\n\tminAffectedClients: number;\n\n\t/** Fraction of participants that must share it. Default `0.5`. */\n\taffectedRatioThreshold: number;\n\n\t/**\n\t * When the onsets of a qualifying cohort fall within this span (ms), the finding is escalated to\n\t * `ISSUE_ONSET_BURST` — they didn't just overlap, they started together. Default `2_000`.\n\t */\n\tonsetBurstWindowInMs: number;\n\n\t/** Re-arm time (ms) per issue type. Default `60_000`. */\n\tcooldownMs: number;\n\n\t/** Forwarded to the {@link IssueRegistry} (stale-issue expiry). */\n\tregistry?: Partial<IssueRegistryConfig>;\n};\n\nconst defaultConfig: ConcurrentIssueDetectorConfig = {\n\tissueTypes: [],\n\tminClients: 3,\n\tminAffectedClients: 3,\n\taffectedRatioThreshold: 0.5,\n\tonsetBurstWindowInMs: 2_000,\n\tcooldownMs: 60_000,\n};\n\n/**\n * Raises a finding when **several participants have the same issue open simultaneously**.\n *\n * This is the generic replacement for a family of symptom-specific detectors. The client already\n * decides *what* is wrong for itself — `congestion`, `ice-disconnected`, `audio-concealment`,\n * `video-decoder-overloaded`, and so on — with detectors that have hysteresis and multi-signal\n * confirmation behind them. Re-deriving those verdicts from raw counters server-side would be\n * strictly worse. What the server uniquely knows is *how many other participants are in the same\n * state right now*, which is exactly the difference between \"one person's Wi-Fi\" and \"our problem\".\n *\n * Concurrency is judged from the **active issue set** (open interval per key), not from a sliding\n * window of recent reports. That distinction matters: a window has to guess whether a symptom is\n * still happening, whereas an interval is closed by the client when the episode actually ends\n * (client-monitor-js >= 4.6.0 ships the `<type>-resolved` companion for this purpose).\n *\n * When the onsets also cluster inside `onsetBurstWindowInMs`, the finding is escalated to\n * `ISSUE_ONSET_BURST`: participants degrading *together within a couple of seconds* is far more\n * likely to be a deploy, a TURN failover or a link flap than a coincidence. Onsets are compared on\n * the **observer clock** (`observedAt`), never on client clocks, because clock skew between\n * machines would otherwise masquerade as a synchronized event.\n *\n * Works at both scopes — pass an `ObservedCall` for \"this meeting\", or the `Observer` for\n * \"everything this SFU is serving\".\n */\nexport class ConcurrentIssueDetector implements Detector {\n\tpublic readonly name = 'concurrent-issue-detector';\n\n\tprivate readonly _config: ConcurrentIssueDetectorConfig;\n\tprivate readonly _registry: IssueRegistry;\n\tprivate readonly _lastRaisedAt = new Map<string, number>();\n\tprivate readonly _isObserverScope: boolean;\n\n\t/** The cohorts that qualified on the most recent `update()`. */\n\tpublic lastCohorts: IssueCohort[] = [];\n\n\tpublic constructor(\n\t\tprivate readonly _scope: ObservedCall | Observer,\n\t\tconfig: Partial<ConcurrentIssueDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._registry = new IssueRegistry(_scope, config.registry);\n\t\tthis._isObserverScope = (_scope as Partial<Observer>).observedCalls !== undefined;\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\t\tconst wanted = new Set(this._config.issueTypes);\n\t\tconst cohorts = this._registry.cohorts(now)\n\t\t\t.filter((cohort) => wanted.size === 0 || wanted.has(cohort.type));\n\n\t\tthis.lastCohorts = [];\n\n\t\tif (this._registry.totalClients < this._config.minClients) return;\n\n\t\tfor (const cohort of cohorts) {\n\t\t\tif (cohort.clientIds.length < this._config.minAffectedClients) continue;\n\t\t\tif (cohort.affectedRatio < this._config.affectedRatioThreshold) continue;\n\n\t\t\tthis.lastCohorts.push(cohort);\n\n\t\t\tif (now - (this._lastRaisedAt.get(cohort.type) ?? 0) < this._config.cooldownMs) continue;\n\n\t\t\tthis._lastRaisedAt.set(cohort.type, now);\n\n\t\t\tconst burst = cohort.onsetSpreadInMs <= this._config.onsetBurstWindowInMs;\n\t\t\tconst type = burst ? ConcurrentIssueTypes.issueOnsetBurst : ConcurrentIssueTypes.concurrentClientIssues;\n\n\t\t\tthis._raise(type, {\n\t\t\t\ttype,\n\t\t\t\tissueType: cohort.type,\n\t\t\t\tscope: this._isObserverScope ? 'observer' : 'call',\n\t\t\t\tclients: cohort.totalClients,\n\t\t\t\taffectedClients: cohort.clientIds.length,\n\t\t\t\taffectedRatio: cohort.affectedRatio,\n\t\t\t\taffectedClientIds: cohort.clientIds,\n\t\t\t\tonsetSpreadInMs: cohort.onsetSpreadInMs,\n\t\t\t\tonsetBurst: burst,\n\t\t\t\tfirstObservedAt: cohort.firstObservedAt,\n\t\t\t}, now);\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tthis._lastRaisedAt.clear();\n\t\tthis.lastCohorts = [];\n\t}\n\n\tprivate _raise(type: string, payload: Record<string, unknown>, now: number) {\n\t\tthis._scope.addIssue({ type, timestamp: now, payload: JSON.stringify(payload) });\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport type { ObservedOutboundTrack } from '../ObservedOutboundTrack';\nimport { IssueRegistry, IssueRegistryConfig } from '../utils/IssueRegistry';\nimport { TrackDistributionAggregator } from '../utils/TrackDistributionAggregator';\n\nexport const IssueFanOutTypes = {\n\t/** Most receivers of one published track have the same issue open → the fault follows the source. */\n\tpublishedTrackIssueFanOut: 'PUBLISHED_TRACK_ISSUE_FAN_OUT',\n\n\t/** Exactly one receiver of a track has it → that receiver's own problem. */\n\tsingleReceiverIssue: 'SINGLE_RECEIVER_ISSUE',\n} as const;\n\nexport type IssueFanOutDetectorConfig = {\n\n\t/** Only consider these issue types. Empty (default) = every type the receivers report. */\n\tissueTypes: string[];\n\n\t/** Minimum receivers of the track before a ratio is meaningful. Default `3`. */\n\tminReceivers: number;\n\n\t/** Fraction of a track's receivers that must share the issue. Default `0.6`. */\n\taffectedRatioThreshold: number;\n\n\t/** Also report the \"only one receiver is affected\" case. Default `true`. */\n\treportSingleReceiver: boolean;\n\n\t/** Re-arm time (ms) per (track, issue type). Default `60_000`. */\n\tcooldownMs: number;\n\n\tregistry?: Partial<IssueRegistryConfig>;\n};\n\nconst defaultConfig: IssueFanOutDetectorConfig = {\n\tissueTypes: [],\n\tminReceivers: 3,\n\taffectedRatioThreshold: 0.6,\n\treportSingleReceiver: true,\n\tcooldownMs: 60_000,\n};\n\n/**\n * Attributes **client-reported issues to the published track they are about**, then asks how far\n * the problem fans out across that track's receivers.\n *\n * The join is what makes this possible: a receiver-side issue payload carries `trackId` (the client\n * detectors report it for every track-scoped issue), the observer resolves that to an inbound track,\n * and `RemoteTrackResolver` links the inbound track to the `remoteOutboundTrack` that published it.\n * With the whole subscriber set of one source in hand, the verdict is straightforward and is the\n * single most useful thing a server can say:\n *\n * - **most receivers of Alice's track are affected** → the fault is on Alice's path — her uplink, the\n * SFU's ingress, or its forwarding of that stream. Corroborated by whether the publisher's own\n * egress looks healthy.\n * - **one receiver of Alice's track is affected** → that receiver's downlink. Nothing to do with\n * Alice, even though the symptom is reported against her stream.\n *\n * Note this is deliberately generic over the issue vocabulary: `freezed-video-track`,\n * `keyframe-storm`, `audio-concealment`, `video-decoder-overloaded`, `stuck-decoder` and anything a\n * custom client detector invents all fan out the same way, so one mechanism replaces a family of\n * symptom-specific detectors.\n */\nexport class IssueFanOutDetector implements Detector {\n\tpublic readonly name = 'issue-fan-out-detector';\n\n\tprivate readonly _config: IssueFanOutDetectorConfig;\n\tprivate readonly _registry: IssueRegistry;\n\tprivate readonly _aggregator: TrackDistributionAggregator;\n\tprivate readonly _lastRaisedAt = new Map<string, number>();\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<IssueFanOutDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._registry = new IssueRegistry(_call, config.registry);\n\t\tthis._aggregator = new TrackDistributionAggregator(_call);\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\t\tconst wanted = new Set(this._config.issueTypes);\n\n\t\tfor (const distribution of this._aggregator.aggregate()) {\n\t\t\t// The inbound track ids of every subscriber of this published track.\n\t\t\tconst receiverTrackIds = new Map<string, string>();\n\n\t\t\tfor (const receiver of distribution.receivers) {\n\t\t\t\treceiverTrackIds.set(receiver.observedInboundTrack.id, receiver.clientId);\n\t\t\t}\n\n\t\t\tconst issues = this._registry.byTrackIds(receiverTrackIds.keys(), now)\n\t\t\t\t.filter((issue) => wanted.size === 0 || wanted.has(issue.type));\n\n\t\t\tif (issues.length === 0) continue;\n\n\t\t\t// group the open issues by type across this track's receivers\n\t\t\tconst byType = new Map<string, Set<string>>();\n\n\t\t\tfor (const issue of issues) {\n\t\t\t\tconst clientIds = byType.get(issue.type) ?? new Set<string>();\n\n\t\t\t\tclientIds.add(issue.clientId);\n\t\t\t\tbyType.set(issue.type, clientIds);\n\t\t\t}\n\n\t\t\tfor (const [ issueType, clientIds ] of byType) {\n\t\t\t\tconst affectedRatio = clientIds.size / distribution.numberOfReceivers;\n\t\t\t\tconst isFanOut = this._config.minReceivers <= distribution.numberOfReceivers\n\t\t\t\t\t&& this._config.affectedRatioThreshold <= affectedRatio;\n\t\t\t\tconst isSingle = this._config.reportSingleReceiver\n\t\t\t\t\t&& clientIds.size === 1 && 1 < distribution.numberOfReceivers;\n\n\t\t\t\tif (!isFanOut && !isSingle) continue;\n\n\t\t\t\tconst key = `${distribution.trackId}:${issueType}`;\n\n\t\t\t\tif (now - (this._lastRaisedAt.get(key) ?? 0) < this._config.cooldownMs) continue;\n\n\t\t\t\tthis._lastRaisedAt.set(key, now);\n\n\t\t\t\tconst type = isFanOut\n\t\t\t\t\t? IssueFanOutTypes.publishedTrackIssueFanOut\n\t\t\t\t\t: IssueFanOutTypes.singleReceiverIssue;\n\n\t\t\t\tthis._call.addIssue({\n\t\t\t\t\ttype,\n\t\t\t\t\ttimestamp: now,\n\t\t\t\t\tpayload: JSON.stringify({\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tissueType,\n\t\t\t\t\t\ttrackId: distribution.trackId,\n\t\t\t\t\t\tkind: distribution.kind,\n\t\t\t\t\t\tpublisherClientId: distribution.publisher.clientId,\n\t\t\t\t\t\t// The corroborating half: if the source's own egress is clean while its\n\t\t\t\t\t\t// receivers are not, the SFU/forwarding path is implicated rather than the sender.\n\t\t\t\t\t\tpublisherHealthy: distribution.publisher.healthy,\n\t\t\t\t\t\tpublisherReasons: distribution.publisher.reasons,\n\t\t\t\t\t\treceivers: distribution.numberOfReceivers,\n\t\t\t\t\t\taffectedReceivers: clientIds.size,\n\t\t\t\t\t\taffectedRatio,\n\t\t\t\t\t\taffectedClientIds: [ ...clientIds ],\n\t\t\t\t\t\t// metric evidence alongside the client's verdict\n\t\t\t\t\t\tfractionLost: distribution.fractionLost,\n\t\t\t\t\t\tbitrate: distribution.bitrate,\n\t\t\t\t\t\tfreezes: distribution.freezes,\n\t\t\t\t\t\tplis: distribution.plis,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tthis._lastRaisedAt.clear();\n\t}\n\n\t/** Exposed for tests/dashboards: the distributions this detector reasons over. */\n\tpublic distributionsOf(): ObservedOutboundTrack[] {\n\t\treturn this._aggregator.aggregate().map((d) => d.publisher.observedOutboundTrack);\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport { TrackDistributionAggregator } from '../utils/TrackDistributionAggregator';\nimport { SlidingWindow, percentile } from '../utils/stats';\n\nexport const WorstReceiverContagionTypes = {\n\t/**\n\t * A publisher's sending bitrate is tracking its **worst** receiver — one bad downlink is\n\t * dragging the quality everyone else gets.\n\t */\n\tworstReceiverContagion: 'WORST_RECEIVER_CONTAGION',\n} as const;\n\nexport type WorstReceiverContagionDetectorConfig = {\n\n\t/** Minimum receivers before the comparison means anything. Default `3`. */\n\tminReceivers: number;\n\n\t/** Observation window (ms) the correlation is computed over. Default `30_000`. */\n\twindowMs: number;\n\n\t/** Minimum samples inside the window before judging. Default `4`. */\n\tminSamples: number;\n\n\t/**\n\t * How closely the publisher's bitrate must track the worst receiver's, relative to the spread\n\t * between the worst and the median receiver. Default `0.75`.\n\t */\n\ttrackingRatioThreshold: number;\n\n\t/**\n\t * The worst receiver must be this much worse than the median receiver before the situation even\n\t * counts as \"one bad apple\" (0..1 of the median). Default `0.5` — i.e. at most half.\n\t */\n\toutlierRatioThreshold: number;\n\n\t/** Re-arm time (ms) per track. Default `120_000`. */\n\tcooldownMs: number;\n};\n\nconst defaultConfig: WorstReceiverContagionDetectorConfig = {\n\tminReceivers: 3,\n\twindowMs: 30_000,\n\tminSamples: 4,\n\ttrackingRatioThreshold: 0.75,\n\toutlierRatioThreshold: 0.5,\n\tcooldownMs: 120_000,\n};\n\ntype TrackSample = {\n\tpublisherBitrate: number;\n\tworstReceiverBitrate: number;\n\tmedianReceiverBitrate: number;\n};\n\n/**\n * Detects the classic SFU misconfiguration: **the sender adapting to the worst receiver**.\n *\n * In a correctly built SFU the RTCP feedback loop is *terminated* at the server — each receiver's\n * reports drive what that receiver is sent, and the publisher encodes for the server, not for the\n * unluckiest participant. When the loop is instead relayed end to end, the publisher's bandwidth\n * estimate collapses to the minimum across all receivers, so a single participant on a bad 3G link\n * silently downgrades the stream *everyone* sees. Simulcast exists precisely to prevent this\n * \"lowest common denominator\" outcome, and its absence (or an SFU that forwards RR/REMB verbatim)\n * reproduces it.\n *\n * The signature is a correlation, not a threshold, so it is judged over a window: the publisher's\n * outbound bitrate moving in lockstep with the *worst* receiver's inbound bitrate, while the median\n * receiver has ample headroom. A publisher that drops because of its own uplink or CPU shows no such\n * relationship — every receiver falls together and there is no outlier to track.\n *\n * This is arguably the most valuable thing an observer can detect, because the damage is invisible\n * from every individual endpoint: the publisher sees \"my bitrate went down\", each healthy receiver\n * sees \"my video got worse\", and nobody can see the causal link except the server.\n */\nexport class WorstReceiverContagionDetector implements Detector {\n\tpublic readonly name = 'worst-receiver-contagion-detector';\n\n\tprivate readonly _config: WorstReceiverContagionDetectorConfig;\n\tprivate readonly _aggregator: TrackDistributionAggregator;\n\tprivate readonly _windows = new Map<string, SlidingWindow<TrackSample>>();\n\tprivate readonly _lastRaisedAt = new Map<string, number>();\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<WorstReceiverContagionDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._aggregator = new TrackDistributionAggregator(_call);\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const distribution of this._aggregator.aggregate()) {\n\t\t\tseen.add(distribution.trackId);\n\n\t\t\tif (distribution.numberOfReceivers < this._config.minReceivers) continue;\n\t\t\tif (distribution.publisher.bitrate <= 0) continue;\n\n\t\t\tconst receiverBitrates = distribution.receivers.map((r) => r.bitrate).filter((b) => 0 < b);\n\n\t\t\tif (receiverBitrates.length < this._config.minReceivers) continue;\n\n\t\t\tconst worst = Math.min(...receiverBitrates);\n\t\t\tconst median = percentile(receiverBitrates, 0.5) ?? worst;\n\t\t\tconst window = this._windowOf(distribution.trackId);\n\n\t\t\twindow.add({ publisherBitrate: distribution.publisher.bitrate, worstReceiverBitrate: worst, medianReceiverBitrate: median }, now);\n\n\t\t\tconst samples = window.values(now);\n\n\t\t\tif (samples.length < this._config.minSamples) continue;\n\n\t\t\t// Is there actually an outlier to be dragged down by?\n\t\t\tconst latest = samples[samples.length - 1];\n\t\t\tconst outlierRatio = 0 < latest.medianReceiverBitrate\n\t\t\t\t? latest.worstReceiverBitrate / latest.medianReceiverBitrate\n\t\t\t\t: 1;\n\n\t\t\tif (this._config.outlierRatioThreshold < outlierRatio) continue;\n\n\t\t\tconst tracking = correlation(\n\t\t\t\tsamples.map((s) => s.publisherBitrate),\n\t\t\t\tsamples.map((s) => s.worstReceiverBitrate),\n\t\t\t);\n\t\t\tconst medianTracking = correlation(\n\t\t\t\tsamples.map((s) => s.publisherBitrate),\n\t\t\t\tsamples.map((s) => s.medianReceiverBitrate),\n\t\t\t);\n\n\t\t\t// The publisher must follow the WORST receiver specifically — if it tracks the median\n\t\t\t// just as closely, everyone is simply moving together and nothing is being dragged.\n\t\t\tif (tracking < this._config.trackingRatioThreshold) continue;\n\t\t\tif (tracking <= medianTracking) continue;\n\t\t\tif (now - (this._lastRaisedAt.get(distribution.trackId) ?? 0) < this._config.cooldownMs) continue;\n\n\t\t\tthis._lastRaisedAt.set(distribution.trackId, now);\n\n\t\t\tconst worstReceiver = distribution.receivers.reduce((a, b) => (a.bitrate <= b.bitrate ? a : b));\n\n\t\t\tthis._call.addIssue({\n\t\t\t\ttype: WorstReceiverContagionTypes.worstReceiverContagion,\n\t\t\t\ttimestamp: now,\n\t\t\t\tpayload: JSON.stringify({\n\t\t\t\t\ttype: WorstReceiverContagionTypes.worstReceiverContagion,\n\t\t\t\t\ttrackId: distribution.trackId,\n\t\t\t\t\tkind: distribution.kind,\n\t\t\t\t\tpublisherClientId: distribution.publisher.clientId,\n\t\t\t\t\tpublisherBitrate: distribution.publisher.bitrate,\n\t\t\t\t\tworstReceiverClientId: worstReceiver.clientId,\n\t\t\t\t\tworstReceiverBitrate: latest.worstReceiverBitrate,\n\t\t\t\t\tmedianReceiverBitrate: latest.medianReceiverBitrate,\n\t\t\t\t\toutlierRatio,\n\t\t\t\t\ttrackingWithWorst: tracking,\n\t\t\t\t\ttrackingWithMedian: medianTracking,\n\t\t\t\t\treceivers: distribution.numberOfReceivers,\n\t\t\t\t\twindowMs: this._config.windowMs,\n\t\t\t\t\tsamples: samples.length,\n\t\t\t\t}),\n\t\t\t});\n\t\t}\n\n\t\tfor (const trackId of [ ...this._windows.keys() ]) {\n\t\t\tif (!seen.has(trackId)) this._windows.delete(trackId);\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tthis._windows.clear();\n\t\tthis._lastRaisedAt.clear();\n\t}\n\n\tprivate _windowOf(trackId: string): SlidingWindow<TrackSample> {\n\t\tlet window = this._windows.get(trackId);\n\n\t\tif (!window) {\n\t\t\twindow = new SlidingWindow<TrackSample>(this._config.windowMs);\n\t\t\tthis._windows.set(trackId, window);\n\t\t}\n\n\t\treturn window;\n\t}\n}\n\n/** Pearson correlation, clamped to 0..1 (negative or undefined relationships read as 0). */\nfunction correlation(xs: number[], ys: number[]): number {\n\tconst n = Math.min(xs.length, ys.length);\n\n\tif (n < 2) return 0;\n\n\tconst meanX = xs.reduce((s, v) => s + v, 0) / n;\n\tconst meanY = ys.reduce((s, v) => s + v, 0) / n;\n\tlet covariance = 0;\n\tlet varianceX = 0;\n\tlet varianceY = 0;\n\n\tfor (let i = 0; i < n; i++) {\n\t\tconst dx = xs[i] - meanX;\n\t\tconst dy = ys[i] - meanY;\n\n\t\tcovariance += dx * dy;\n\t\tvarianceX += dx * dx;\n\t\tvarianceY += dy * dy;\n\t}\n\n\tif (varianceX <= 0 || varianceY <= 0) return 0;\n\n\treturn Math.max(0, covariance / Math.sqrt(varianceX * varianceY));\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\nimport { IssueRegistry, IssueRegistryConfig } from '../utils/IssueRegistry';\nimport { TrackDistributionAggregator } from '../utils/TrackDistributionAggregator';\n\nexport const TrackDeliveryMismatchTypes = {\n\t/**\n\t * The source is sending, but **none** of its subscribers are receiving → the media is being lost\n\t * between the publisher and the receivers. In an SFU that means the forwarding path.\n\t */\n\tpublishedTrackNotDelivered: 'PUBLISHED_TRACK_NOT_DELIVERED',\n\n\t/**\n\t * The source is sending and most subscribers are fine, but **some** are dry → those consumers are\n\t * broken individually (in mediasoup, the usual mitigation is recreating the consumer).\n\t */\n\treceiverTrackNotDelivered: 'RECEIVER_TRACK_NOT_DELIVERED',\n\n\t/**\n\t * The source itself stopped producing, so its subscribers being dry is expected and **not** an\n\t * SFU fault. Reported so the other two verdicts can be trusted as *not* being this.\n\t */\n\tpublisherTrackDry: 'PUBLISHER_TRACK_DRY',\n} as const;\n\nexport type TrackDeliveryMismatchDetectorConfig = {\n\n\t/** The receiver-side issue type meaning \"no media arriving\". Default `'dry-inbound-track'`. */\n\tdryInboundIssueType: string;\n\n\t/** The publisher-side issue type meaning \"not producing\". Default `'dry-outbound-track'`. */\n\tdryOutboundIssueType: string;\n\n\t/** Minimum subscribers before \"all of them\" means anything. Default `2`. */\n\tminReceivers: number;\n\n\t/** Fraction of subscribers that must be dry to call it a whole-track delivery failure. Default `1`. */\n\tallReceiversRatio: number;\n\n\t/** Re-arm time (ms) per (track, verdict). Default `60_000`. */\n\tcooldownMs: number;\n\n\tregistry?: Partial<IssueRegistryConfig>;\n};\n\nconst defaultConfig: TrackDeliveryMismatchDetectorConfig = {\n\tdryInboundIssueType: 'dry-inbound-track',\n\tdryOutboundIssueType: 'dry-outbound-track',\n\tminReceivers: 2,\n\tallReceiversRatio: 1,\n\tcooldownMs: 60_000,\n};\n\n/**\n * Answers **\"is the media actually getting through?\"** by joining the two ends of a published track.\n *\n * A dry track is the clearest possible symptom — no bytes are arriving — but on its own it is\n * ambiguous, and the ambiguity is precisely what a single endpoint cannot resolve. A receiver seeing\n * silence cannot tell whether the camera was switched off, the SFU stopped forwarding, or its own\n * consumer wedged. All three look identical from the browser.\n *\n * With the publisher↔subscriber links this becomes a three-way decision:\n *\n * | publisher | subscribers | verdict |\n * |---|---|---|\n * | sending | **all** dry | `PUBLISHED_TRACK_NOT_DELIVERED` — the SFU/forwarding path |\n * | sending | **some** dry | `RECEIVER_TRACK_NOT_DELIVERED` — those consumers (recreate them) |\n * | dry | any dry | `PUBLISHER_TRACK_DRY` — the source stopped; not an SFU fault |\n *\n * The publisher side is judged from **both** signals available: its own `dry-outbound-track` issue\n * when the client reports one, and — as the fallback, and the corroboration when it does not — the\n * observed outbound RTP (`deltaPacketsSent`). That combination is what makes the first row\n * trustworthy: the server can state that packets demonstrably left the publisher during the same\n * interval in which every receiver got nothing.\n *\n * This is the \"SFU forwarding mismatch\" check, and notably it needs **no** mediasoup instrumentation\n * — the client's own dry-track verdicts plus the resolver links are sufficient.\n */\nexport class TrackDeliveryMismatchDetector implements Detector {\n\tpublic readonly name = 'track-delivery-mismatch-detector';\n\n\tprivate readonly _config: TrackDeliveryMismatchDetectorConfig;\n\tprivate readonly _registry: IssueRegistry;\n\tprivate readonly _aggregator: TrackDistributionAggregator;\n\tprivate readonly _lastRaisedAt = new Map<string, number>();\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<TrackDeliveryMismatchDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t\tthis._registry = new IssueRegistry(_call, config.registry);\n\t\tthis._aggregator = new TrackDistributionAggregator(_call);\n\t}\n\n\tpublic update(): void {\n\t\tconst now = Date.now();\n\n\t\tfor (const distribution of this._aggregator.aggregate()) {\n\t\t\tif (distribution.numberOfReceivers < this._config.minReceivers) continue;\n\n\t\t\tconst receiverTrackIds = new Set(distribution.receivers.map((r) => r.observedInboundTrack.id));\n\t\t\tconst dryReceiverIds = new Set(\n\t\t\t\tthis._registry.byTrackIds(receiverTrackIds, now)\n\t\t\t\t\t.filter((issue) => issue.type === this._config.dryInboundIssueType)\n\t\t\t\t\t.map((issue) => issue.clientId),\n\t\t\t);\n\n\t\t\tif (dryReceiverIds.size === 0) continue;\n\n\t\t\t// Is the source actually producing? Prefer its own verdict, corroborate with the RTP.\n\t\t\tconst publisherDryIssue = this._registry\n\t\t\t\t.byClientId(distribution.publisher.clientId, now)\n\t\t\t\t.some((issue) => issue.type === this._config.dryOutboundIssueType\n\t\t\t\t\t&& (issue.trackId === undefined || issue.trackId === distribution.trackId));\n\t\t\tconst publisherSending = !publisherDryIssue && 0 < distribution.publisher.deltaPacketsSent;\n\n\t\t\tconst dryRatio = dryReceiverIds.size / distribution.numberOfReceivers;\n\t\t\tlet type: string;\n\n\t\t\tif (!publisherSending) {\n\t\t\t\ttype = TrackDeliveryMismatchTypes.publisherTrackDry;\n\t\t\t} else if (this._config.allReceiversRatio <= dryRatio) {\n\t\t\t\ttype = TrackDeliveryMismatchTypes.publishedTrackNotDelivered;\n\t\t\t} else {\n\t\t\t\ttype = TrackDeliveryMismatchTypes.receiverTrackNotDelivered;\n\t\t\t}\n\n\t\t\tconst key = `${distribution.trackId}:${type}`;\n\n\t\t\tif (now - (this._lastRaisedAt.get(key) ?? 0) < this._config.cooldownMs) continue;\n\n\t\t\tthis._lastRaisedAt.set(key, now);\n\n\t\t\tthis._call.addIssue({\n\t\t\t\ttype,\n\t\t\t\ttimestamp: now,\n\t\t\t\tpayload: JSON.stringify({\n\t\t\t\t\ttype,\n\t\t\t\t\ttrackId: distribution.trackId,\n\t\t\t\t\tkind: distribution.kind,\n\t\t\t\t\tpublisherClientId: distribution.publisher.clientId,\n\t\t\t\t\tpublisherSending,\n\t\t\t\t\tpublisherDryIssue,\n\t\t\t\t\tpublisherBitrate: distribution.publisher.bitrate,\n\t\t\t\t\tpublisherDeltaPacketsSent: distribution.publisher.deltaPacketsSent,\n\t\t\t\t\treceivers: distribution.numberOfReceivers,\n\t\t\t\t\tdryReceivers: dryReceiverIds.size,\n\t\t\t\t\tdryRatio,\n\t\t\t\t\tdryClientIds: [ ...dryReceiverIds ],\n\t\t\t\t\thealthyClientIds: distribution.receivers\n\t\t\t\t\t\t.map((r) => r.clientId)\n\t\t\t\t\t\t.filter((clientId) => !dryReceiverIds.has(clientId)),\n\t\t\t\t}),\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tthis._lastRaisedAt.clear();\n\t}\n}\n","import type { Detector } from './Detector';\nimport type { ObservedCall } from '../ObservedCall';\n\nexport const UnconsumedTrackTypes = {\n\t/** A track is being published to the SFU that nobody is subscribed to — pure wasted uplink. */\n\tunconsumedPublishedTrack: 'UNCONSUMED_PUBLISHED_TRACK',\n} as const;\n\nexport type UnconsumedTrackDetectorConfig = {\n\n\t/** How long a track must stay unconsumed while sending before reporting (ms). Default `30_000`. */\n\tminUnconsumedDurationInMs: number;\n\n\t/** Ignore tracks below this bitrate — a trickle isn't worth an alert (bps). Default `50_000`. */\n\tminBitrate: number;\n\n\t/** Re-arm time (ms) per track. Default `300_000`. */\n\tcooldownMs: number;\n};\n\nconst defaultConfig: UnconsumedTrackDetectorConfig = {\n\tminUnconsumedDurationInMs: 30_000,\n\tminBitrate: 50_000,\n\tcooldownMs: 300_000,\n};\n\n/**\n * Finds tracks that are **published but consumed by nobody** — uplink and SFU ingress spent on media\n * that is never forwarded anywhere.\n *\n * This is the one detector that reads the resolver's *silence* as the signal: an outbound track with\n * an empty `remoteInboundTracks` set, still pushing packets. The usual causes are a participant\n * publishing while everyone has them hidden or muted-in-UI, a simulcast layer no viewer's bandwidth\n * ever selects, or an application that forgot to stop a track after the last subscriber left.\n *\n * It is deliberately slow to fire: `minUnconsumedDurationInMs` must elapse with the track still\n * sending, because a brief gap between publishing and the first subscription is completely normal at\n * join time.\n *\n * ### Careful: this detector is only sound with a resolver\n *\n * \"No subscribers\" and \"no resolver configured\" produce the identical observation — an empty link\n * set. Without a `RemoteTrackResolver` this would report *every* published track in the call as\n * unconsumed, so it checks `call.remoteTrackResolver` at runtime and does nothing without one.\n */\nexport class UnconsumedTrackDetector implements Detector {\n\tpublic readonly name = 'unconsumed-track-detector';\n\n\tprivate readonly _config: UnconsumedTrackDetectorConfig;\n\n\t/** trackId -> when it was first seen sending with no subscribers. */\n\tprivate readonly _unconsumedSince = new Map<string, number>();\n\tprivate readonly _lastRaisedAt = new Map<string, number>();\n\n\tpublic constructor(\n\t\tprivate readonly _call: ObservedCall,\n\t\tconfig: Partial<UnconsumedTrackDetectorConfig> = {},\n\t) {\n\t\tthis._config = { ...defaultConfig, ...config };\n\t}\n\n\tpublic update(): void {\n\t\t// Without links, \"no subscribers\" is unknowable — never guess.\n\t\tif (!this._call.remoteTrackResolver) return;\n\n\t\tconst now = Date.now();\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const client of this._call.observedClients.values()) {\n\t\t\tfor (const peerConnection of client.observedPeerConnections.values()) {\n\t\t\t\tfor (const outboundTrack of peerConnection.observedOutboundTracks.values()) {\n\t\t\t\t\tconst rtps = outboundTrack.getOutboundRtps() ?? [];\n\t\t\t\t\tconst bitrate = rtps.reduce((sum, rtp) => sum + rtp.bitrate, 0);\n\t\t\t\t\tconst sending = rtps.some((rtp) => 0 < rtp.deltaPacketsSent);\n\t\t\t\t\tconst consumed = 0 < outboundTrack.remoteInboundTracks.size;\n\n\t\t\t\t\tseen.add(outboundTrack.id);\n\n\t\t\t\t\tif (consumed || !sending || bitrate < this._config.minBitrate) {\n\t\t\t\t\t\tthis._unconsumedSince.delete(outboundTrack.id);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst since = this._unconsumedSince.get(outboundTrack.id) ?? now;\n\n\t\t\t\t\tthis._unconsumedSince.set(outboundTrack.id, since);\n\n\t\t\t\t\tconst unconsumedForMs = now - since;\n\n\t\t\t\t\tif (unconsumedForMs < this._config.minUnconsumedDurationInMs) continue;\n\t\t\t\t\tif (now - (this._lastRaisedAt.get(outboundTrack.id) ?? 0) < this._config.cooldownMs) continue;\n\n\t\t\t\t\tthis._lastRaisedAt.set(outboundTrack.id, now);\n\n\t\t\t\t\tthis._call.addIssue({\n\t\t\t\t\t\ttype: UnconsumedTrackTypes.unconsumedPublishedTrack,\n\t\t\t\t\t\ttimestamp: now,\n\t\t\t\t\t\tpayload: JSON.stringify({\n\t\t\t\t\t\t\ttype: UnconsumedTrackTypes.unconsumedPublishedTrack,\n\t\t\t\t\t\t\ttrackId: outboundTrack.id,\n\t\t\t\t\t\t\tkind: outboundTrack.kind,\n\t\t\t\t\t\t\tpublisherClientId: client.clientId,\n\t\t\t\t\t\t\tpeerConnectionId: peerConnection.peerConnectionId,\n\t\t\t\t\t\t\tbitrate,\n\t\t\t\t\t\t\tunconsumedForMs,\n\t\t\t\t\t\t\t// what the waste costs, roughly, if it continues\n\t\t\t\t\t\t\twastedBytesPerSecond: bitrate / 8,\n\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const trackId of [ ...this._unconsumedSince.keys() ]) {\n\t\t\tif (!seen.has(trackId)) this._unconsumedSince.delete(trackId);\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tthis._unconsumedSince.clear();\n\t\tthis._lastRaisedAt.clear();\n\t}\n}\n","import { EventEmitter } from 'events';\nimport type { ClientSample } from '../schema/ClientSample';\nimport type { ObservedCall } from '../ObservedCall';\n\n/** The lifecycle events a sink may emit (a subset of Node's writable-stream events). */\nexport type ClientSampleSinkEvents = {\n\n\t/** The destination is fully written and closed (e.g. a file flushed and its fd closed). */\n\tclose: [];\n\n\t/** The destination failed. */\n\terror: [Error];\n\n\t/** `end()` was processed and all queued data was flushed (before `close`). */\n\tfinish: [];\n\n\t/** The buffer drained after backpressure; safe to write more. */\n\tdrain: [];\n};\n\nexport declare interface ClientSampleSink {\n\ton<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;\n\tonce<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;\n\toff<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;\n\temit<E extends keyof ClientSampleSinkEvents>(event: E, ...args: ClientSampleSinkEvents[E]): boolean;\n}\n\n/**\n * A per-client destination for accepted samples — a typed `EventEmitter` base class. One sink is\n * created per `ObservedClient` (via `ObserverConfig.createClientSink`). It is **object-mode**:\n * `write` receives the `ClientSample` itself, so each sink decides how to serialize it (JSON\n * line, protobuf, msgpack, a remote payload, …).\n *\n * The library calls `write(sample)` synchronously per accepted sample (not awaited), `end()`s the\n * sink when the client closes, and attaches an `error` listener so a failing sink can't crash the\n * process. The application — which created the sink — listens for `close` (destination ready,\n * e.g. a file flushed and its fd closed) and `error`.\n *\n * Subclass this and implement `write`/`end` (and `emit` your lifecycle events). Built-in sinks\n * (`JsonlFileSink`, `InMemorySink`) and their factories are exported from the package root.\n */\nexport abstract class ClientSampleSink extends EventEmitter {\n\t/** Accept one sample; the sink serializes it however it likes. `false` signals backpressure. */\n\tpublic abstract write(sample: ClientSample): boolean;\n\n\t/** Finish writing; the sink flushes and (if applicable) emits `close`. */\n\tpublic abstract end(): void;\n}\n\n/**\n * Produces a sink for a newly-created client, or `undefined` for no sink. Receives the\n * client id and its (already-created) parent call, so the destination can be derived\n * from `callId` / `clientId`.\n */\nexport type ClientSampleSinkFactory = (params: {\n\tclientId: string,\n\tobservedCall: ObservedCall,\n}) => ClientSampleSink | undefined;\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { ClientSampleSink, ClientSampleSinkFactory } from './ClientSampleSink';\nimport type { ClientSample } from '../schema/ClientSample';\n\nexport type JsonlFileSinkOptions = {\n\n\t/** Absolute or relative file path to append JSONL lines to. */\n\tpath: string,\n\n\t/** Optional custom serializer; defaults to `JSON.stringify`. */\n\tserializeSample?: (sample: ClientSample) => string,\n};\n\n/**\n * A sink that serializes each sample to a JSON line and appends it to a file. It wraps an\n * `fs.WriteStream` and re-emits its lifecycle events, so `close` fires once the file is flushed\n * and its descriptor is closed (file ready) and `error` surfaces file errors.\n */\nexport class JsonlFileSink extends ClientSampleSink {\n\t/** The file this sink writes to. Read it (e.g. in a `close` handler) to upload/move the file. */\n\tpublic readonly path: string;\n\n\tprivate readonly _stream: fs.WriteStream;\n\tprivate readonly _serializeSample: (sample: ClientSample) => string;\n\n\tpublic constructor(options: JsonlFileSinkOptions) {\n\t\tsuper();\n\t\tthis.path = options.path;\n\t\tthis._stream = fs.createWriteStream(this.path, { flags: 'a' });\n\n\t\tthis._stream.on('close', () => this.emit('close'));\n\t\tthis._stream.on('finish', () => this.emit('finish'));\n\t\tthis._stream.on('drain', () => this.emit('drain'));\n\t\tthis._stream.on('error', (err) => this.emit('error', err));\n\n\t\tthis._serializeSample = options.serializeSample ?? ((sample) => JSON.stringify(sample));\n\t}\n\n\tpublic write(sample: ClientSample): boolean {\n\t\treturn this._stream.write(`${this._serializeSample(sample)}\\n`);\n\t}\n\n\tpublic end(): void {\n\t\tthis._stream.end();\n\t}\n}\n\n/** Build a JSONL file sink for a single path. */\nexport function createJsonlFileSink(options: JsonlFileSinkOptions): ClientSampleSink {\n\treturn new JsonlFileSink(options);\n}\n\nexport type JsonlFileSinkFactoryOptions = {\n\n\t/** Directory the per-client files are written into (must exists). */\n\tdirectory: string,\n\n\t/** Builds the file name from the call/client ids. Defaults to `${callId}__${clientId}.jsonl`. */\n\tgetFileName?: (params: { callId: string, clientId: string }) => string,\n\n\t/** Optional custom serializer; defaults to `JSON.stringify`. */\n\tserializeSample?: (sample: ClientSample) => string,\n};\n\n/**\n * Convenience factory that writes one JSONL file per client, with the path derived from\n * `callId` / `clientId`. Plug into `ObserverConfig.createClientSink`.\n */\nexport function createJsonlFileSinkFactory(options: JsonlFileSinkFactoryOptions): ClientSampleSinkFactory {\n\n\treturn ({ clientId, observedCall }) => {\n\t\tconst filename = options.getFileName?.({ callId: observedCall.callId, clientId }) ?? `${observedCall.callId}__${clientId}.jsonl`;\n\n\t\treturn createJsonlFileSink({\n\t\t\tpath: path.join(options.directory, filename),\n\t\t\tserializeSample: options.serializeSample,\n\t\t});\n\t};\n}\n","import { ClientSampleSink } from './ClientSampleSink';\nimport type { ClientSample } from '../schema/ClientSample';\n\n/**\n * A `ClientSampleSink` that collects the accepted sample objects into an array. Useful for\n * tests and offline replay. Emits `close` on `end()`.\n */\nexport class InMemorySink extends ClientSampleSink {\n\tpublic constructor(public readonly samples: ClientSample[] = []) {\n\t\tsuper();\n\t}\n\n\tpublic write(sample: ClientSample): boolean {\n\t\tthis.samples.push(sample);\n\n\t\treturn true;\n\t}\n\n\tpublic end(): void {\n\t\tthis.emit('close');\n\t}\n}\n\nexport function createInMemorySink(samples?: ClientSample[]): InMemorySink {\n\treturn new InMemorySink(samples);\n}\n","import { ObservedCall } from '../ObservedCall';\nimport { ObservedInboundTrack } from '../ObservedInboundTrack';\nimport { ObservedOutboundTrack } from '../ObservedOutboundTrack';\nimport type { ObserverEvents } from '../ObserverEvents';\n\nexport type RemoteTrackResolverFactory = (observedCall: ObservedCall) => RemoteTrackResolver;\n\n/**\n * Strategy functions that map a track to its publish/subscribe identity. Two tracks are linked\n * when a subscribed (inbound) track's **publisher id** equals a published (outbound) track's\n * **publisher id** — one publisher → many subscribers. The **subscriber id** is optional and is\n * only used to look an inbound track up via `getInboundTrackBySubscriberId`.\n *\n * The \"publisher id\" is whatever a strategy uses as the link key: mediasoup passes its producerId,\n * a p2p strategy the SSRC, a generic strategy a shared attachment value.\n */\nexport type RemoteTrackResolvers = {\n\n\t/** The publisher id a subscribed (inbound) track receives. Required — this is the link key. */\n\tresolveInboundTrackPublisherId: (inboundTrack: ObservedInboundTrack) => string | undefined,\n\n\t/** The publisher id a published (outbound) track represents. Required — this is the link key. */\n\tresolveOutboundTrackPublisherId: (outboundTrack: ObservedOutboundTrack) => string | undefined,\n\n\t/** Optional: the inbound track's own subscription id (enables `getInboundTrackBySubscriberId`). */\n\tresolveInboundTrackSubscriberId?: (inboundTrack: ObservedInboundTrack) => string | undefined,\n};\n\n/**\n * Generic, strategy-driven base resolver. It subscribes to the Observer bus (filtered to one call),\n * links subscribed↔published tracks by publisher id, and maintains the links directly on the tracks\n * (`inboundTrack.remoteOutboundTrack`, `outboundTrack.remoteInboundTracks`).\n *\n * Concrete strategies (mediasoup, p2p-by-SSRC, generic attachment) are just different\n * {@link RemoteTrackResolvers} passed to this class. Ids are re-resolved on demand rather than\n * cached, so the only state kept is the two lookup indexes that back the public getters.\n */\nexport class RemoteTrackResolver {\n\tprivate readonly _publisherIdToOutboundTrack = new Map<string, ObservedOutboundTrack>();\n\tprivate readonly _subscriberIdToInboundTrack = new Map<string, ObservedInboundTrack>();\n\n\tpublic constructor(\n\t\tpublic readonly observedCall: ObservedCall,\n\t\tprivate readonly resolvers: RemoteTrackResolvers,\n\t) {\n\t\tconst observer = observedCall.observer;\n\n\t\t// Subscribe to the central Observer bus, filtering to this call's tracks.\n\t\tconst onInboundAdded = (p: ObserverEvents['inbound-track-added'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._addInboundTrack(p.observedInboundTrack);\n\t\t};\n\t\tconst onInboundRemoved = (p: ObserverEvents['inbound-track-removed'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._removeInboundTrack(p.observedInboundTrack);\n\t\t};\n\t\tconst onOutboundAdded = (p: ObserverEvents['outbound-track-added'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._addOutboundTrack(p.observedOutboundTrack);\n\t\t};\n\t\tconst onOutboundRemoved = (p: ObserverEvents['outbound-track-removed'][0]) => {\n\t\t\tif (p.observedCall === this.observedCall) this._removeOutboundTrack(p.observedOutboundTrack);\n\t\t};\n\n\t\tobservedCall.once('close', () => {\n\t\t\tobserver.off('inbound-track-added', onInboundAdded);\n\t\t\tobserver.off('inbound-track-removed', onInboundRemoved);\n\t\t\tobserver.off('outbound-track-added', onOutboundAdded);\n\t\t\tobserver.off('outbound-track-removed', onOutboundRemoved);\n\t\t});\n\n\t\tobserver.on('inbound-track-added', onInboundAdded);\n\t\tobserver.on('inbound-track-removed', onInboundRemoved);\n\t\tobserver.on('outbound-track-added', onOutboundAdded);\n\t\tobserver.on('outbound-track-removed', onOutboundRemoved);\n\t}\n\n\t/** The published (outbound) track for a publisher id, if any. */\n\tpublic getOutboundTrackByPublisherId(publisherId: string): ObservedOutboundTrack | undefined {\n\t\treturn this._publisherIdToOutboundTrack.get(publisherId);\n\t}\n\n\t/** The subscribed (inbound) track for a subscriber id, if the strategy resolves subscriber ids. */\n\tpublic getInboundTrackBySubscriberId(subscriberId: string): ObservedInboundTrack | undefined {\n\t\treturn this._subscriberIdToInboundTrack.get(subscriberId);\n\t}\n\n\t// RemoteTrackResolver interface — thin readers over the links maintained on the tracks.\n\tpublic resolveRemoteOutboundTrack(inboundTrack: ObservedInboundTrack): ObservedOutboundTrack | undefined {\n\t\treturn inboundTrack.remoteOutboundTrack;\n\t}\n\n\tpublic resolveRemoteInboundTracks(outboundTrack: ObservedOutboundTrack): ObservedInboundTrack[] | undefined {\n\t\treturn [ ...outboundTrack.remoteInboundTracks ];\n\t}\n\n\tprivate _addInboundTrack(inboundTrack: ObservedInboundTrack) {\n\t\tconst publisherId = this.resolvers.resolveInboundTrackPublisherId(inboundTrack);\n\n\t\tif (!publisherId) return;\n\n\t\tconst subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);\n\n\t\tif (subscriberId) {\n\t\t\tthis._subscriberIdToInboundTrack.set(subscriberId, inboundTrack);\n\t\t}\n\n\t\tconst outboundTrack = this._publisherIdToOutboundTrack.get(publisherId);\n\n\t\tif (!outboundTrack) return;\n\n\t\toutboundTrack.remoteInboundTracks.add(inboundTrack);\n\t\tinboundTrack.remoteOutboundTrack = outboundTrack;\n\t}\n\n\tprivate _removeInboundTrack(inboundTrack: ObservedInboundTrack) {\n\t\t// Use the stored link to unlink; no need to re-resolve the publisher id here.\n\t\tinboundTrack.remoteOutboundTrack?.remoteInboundTracks.delete(inboundTrack);\n\t\tinboundTrack.remoteOutboundTrack = undefined;\n\n\t\tconst subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);\n\n\t\tif (subscriberId) {\n\t\t\tthis._subscriberIdToInboundTrack.delete(subscriberId);\n\t\t}\n\t}\n\n\tprivate _addOutboundTrack(outboundTrack: ObservedOutboundTrack) {\n\t\tconst publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);\n\n\t\tif (!publisherId) return;\n\n\t\tthis._publisherIdToOutboundTrack.set(publisherId, outboundTrack);\n\n\t\t// Link any already-present subscribers of this publisher.\n\t\tfor (const observedClient of this.observedCall.observedClients.values()) {\n\t\t\tfor (const observedPeerConnection of observedClient.observedPeerConnections.values()) {\n\t\t\t\tfor (const inboundTrack of observedPeerConnection.observedInboundTracks.values()) {\n\t\t\t\t\tif (this.resolvers.resolveInboundTrackPublisherId(inboundTrack) !== publisherId) continue;\n\n\t\t\t\t\toutboundTrack.remoteInboundTracks.add(inboundTrack);\n\t\t\t\t\tinboundTrack.remoteOutboundTrack = outboundTrack;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _removeOutboundTrack(outboundTrack: ObservedOutboundTrack) {\n\t\tconst publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);\n\n\t\t// Only clear the map entry if it still points at this track (guards republish races).\n\t\tif (publisherId && this._publisherIdToOutboundTrack.get(publisherId) === outboundTrack) {\n\t\t\tthis._publisherIdToOutboundTrack.delete(publisherId);\n\t\t}\n\n\t\tfor (const inboundTrack of outboundTrack.remoteInboundTracks) {\n\t\t\tinboundTrack.remoteOutboundTrack = undefined;\n\t\t}\n\t\toutboundTrack.remoteInboundTracks.clear();\n\t}\n}\n","import { ObservedCall } from '../ObservedCall';\nimport { RemoteTrackResolver, RemoteTrackResolverFactory } from './RemoteTrackResolver';\n\nexport function createDefaultMediasoupRemoteTrackResolverFactory(): RemoteTrackResolverFactory {\n\treturn (observedCall: ObservedCall) => new RemoteTrackResolver(observedCall, {\n\t\tresolveInboundTrackPublisherId: (inboundTrack) => inboundTrack.attachments?.producerId as string | undefined,\n\t\tresolveInboundTrackSubscriberId: (inboundTrack) => inboundTrack.attachments?.consumerId as string | undefined,\n\t\tresolveOutboundTrackPublisherId: (outboundTrack) => outboundTrack.attachments?.producerId as string | undefined,\n\t});\n}\n\nexport function createP2pRemoteTrackResolverFactory(): RemoteTrackResolverFactory {\n\treturn (observedCall: ObservedCall) => new RemoteTrackResolver(observedCall, {\n\t\tresolveInboundTrackPublisherId: (inboundTrack) => {\n\t\t\tconst ssrc = inboundTrack.getInboundRtp()?.ssrc;\n\n\t\t\treturn ssrc ? `${ssrc}` : undefined;\n\t\t},\n\t\tresolveInboundTrackSubscriberId: (inboundTrack) => {\n\t\t\tconst ssrc = inboundTrack.getInboundRtp()?.ssrc;\n\n\t\t\treturn ssrc ? `${ssrc}` : undefined;\n\t\t},\n\t\tresolveOutboundTrackPublisherId: (outboundTrack) => {\n\t\t\t// In p2p the sender's SSRC is preserved end-to-end, so it matches the receiver's\n\t\t\t// inbound SSRC. (Single-encoding case; simulcast would need per-encoding keys.)\n\t\t\tconst rtps = outboundTrack.getOutboundRtps();\n\n\t\t\tif (!rtps || rtps.length === 0) return undefined;\n\n\t\t\treturn rtps.map((rtp) => rtp.ssrc).join(',');\n\t\t}\n\t});\n}\n"],"mappings":"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","names":["module","logger","import_events","import_events","ClientEventTypes","ClientMetaTypes","logger","logger","logger","import_events","import_events","logger","import_events","logger","logger","defaultConfig","defaultConfig","defaultConfig","defaultConfig","defaultConfig","defaultConfig","defaultConfig","defaultConfig","defaultConfig","median","defaultConfig","defaultConfig","import_events"]}