@observertc/observer-js 1.0.0-beta.1 → 1.0.0-beta.11

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.
Files changed (227) hide show
  1. package/README.md +1032 -381
  2. package/dist/index.d.mts +2956 -0
  3. package/dist/index.d.ts +2956 -0
  4. package/dist/index.js +4095 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.mjs +4025 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/llms-full.txt +1598 -0
  9. package/package.json +33 -16
  10. package/.eslintrc.json +0 -143
  11. package/.prettierignore +0 -5
  12. package/.prettierrc +0 -7
  13. package/jest.config.js +0 -9
  14. package/lib/ObservedCall.d.ts +0 -85
  15. package/lib/ObservedCall.d.ts.map +0 -1
  16. package/lib/ObservedCall.js +0 -219
  17. package/lib/ObservedCallEventMonitor.d.ts +0 -104
  18. package/lib/ObservedCallEventMonitor.d.ts.map +0 -1
  19. package/lib/ObservedCallEventMonitor.js +0 -314
  20. package/lib/ObservedCallSummary.d.ts +0 -18
  21. package/lib/ObservedCallSummary.d.ts.map +0 -1
  22. package/lib/ObservedCallSummary.js +0 -2
  23. package/lib/ObservedCertificate.d.ts +0 -19
  24. package/lib/ObservedCertificate.d.ts.map +0 -1
  25. package/lib/ObservedCertificate.js +0 -38
  26. package/lib/ObservedClient.d.ts +0 -127
  27. package/lib/ObservedClient.d.ts.map +0 -1
  28. package/lib/ObservedClient.js +0 -636
  29. package/lib/ObservedClientEventMonitor.d.ts +0 -91
  30. package/lib/ObservedClientEventMonitor.d.ts.map +0 -1
  31. package/lib/ObservedClientEventMonitor.js +0 -254
  32. package/lib/ObservedClientSummary.d.ts +0 -23
  33. package/lib/ObservedClientSummary.d.ts.map +0 -1
  34. package/lib/ObservedClientSummary.js +0 -2
  35. package/lib/ObservedCodec.d.ts +0 -22
  36. package/lib/ObservedCodec.d.ts.map +0 -1
  37. package/lib/ObservedCodec.js +0 -45
  38. package/lib/ObservedDataChannel.d.ts +0 -30
  39. package/lib/ObservedDataChannel.d.ts.map +0 -1
  40. package/lib/ObservedDataChannel.js +0 -75
  41. package/lib/ObservedIceCandidate.d.ts +0 -29
  42. package/lib/ObservedIceCandidate.d.ts.map +0 -1
  43. package/lib/ObservedIceCandidate.js +0 -59
  44. package/lib/ObservedIceCandidatePair.d.ts +0 -45
  45. package/lib/ObservedIceCandidatePair.d.ts.map +0 -1
  46. package/lib/ObservedIceCandidatePair.js +0 -127
  47. package/lib/ObservedIceTransport.d.ts +0 -36
  48. package/lib/ObservedIceTransport.d.ts.map +0 -1
  49. package/lib/ObservedIceTransport.js +0 -93
  50. package/lib/ObservedInboundRtp.d.ts +0 -92
  51. package/lib/ObservedInboundRtp.d.ts.map +0 -1
  52. package/lib/ObservedInboundRtp.js +0 -193
  53. package/lib/ObservedInboundTrack.d.ts +0 -32
  54. package/lib/ObservedInboundTrack.d.ts.map +0 -1
  55. package/lib/ObservedInboundTrack.js +0 -60
  56. package/lib/ObservedMediaPlayout.d.ts +0 -22
  57. package/lib/ObservedMediaPlayout.d.ts.map +0 -1
  58. package/lib/ObservedMediaPlayout.js +0 -42
  59. package/lib/ObservedMediaSource.d.ts +0 -28
  60. package/lib/ObservedMediaSource.d.ts.map +0 -1
  61. package/lib/ObservedMediaSource.js +0 -55
  62. package/lib/ObservedOutboundRtp.d.ts +0 -62
  63. package/lib/ObservedOutboundRtp.d.ts.map +0 -1
  64. package/lib/ObservedOutboundRtp.js +0 -144
  65. package/lib/ObservedOutboundTrack.d.ts +0 -32
  66. package/lib/ObservedOutboundTrack.d.ts.map +0 -1
  67. package/lib/ObservedOutboundTrack.js +0 -60
  68. package/lib/ObservedPeerConnection.d.ts +0 -207
  69. package/lib/ObservedPeerConnection.d.ts.map +0 -1
  70. package/lib/ObservedPeerConnection.js +0 -773
  71. package/lib/ObservedPeerConnectionTransport.d.ts +0 -17
  72. package/lib/ObservedPeerConnectionTransport.d.ts.map +0 -1
  73. package/lib/ObservedPeerConnectionTransport.js +0 -34
  74. package/lib/ObservedRemoteInboundRtp.d.ts +0 -30
  75. package/lib/ObservedRemoteInboundRtp.d.ts.map +0 -1
  76. package/lib/ObservedRemoteInboundRtp.js +0 -60
  77. package/lib/ObservedRemoteOutboundRtp.d.ts +0 -30
  78. package/lib/ObservedRemoteOutboundRtp.d.ts.map +0 -1
  79. package/lib/ObservedRemoteOutboundRtp.js +0 -60
  80. package/lib/ObservedTURN.d.ts +0 -31
  81. package/lib/ObservedTURN.d.ts.map +0 -1
  82. package/lib/ObservedTURN.js +0 -58
  83. package/lib/ObservedTurnServer.d.ts +0 -25
  84. package/lib/ObservedTurnServer.d.ts.map +0 -1
  85. package/lib/ObservedTurnServer.js +0 -59
  86. package/lib/Observer.d.ts +0 -65
  87. package/lib/Observer.d.ts.map +0 -1
  88. package/lib/Observer.js +0 -160
  89. package/lib/ObserverEventMonitor.d.ts +0 -138
  90. package/lib/ObserverEventMonitor.d.ts.map +0 -1
  91. package/lib/ObserverEventMonitor.js +0 -433
  92. package/lib/ObserverSummary.d.ts +0 -13
  93. package/lib/ObserverSummary.d.ts.map +0 -1
  94. package/lib/ObserverSummary.js +0 -2
  95. package/lib/common/Middleware.d.ts +0 -17
  96. package/lib/common/Middleware.d.ts.map +0 -1
  97. package/lib/common/Middleware.js +0 -60
  98. package/lib/common/SingleExecutor.d.ts +0 -3
  99. package/lib/common/SingleExecutor.d.ts.map +0 -1
  100. package/lib/common/SingleExecutor.js +0 -31
  101. package/lib/common/logger.d.ts +0 -17
  102. package/lib/common/logger.d.ts.map +0 -1
  103. package/lib/common/logger.js +0 -50
  104. package/lib/common/types.d.ts +0 -3
  105. package/lib/common/types.d.ts.map +0 -1
  106. package/lib/common/types.js +0 -3
  107. package/lib/common/utils.d.ts +0 -11
  108. package/lib/common/utils.d.ts.map +0 -1
  109. package/lib/common/utils.js +0 -63
  110. package/lib/detectors/Detector.d.ts +0 -5
  111. package/lib/detectors/Detector.d.ts.map +0 -1
  112. package/lib/detectors/Detector.js +0 -3
  113. package/lib/detectors/Detectors.d.ts +0 -11
  114. package/lib/detectors/Detectors.d.ts.map +0 -1
  115. package/lib/detectors/Detectors.js +0 -34
  116. package/lib/index.d.ts +0 -28
  117. package/lib/index.d.ts.map +0 -1
  118. package/lib/index.js +0 -49
  119. package/lib/mediasoup/ObservedMediaRouter.d.ts +0 -10
  120. package/lib/mediasoup/ObservedMediaRouter.d.ts.map +0 -1
  121. package/lib/mediasoup/ObservedMediaRouter.js +0 -6
  122. package/lib/monitors/TurnUsageMonitor.d.ts +0 -1
  123. package/lib/monitors/TurnUsageMonitor.d.ts.map +0 -1
  124. package/lib/monitors/TurnUsageMonitor.js +0 -146
  125. package/lib/schema/ClientEventTypes.d.ts +0 -228
  126. package/lib/schema/ClientEventTypes.d.ts.map +0 -1
  127. package/lib/schema/ClientEventTypes.js +0 -41
  128. package/lib/schema/ClientMetaTypes.d.ts +0 -34
  129. package/lib/schema/ClientMetaTypes.d.ts.map +0 -1
  130. package/lib/schema/ClientMetaTypes.js +0 -16
  131. package/lib/schema/ClientSample.d.ts +0 -1333
  132. package/lib/schema/ClientSample.d.ts.map +0 -1
  133. package/lib/schema/ClientSample.js +0 -4
  134. package/lib/scores/CalculatedScore.d.ts +0 -6
  135. package/lib/scores/CalculatedScore.d.ts.map +0 -1
  136. package/lib/scores/CalculatedScore.js +0 -2
  137. package/lib/scores/DefaultCallScoreCalculator.d.ts +0 -7
  138. package/lib/scores/DefaultCallScoreCalculator.d.ts.map +0 -1
  139. package/lib/scores/DefaultCallScoreCalculator.js +0 -21
  140. package/lib/scores/ScoreCalculator.d.ts +0 -4
  141. package/lib/scores/ScoreCalculator.d.ts.map +0 -1
  142. package/lib/scores/ScoreCalculator.js +0 -2
  143. package/lib/updaters/CallUpdater.d.ts +0 -5
  144. package/lib/updaters/CallUpdater.d.ts.map +0 -1
  145. package/lib/updaters/CallUpdater.js +0 -2
  146. package/lib/updaters/ObserverUpdater.d.ts +0 -5
  147. package/lib/updaters/ObserverUpdater.d.ts.map +0 -1
  148. package/lib/updaters/ObserverUpdater.js +0 -2
  149. package/lib/updaters/OnAllCallObserverUpdater.d.ts +0 -15
  150. package/lib/updaters/OnAllCallObserverUpdater.d.ts.map +0 -1
  151. package/lib/updaters/OnAllCallObserverUpdater.js +0 -50
  152. package/lib/updaters/OnAllClientCallUpdater.d.ts +0 -15
  153. package/lib/updaters/OnAllClientCallUpdater.d.ts.map +0 -1
  154. package/lib/updaters/OnAllClientCallUpdater.js +0 -53
  155. package/lib/updaters/OnAnyCallObserverUpdater.d.ts +0 -12
  156. package/lib/updaters/OnAnyCallObserverUpdater.d.ts.map +0 -1
  157. package/lib/updaters/OnAnyCallObserverUpdater.js +0 -37
  158. package/lib/updaters/OnAnyClientCallUpdater.d.ts +0 -12
  159. package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +0 -1
  160. package/lib/updaters/OnAnyClientCallUpdater.js +0 -36
  161. package/lib/updaters/OnIntervalUpdater.d.ts +0 -10
  162. package/lib/updaters/OnIntervalUpdater.d.ts.map +0 -1
  163. package/lib/updaters/OnIntervalUpdater.js +0 -17
  164. package/lib/updaters/Updater.d.ts +0 -6
  165. package/lib/updaters/Updater.d.ts.map +0 -1
  166. package/lib/updaters/Updater.js +0 -2
  167. package/lib/utils/MediasoupRemoteTrackResolver.d.ts +0 -25
  168. package/lib/utils/MediasoupRemoteTrackResolver.d.ts.map +0 -1
  169. package/lib/utils/MediasoupRemoteTrackResolver.js +0 -110
  170. package/lib/utils/RemoteTrackResolver.d.ts +0 -7
  171. package/lib/utils/RemoteTrackResolver.d.ts.map +0 -1
  172. package/lib/utils/RemoteTrackResolver.js +0 -2
  173. package/src/ObservedCall.ts +0 -338
  174. package/src/ObservedCallEventMonitor.ts +0 -392
  175. package/src/ObservedCallSummary.ts +0 -22
  176. package/src/ObservedCertificate.ts +0 -43
  177. package/src/ObservedClient.ts +0 -788
  178. package/src/ObservedClientEventMonitor.ts +0 -309
  179. package/src/ObservedClientSummary.ts +0 -24
  180. package/src/ObservedCodec.ts +0 -49
  181. package/src/ObservedDataChannel.ts +0 -85
  182. package/src/ObservedIceCandidate.ts +0 -64
  183. package/src/ObservedIceCandidatePair.ts +0 -134
  184. package/src/ObservedIceTransport.ts +0 -99
  185. package/src/ObservedInboundRtp.ts +0 -205
  186. package/src/ObservedInboundTrack.ts +0 -75
  187. package/src/ObservedMediaPlayout.ts +0 -49
  188. package/src/ObservedMediaSource.ts +0 -60
  189. package/src/ObservedOutboundRtp.ts +0 -156
  190. package/src/ObservedOutboundTrack.ts +0 -74
  191. package/src/ObservedPeerConnection.ts +0 -1088
  192. package/src/ObservedPeerConnectionTransport.ts +0 -38
  193. package/src/ObservedRemoteInboundRtp.ts +0 -64
  194. package/src/ObservedRemoteOutboundRtp.ts +0 -65
  195. package/src/ObservedTURN.ts +0 -86
  196. package/src/ObservedTurnServer.ts +0 -72
  197. package/src/Observer.ts +0 -247
  198. package/src/ObserverEventMonitor.ts +0 -551
  199. package/src/ObserverSummary.ts +0 -15
  200. package/src/common/Middleware.ts +0 -84
  201. package/src/common/SingleExecutor.ts +0 -36
  202. package/src/common/logger.ts +0 -82
  203. package/src/common/types.ts +0 -4
  204. package/src/common/utils.ts +0 -69
  205. package/src/detectors/Detector.ts +0 -6
  206. package/src/detectors/Detectors.ts +0 -38
  207. package/src/index.ts +0 -28
  208. package/src/mediasoup/ObservedMediaRouter.ts +0 -10
  209. package/src/monitors/TurnUsageMonitor.ts +0 -187
  210. package/src/schema/ClientEventTypes.ts +0 -280
  211. package/src/schema/ClientMetaTypes.ts +0 -41
  212. package/src/schema/ClientSample.ts +0 -1682
  213. package/src/scores/CalculatedScore.ts +0 -6
  214. package/src/scores/DefaultCallScoreCalculator.ts +0 -23
  215. package/src/scores/ScoreCalculator.ts +0 -3
  216. package/src/updaters/CallUpdater.ts +0 -5
  217. package/src/updaters/ObserverUpdater.ts +0 -5
  218. package/src/updaters/OnAllCallObserverUpdater.ts +0 -59
  219. package/src/updaters/OnAllClientCallUpdater.ts +0 -61
  220. package/src/updaters/OnAnyCallObserverUpdater.ts +0 -41
  221. package/src/updaters/OnAnyClientCallUpdater.ts +0 -39
  222. package/src/updaters/OnIntervalUpdater.ts +0 -19
  223. package/src/updaters/Updater.ts +0 -5
  224. package/src/utils/MediasoupRemoteTrackResolver.ts +0 -155
  225. package/src/utils/RemoteTrackResolver.ts +0 -12
  226. package/tsconfig.json +0 -19
  227. package/tslint.json +0 -6
package/dist/index.js ADDED
@@ -0,0 +1,4095 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ ClientEventTypes: () => ClientEventTypes,
34
+ ClientMetaTypes: () => ClientMetaTypes,
35
+ ClientSampleSink: () => ClientSampleSink,
36
+ Detectors: () => Detectors,
37
+ InMemorySink: () => InMemorySink,
38
+ JsonlFileSink: () => JsonlFileSink,
39
+ ObservedCall: () => ObservedCall,
40
+ ObservedCertificate: () => ObservedCertificate,
41
+ ObservedClient: () => ObservedClient,
42
+ ObservedCodec: () => ObservedCodec,
43
+ ObservedDataChannel: () => ObservedDataChannel,
44
+ ObservedIceCandidate: () => ObservedIceCandidate,
45
+ ObservedIceCandidatePair: () => ObservedIceCandidatePair,
46
+ ObservedIceTransport: () => ObservedIceTransport,
47
+ ObservedInboundRtp: () => ObservedInboundRtp,
48
+ ObservedInboundTrack: () => ObservedInboundTrack,
49
+ ObservedMediaPlayout: () => ObservedMediaPlayout,
50
+ ObservedMediaSource: () => ObservedMediaSource,
51
+ ObservedMediasoupRouter: () => ObservedMediasoupRouter,
52
+ ObservedOutboundRtp: () => ObservedOutboundRtp,
53
+ ObservedOutboundTrack: () => ObservedOutboundTrack,
54
+ ObservedPeerConnection: () => ObservedPeerConnection,
55
+ ObservedPeerConnectionTransport: () => ObservedPeerConnectionTransport,
56
+ ObservedRemoteInboundRtp: () => ObservedRemoteInboundRtp,
57
+ ObservedRemoteOutboundRtp: () => ObservedRemoteOutboundRtp,
58
+ Observer: () => Observer,
59
+ RemoteTrackResolver: () => RemoteTrackResolver,
60
+ createDefaultMediasoupRemoteTrackResolverFactory: () => createDefaultMediasoupRemoteTrackResolverFactory,
61
+ createInMemorySink: () => createInMemorySink,
62
+ createJsonlFileSink: () => createJsonlFileSink,
63
+ createJsonlFileSinkFactory: () => createJsonlFileSinkFactory,
64
+ createLogger: () => createLogger,
65
+ createP2pRemoteTrackResolverFactory: () => createP2pRemoteTrackResolverFactory,
66
+ setObserverLogger: () => setObserverLogger
67
+ });
68
+ module.exports = __toCommonJS(src_exports);
69
+
70
+ // src/common/logger.ts
71
+ var mainLogger = new class {
72
+ trace = () => void 0;
73
+ // trace(module: string, ...args: any[]) {
74
+ // // eslint-disable-next-line no-console
75
+ // console.log(`[TRACE] ${module}`, ...args);
76
+ // }
77
+ debug(module2, ...args) {
78
+ console.log(`[DEBUG] ${module2}`, ...args);
79
+ }
80
+ info(module2, ...args) {
81
+ console.info(`[INFO] ${module2}`, ...args);
82
+ }
83
+ warn(module2, ...args) {
84
+ console.warn(`[WARN] ${module2}`, ...args);
85
+ }
86
+ error(module2, ...args) {
87
+ console.error(`[ERROR] ${module2}`, ...args);
88
+ }
89
+ }();
90
+ function createLogger(moduleName) {
91
+ return new class {
92
+ trace(...args) {
93
+ mainLogger.trace(moduleName, ...args);
94
+ }
95
+ debug(...args) {
96
+ mainLogger.debug(moduleName, ...args);
97
+ }
98
+ info(...args) {
99
+ mainLogger.info(moduleName, ...args);
100
+ }
101
+ warn(...args) {
102
+ mainLogger.warn(moduleName, ...args);
103
+ }
104
+ error(...args) {
105
+ mainLogger.error(moduleName, ...args);
106
+ }
107
+ }();
108
+ }
109
+ function setObserverLogger(logger8) {
110
+ mainLogger = logger8;
111
+ }
112
+
113
+ // src/ObservedCall.ts
114
+ var import_events3 = require("events");
115
+
116
+ // src/ObservedClient.ts
117
+ var import_events2 = require("events");
118
+
119
+ // src/ObservedPeerConnection.ts
120
+ var import_events = require("events");
121
+
122
+ // src/ObservedInboundRtp.ts
123
+ var ObservedInboundRtp = class {
124
+ constructor(timestamp, id, ssrc, kind, trackIdentifier, _peerConnection) {
125
+ this.timestamp = timestamp;
126
+ this.id = id;
127
+ this.ssrc = ssrc;
128
+ this.kind = kind;
129
+ this.trackIdentifier = trackIdentifier;
130
+ this._peerConnection = _peerConnection;
131
+ }
132
+ timestamp;
133
+ id;
134
+ ssrc;
135
+ kind;
136
+ trackIdentifier;
137
+ _peerConnection;
138
+ appData;
139
+ _visited = false;
140
+ transportId;
141
+ codecId;
142
+ packetsReceived;
143
+ packetsLost;
144
+ mid;
145
+ remoteId;
146
+ framesDecoded;
147
+ keyFramesDecoded;
148
+ framesRendered;
149
+ framesDropped;
150
+ frameWidth;
151
+ frameHeight;
152
+ framesPerSecond;
153
+ qpSum;
154
+ totalDecodeTime;
155
+ totalInterFrameDelay;
156
+ totalSquaredInterFrameDelay;
157
+ pauseCount;
158
+ totalPausesDuration;
159
+ freezeCount;
160
+ totalFreezesDuration;
161
+ lastPacketReceivedTimestamp;
162
+ headerBytesReceived;
163
+ packetsDiscarded;
164
+ fecBytesReceived;
165
+ fecPacketsReceived;
166
+ fecPacketsDiscarded;
167
+ bytesReceived;
168
+ nackCount;
169
+ firCount;
170
+ pliCount;
171
+ totalProcessingDelay;
172
+ estimatedPlayoutTimestamp;
173
+ jitterBufferDelay;
174
+ jitterBufferTargetDelay;
175
+ jitterBufferEmittedCount;
176
+ jitterBufferMinimumDelay;
177
+ totalSamplesReceived;
178
+ concealedSamples;
179
+ silentConcealedSamples;
180
+ concealmentEvents;
181
+ insertedSamplesForDeceleration;
182
+ removedSamplesForAcceleration;
183
+ audioLevel;
184
+ totalAudioEnergy;
185
+ totalSamplesDuration;
186
+ framesReceived;
187
+ decoderImplementation;
188
+ playoutId;
189
+ powerEfficientDecoder;
190
+ framesAssembledFromMultiplePackets;
191
+ totalAssemblyTime;
192
+ retransmittedPacketsReceived;
193
+ retransmittedBytesReceived;
194
+ rtxSsrc;
195
+ fecSsrc;
196
+ totalCorruptionProbability;
197
+ totalSquaredCorruptionProbability;
198
+ corruptionMeasurements;
199
+ attachments;
200
+ jitter;
201
+ bitrate = 0;
202
+ fractionLost;
203
+ bitPerPixel = 0;
204
+ deltaLostPackets = 0;
205
+ deltaReceivedPackets = 0;
206
+ deltaBytesReceived = 0;
207
+ deltaReceivedSamples = 0;
208
+ deltaSilentConcealedSamples = 0;
209
+ // Derived from the corresponding remote-outbound-rtp (sender report), when present.
210
+ remoteRttInMs;
211
+ remoteBytesSent;
212
+ remotePacketsSent;
213
+ remoteTimestamp;
214
+ get visited() {
215
+ const visited = this._visited;
216
+ this._visited = false;
217
+ return visited;
218
+ }
219
+ getPeerConnection() {
220
+ return this._peerConnection;
221
+ }
222
+ getRemoteOutboundRtp() {
223
+ return this._peerConnection.observedRemoteOutboundRtps.get(this.ssrc);
224
+ }
225
+ getIceTransport() {
226
+ return this._peerConnection.observedIceTransports.get(this.transportId ?? "");
227
+ }
228
+ getCodec() {
229
+ return this._peerConnection.observedCodecs.get(this.codecId ?? "");
230
+ }
231
+ getMediaPlayout() {
232
+ return this._peerConnection.observedMediaPlayouts.get(this.playoutId ?? "");
233
+ }
234
+ getTrack() {
235
+ return this._peerConnection.observedInboundTracks.get(this.trackIdentifier);
236
+ }
237
+ update(stats) {
238
+ this._visited = true;
239
+ this.deltaBytesReceived = 0;
240
+ this.deltaLostPackets = 0;
241
+ this.deltaReceivedPackets = 0;
242
+ this.deltaReceivedSamples = 0;
243
+ this.deltaSilentConcealedSamples = 0;
244
+ this.remoteRttInMs = void 0;
245
+ this.remoteBytesSent = void 0;
246
+ this.remotePacketsSent = void 0;
247
+ this.remoteTimestamp = void 0;
248
+ this.bitrate = 0;
249
+ this.jitter = void 0;
250
+ this.fractionLost = void 0;
251
+ this.bitPerPixel = 0;
252
+ const elapsedTimeInMs = stats.timestamp - this.timestamp;
253
+ if (elapsedTimeInMs) {
254
+ if (this.bytesReceived && stats.bytesReceived && this.bytesReceived < stats.bytesReceived) {
255
+ this.bitrate = (stats.bytesReceived - (this.bytesReceived ?? 0)) * 8 / elapsedTimeInMs;
256
+ }
257
+ if (this.packetsLost && stats.packetsLost && this.packetsLost < stats.packetsLost) {
258
+ this.deltaLostPackets = stats.packetsLost - this.packetsLost;
259
+ }
260
+ if (this.packetsReceived && stats.packetsReceived && this.packetsReceived < stats.packetsReceived) {
261
+ this.deltaReceivedPackets = stats.packetsReceived - this.packetsReceived;
262
+ }
263
+ if (this.totalSamplesReceived && stats.totalSamplesReceived && this.totalSamplesReceived < stats.totalSamplesReceived) {
264
+ this.deltaReceivedSamples = stats.totalSamplesReceived - this.totalSamplesReceived;
265
+ }
266
+ if (this.silentConcealedSamples && stats.silentConcealedSamples && this.silentConcealedSamples < stats.silentConcealedSamples) {
267
+ this.deltaSilentConcealedSamples = stats.silentConcealedSamples - this.silentConcealedSamples;
268
+ }
269
+ if (stats.bytesReceived && this.framesReceived && stats.framesReceived && this.framesReceived < stats.framesReceived) {
270
+ this.bitPerPixel = (stats.bytesReceived - (this.bytesReceived ?? 0)) / (stats.framesReceived - this.framesReceived);
271
+ }
272
+ if (this.deltaLostPackets && this.deltaReceivedPackets) {
273
+ this.fractionLost = this.deltaLostPackets / (this.deltaLostPackets + this.deltaReceivedPackets);
274
+ }
275
+ }
276
+ this.timestamp = stats.timestamp;
277
+ this.transportId = stats.transportId;
278
+ this.codecId = stats.codecId;
279
+ this.packetsReceived = stats.packetsReceived;
280
+ this.packetsLost = stats.packetsLost;
281
+ this.mid = stats.mid;
282
+ this.remoteId = stats.remoteId;
283
+ this.framesDecoded = stats.framesDecoded;
284
+ this.keyFramesDecoded = stats.keyFramesDecoded;
285
+ this.framesRendered = stats.framesRendered;
286
+ this.framesDropped = stats.framesDropped;
287
+ this.frameWidth = stats.frameWidth;
288
+ this.frameHeight = stats.frameHeight;
289
+ this.framesPerSecond = stats.framesPerSecond;
290
+ this.qpSum = stats.qpSum;
291
+ this.totalDecodeTime = stats.totalDecodeTime;
292
+ this.totalInterFrameDelay = stats.totalInterFrameDelay;
293
+ this.totalSquaredInterFrameDelay = stats.totalSquaredInterFrameDelay;
294
+ this.pauseCount = stats.pauseCount;
295
+ this.totalPausesDuration = stats.totalPausesDuration;
296
+ this.freezeCount = stats.freezeCount;
297
+ this.totalFreezesDuration = stats.totalFreezesDuration;
298
+ this.lastPacketReceivedTimestamp = stats.lastPacketReceivedTimestamp;
299
+ this.headerBytesReceived = stats.headerBytesReceived;
300
+ this.packetsDiscarded = stats.packetsDiscarded;
301
+ this.fecBytesReceived = stats.fecBytesReceived;
302
+ this.fecPacketsReceived = stats.fecPacketsReceived;
303
+ this.fecPacketsDiscarded = stats.fecPacketsDiscarded;
304
+ this.bytesReceived = stats.bytesReceived;
305
+ this.nackCount = stats.nackCount;
306
+ this.firCount = stats.firCount;
307
+ this.pliCount = stats.pliCount;
308
+ this.totalProcessingDelay = stats.totalProcessingDelay;
309
+ this.estimatedPlayoutTimestamp = stats.estimatedPlayoutTimestamp;
310
+ this.jitterBufferDelay = stats.jitterBufferDelay;
311
+ this.jitterBufferTargetDelay = stats.jitterBufferTargetDelay;
312
+ this.jitterBufferEmittedCount = stats.jitterBufferEmittedCount;
313
+ this.jitterBufferMinimumDelay = stats.jitterBufferMinimumDelay;
314
+ this.totalSamplesReceived = stats.totalSamplesReceived;
315
+ this.concealedSamples = stats.concealedSamples;
316
+ this.silentConcealedSamples = stats.silentConcealedSamples;
317
+ this.concealmentEvents = stats.concealmentEvents;
318
+ }
319
+ };
320
+
321
+ // src/ObservedOutboundRtp.ts
322
+ var ObservedOutboundRtp = class {
323
+ constructor(timestamp, id, ssrc, kind, _peerConnection) {
324
+ this.timestamp = timestamp;
325
+ this.id = id;
326
+ this.ssrc = ssrc;
327
+ this.kind = kind;
328
+ this._peerConnection = _peerConnection;
329
+ }
330
+ timestamp;
331
+ id;
332
+ ssrc;
333
+ kind;
334
+ _peerConnection;
335
+ _visited = false;
336
+ appData;
337
+ transportId;
338
+ codecId;
339
+ packetsSent;
340
+ bytesSent;
341
+ mid;
342
+ mediaSourceId;
343
+ remoteId;
344
+ rid;
345
+ headerBytesSent;
346
+ retransmittedPacketsSent;
347
+ retransmittedBytesSent;
348
+ rtxSsrc;
349
+ targetBitrate;
350
+ totalEncodedBytesTarget;
351
+ frameWidth;
352
+ frameHeight;
353
+ framesPerSecond;
354
+ framesSent;
355
+ hugeFramesSent;
356
+ framesEncoded;
357
+ keyFramesEncoded;
358
+ qpSum;
359
+ totalEncodeTime;
360
+ totalPacketSendDelay;
361
+ qualityLimitationReason;
362
+ qualityLimitationResolutionChanges;
363
+ nackCount;
364
+ firCount;
365
+ pliCount;
366
+ encoderImplementation;
367
+ powerEfficientEncoder;
368
+ active;
369
+ scalabilityMode;
370
+ qualityLimitationDurations;
371
+ attachments;
372
+ // derived fields
373
+ bitrate = 0;
374
+ payloadBitrate = 0;
375
+ packetRate = 0;
376
+ bitPerPixel = 0;
377
+ deltaPacketsSent = 0;
378
+ deltaBytesSent = 0;
379
+ // Derived from the corresponding remote-inbound-rtp (receiver report), when present.
380
+ remoteRttInMs;
381
+ remoteFractionLost;
382
+ remoteJitter;
383
+ remotePacketsLost;
384
+ get visited() {
385
+ const visited = this._visited;
386
+ this._visited = false;
387
+ return visited;
388
+ }
389
+ getPeerConnection() {
390
+ return this._peerConnection;
391
+ }
392
+ getRemoteInboundRtp() {
393
+ return this._peerConnection.observedRemoteInboundRtps.get(this.ssrc);
394
+ }
395
+ getCodec() {
396
+ return this._peerConnection.observedCodecs.get(this.codecId ?? "");
397
+ }
398
+ getMediaSource() {
399
+ return this._peerConnection.observedMediaSources.get(this.mediaSourceId ?? "");
400
+ }
401
+ getTrack() {
402
+ return this.getMediaSource()?.getTrack();
403
+ }
404
+ update(stats) {
405
+ this._visited = true;
406
+ this.bitPerPixel = 0;
407
+ this.bitrate = 0;
408
+ this.payloadBitrate = 0;
409
+ this.packetRate = 0;
410
+ this.deltaPacketsSent = 0;
411
+ this.deltaBytesSent = 0;
412
+ this.remoteRttInMs = void 0;
413
+ this.remoteFractionLost = void 0;
414
+ this.remoteJitter = void 0;
415
+ this.remotePacketsLost = void 0;
416
+ const elapsedTimeInMs = stats.timestamp - this.timestamp;
417
+ if (elapsedTimeInMs) {
418
+ if (stats.packetsSent !== void 0 && this.packetsSent !== void 0 && stats.packetsSent >= this.packetsSent) {
419
+ this.deltaPacketsSent = stats.packetsSent - this.packetsSent;
420
+ this.packetRate = this.deltaPacketsSent / (elapsedTimeInMs / 1e3);
421
+ }
422
+ if (stats.bytesSent !== void 0 && this.bytesSent !== void 0 && stats.bytesSent >= this.bytesSent) {
423
+ this.deltaBytesSent = stats.bytesSent - this.bytesSent;
424
+ this.bitrate = this.deltaBytesSent * 8 / (elapsedTimeInMs / 1e3);
425
+ }
426
+ if (stats.headerBytesSent !== void 0 && this.headerBytesSent !== void 0) {
427
+ this.payloadBitrate = (this.deltaBytesSent ?? 0 - (stats.headerBytesSent - this.headerBytesSent)) * 8 / (elapsedTimeInMs / 1e3);
428
+ }
429
+ if (this.framesSent !== void 0 && stats.framesSent !== void 0) {
430
+ this.bitPerPixel = this.deltaBytesSent ? this.deltaBytesSent * 8 / (this.framesSent - stats.framesSent) : 0;
431
+ }
432
+ }
433
+ this.timestamp = stats.timestamp;
434
+ this.transportId = stats.transportId;
435
+ this.codecId = stats.codecId;
436
+ this.packetsSent = stats.packetsSent;
437
+ this.bytesSent = stats.bytesSent;
438
+ this.mid = stats.mid;
439
+ this.mediaSourceId = stats.mediaSourceId;
440
+ this.remoteId = stats.remoteId;
441
+ this.rid = stats.rid;
442
+ this.headerBytesSent = stats.headerBytesSent;
443
+ this.retransmittedPacketsSent = stats.retransmittedPacketsSent;
444
+ this.retransmittedBytesSent = stats.retransmittedBytesSent;
445
+ this.rtxSsrc = stats.rtxSsrc;
446
+ this.targetBitrate = stats.targetBitrate;
447
+ this.totalEncodedBytesTarget = stats.totalEncodedBytesTarget;
448
+ this.frameWidth = stats.frameWidth;
449
+ this.frameHeight = stats.frameHeight;
450
+ this.framesPerSecond = stats.framesPerSecond;
451
+ this.framesSent = stats.framesSent;
452
+ this.hugeFramesSent = stats.hugeFramesSent;
453
+ this.framesEncoded = stats.framesEncoded;
454
+ this.keyFramesEncoded = stats.keyFramesEncoded;
455
+ this.qpSum = stats.qpSum;
456
+ this.totalEncodeTime = stats.totalEncodeTime;
457
+ this.totalPacketSendDelay = stats.totalPacketSendDelay;
458
+ this.qualityLimitationReason = stats.qualityLimitationReason;
459
+ this.qualityLimitationResolutionChanges = stats.qualityLimitationResolutionChanges;
460
+ this.nackCount = stats.nackCount;
461
+ this.firCount = stats.firCount;
462
+ this.pliCount = stats.pliCount;
463
+ this.encoderImplementation = stats.encoderImplementation;
464
+ this.powerEfficientEncoder = stats.powerEfficientEncoder;
465
+ this.active = stats.active;
466
+ this.scalabilityMode = stats.scalabilityMode;
467
+ this.qualityLimitationDurations = stats.qualityLimitationDurations;
468
+ this.attachments = stats.attachments;
469
+ }
470
+ };
471
+
472
+ // src/ObservedCertificate.ts
473
+ var ObservedCertificate = class {
474
+ constructor(timestamp, id, _peerConnection) {
475
+ this.timestamp = timestamp;
476
+ this.id = id;
477
+ this._peerConnection = _peerConnection;
478
+ }
479
+ timestamp;
480
+ id;
481
+ _peerConnection;
482
+ appData;
483
+ _visited = false;
484
+ fingerprint;
485
+ fingerprintAlgorithm;
486
+ base64Certificate;
487
+ issuerCertificateId;
488
+ attachments;
489
+ get visited() {
490
+ const visited = this._visited;
491
+ this._visited = false;
492
+ return visited;
493
+ }
494
+ getPeerConnection() {
495
+ return this._peerConnection;
496
+ }
497
+ update(stats) {
498
+ this._visited = true;
499
+ this.timestamp = stats.timestamp;
500
+ this.fingerprint = stats.fingerprint;
501
+ this.fingerprintAlgorithm = stats.fingerprintAlgorithm;
502
+ this.base64Certificate = stats.base64Certificate;
503
+ this.issuerCertificateId = stats.issuerCertificateId;
504
+ this.attachments = stats.attachments;
505
+ }
506
+ };
507
+
508
+ // src/ObservedCodec.ts
509
+ var ObservedCodec = class {
510
+ constructor(timestamp, id, mimeType, _peerConnection) {
511
+ this.timestamp = timestamp;
512
+ this.id = id;
513
+ this.mimeType = mimeType;
514
+ this._peerConnection = _peerConnection;
515
+ }
516
+ timestamp;
517
+ id;
518
+ mimeType;
519
+ _peerConnection;
520
+ _visited = false;
521
+ appData;
522
+ payloadType;
523
+ transportId;
524
+ clockRate;
525
+ channels;
526
+ sdpFmtpLine;
527
+ attachments;
528
+ get visited() {
529
+ const visited = this._visited;
530
+ this._visited = false;
531
+ return visited;
532
+ }
533
+ getPeerConnection() {
534
+ return this._peerConnection;
535
+ }
536
+ getIceTransport() {
537
+ return this._peerConnection.observedIceTransports.get(this.transportId ?? "");
538
+ }
539
+ update(stats) {
540
+ this._visited = true;
541
+ this.timestamp = stats.timestamp;
542
+ this.payloadType = stats.payloadType;
543
+ this.transportId = stats.transportId;
544
+ this.clockRate = stats.clockRate;
545
+ this.channels = stats.channels;
546
+ this.sdpFmtpLine = stats.sdpFmtpLine;
547
+ this.attachments = stats.attachments;
548
+ }
549
+ };
550
+
551
+ // src/ObservedDataChannel.ts
552
+ var ObservedDataChannel = class {
553
+ constructor(timestamp, id, _peerConnection) {
554
+ this.timestamp = timestamp;
555
+ this.id = id;
556
+ this._peerConnection = _peerConnection;
557
+ }
558
+ timestamp;
559
+ id;
560
+ _peerConnection;
561
+ _visited = false;
562
+ label;
563
+ protocol;
564
+ dataChannelIdentifier;
565
+ state;
566
+ messagesSent;
567
+ bytesSent;
568
+ messagesReceived;
569
+ bytesReceived;
570
+ attachments;
571
+ addedAt;
572
+ removedAt;
573
+ deltaBytesSent = 0;
574
+ deltaBytesReceived = 0;
575
+ deltaMessagesSent = 0;
576
+ deltaMessagesReceived = 0;
577
+ appData;
578
+ get visited() {
579
+ const visited = this._visited;
580
+ this._visited = false;
581
+ return visited;
582
+ }
583
+ getPeerConnection() {
584
+ return this._peerConnection;
585
+ }
586
+ update(stats) {
587
+ this._visited = true;
588
+ if (this.messagesSent && stats.messagesSent && stats.messagesSent >= this.messagesSent) {
589
+ this.deltaMessagesSent = stats.messagesSent - this.messagesSent;
590
+ } else {
591
+ this.deltaMessagesSent = 0;
592
+ }
593
+ if (this.messagesReceived && stats.messagesReceived && stats.messagesReceived >= this.messagesReceived) {
594
+ this.deltaMessagesReceived = stats.messagesReceived - this.messagesReceived;
595
+ } else {
596
+ this.deltaMessagesReceived = 0;
597
+ }
598
+ if (this.bytesSent && stats.bytesSent && stats.bytesSent >= this.bytesSent) {
599
+ this.deltaBytesSent = stats.bytesSent - this.bytesSent;
600
+ } else {
601
+ this.deltaBytesSent = 0;
602
+ }
603
+ if (this.bytesReceived && stats.bytesReceived && stats.bytesReceived >= this.bytesReceived) {
604
+ this.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;
605
+ } else {
606
+ this.deltaBytesReceived = 0;
607
+ }
608
+ this.label = stats.label;
609
+ this.protocol = stats.protocol;
610
+ this.dataChannelIdentifier = stats.dataChannelIdentifier;
611
+ this.state = stats.state;
612
+ this.messagesSent = stats.messagesSent;
613
+ this.bytesSent = stats.bytesSent;
614
+ this.messagesReceived = stats.messagesReceived;
615
+ this.bytesReceived = stats.bytesReceived;
616
+ this.attachments = stats.attachments;
617
+ }
618
+ };
619
+
620
+ // src/ObservedIceCandidate.ts
621
+ var ObservedIceCandidate = class {
622
+ constructor(timestamp, id, _peerConnection) {
623
+ this.timestamp = timestamp;
624
+ this.id = id;
625
+ this._peerConnection = _peerConnection;
626
+ }
627
+ timestamp;
628
+ id;
629
+ _peerConnection;
630
+ _visited = false;
631
+ appData;
632
+ transportId;
633
+ address;
634
+ port;
635
+ protocol;
636
+ candidateType;
637
+ priority;
638
+ url;
639
+ relayProtocol;
640
+ foundation;
641
+ relatedAddress;
642
+ relatedPort;
643
+ usernameFragment;
644
+ tcpType;
645
+ attachments;
646
+ get visited() {
647
+ const visited = this._visited;
648
+ this._visited = false;
649
+ return visited;
650
+ }
651
+ getPeerConnection() {
652
+ return this._peerConnection;
653
+ }
654
+ getIceTransport() {
655
+ return this._peerConnection.observedIceTransports.get(this.transportId ?? "");
656
+ }
657
+ update(stats) {
658
+ this._visited = true;
659
+ this.timestamp = stats.timestamp;
660
+ this.transportId = stats.transportId;
661
+ this.address = stats.address;
662
+ this.port = stats.port;
663
+ this.protocol = stats.protocol;
664
+ this.candidateType = stats.candidateType;
665
+ this.priority = stats.priority;
666
+ this.url = stats.url;
667
+ this.relayProtocol = stats.relayProtocol;
668
+ this.foundation = stats.foundation;
669
+ this.relatedAddress = stats.relatedAddress;
670
+ this.relatedPort = stats.relatedPort;
671
+ this.usernameFragment = stats.usernameFragment;
672
+ this.tcpType = stats.tcpType;
673
+ this.attachments = stats.attachments;
674
+ }
675
+ };
676
+
677
+ // src/ObservedIceCandidatePair.ts
678
+ var ObservedIceCandidatePair = class {
679
+ constructor(timestamp, id, _peerConnection) {
680
+ this.timestamp = timestamp;
681
+ this.id = id;
682
+ this._peerConnection = _peerConnection;
683
+ }
684
+ timestamp;
685
+ id;
686
+ _peerConnection;
687
+ _visited = false;
688
+ appData;
689
+ transportId;
690
+ localCandidateId;
691
+ remoteCandidateId;
692
+ state;
693
+ nominated;
694
+ packetsSent;
695
+ packetsReceived;
696
+ bytesSent;
697
+ bytesReceived;
698
+ lastPacketSentTimestamp;
699
+ lastPacketReceivedTimestamp;
700
+ totalRoundTripTime;
701
+ currentRoundTripTime;
702
+ availableOutgoingBitrate;
703
+ availableIncomingBitrate;
704
+ requestsReceived;
705
+ requestsSent;
706
+ responsesReceived;
707
+ responsesSent;
708
+ consentRequestsSent;
709
+ packetsDiscardedOnSend;
710
+ bytesDiscardedOnSend;
711
+ attachments;
712
+ deltaBytesSent = 0;
713
+ deltaBytesReceived = 0;
714
+ deltaPacketsSent = 0;
715
+ deltaPacketsReceived = 0;
716
+ get visited() {
717
+ const visited = this._visited;
718
+ this._visited = false;
719
+ return visited;
720
+ }
721
+ getPeerConnection() {
722
+ return this._peerConnection;
723
+ }
724
+ getIceTransport() {
725
+ return this._peerConnection.observedIceTransports.get(this.transportId ?? "");
726
+ }
727
+ getLocalCandidate() {
728
+ return this._peerConnection.observedIceCandidates.get(this.localCandidateId ?? "");
729
+ }
730
+ getRemoteCandidate() {
731
+ return this._peerConnection.observedIceCandidates.get(this.remoteCandidateId ?? "");
732
+ }
733
+ update(stats) {
734
+ this._visited = true;
735
+ if (this.packetsSent && stats.packetsSent && stats.packetsSent >= this.packetsSent) {
736
+ this.deltaPacketsSent = stats.packetsSent - this.packetsSent;
737
+ } else {
738
+ this.deltaPacketsSent = 0;
739
+ }
740
+ if (this.packetsReceived && stats.packetsReceived && stats.packetsReceived >= this.packetsReceived) {
741
+ this.deltaPacketsReceived = stats.packetsReceived - this.packetsReceived;
742
+ } else {
743
+ this.deltaPacketsReceived = 0;
744
+ }
745
+ if (this.bytesSent && stats.bytesSent && stats.bytesSent >= this.bytesSent) {
746
+ this.deltaBytesSent = stats.bytesSent - this.bytesSent;
747
+ } else {
748
+ this.deltaBytesSent = 0;
749
+ }
750
+ if (this.bytesReceived && stats.bytesReceived && stats.bytesReceived >= this.bytesReceived) {
751
+ this.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;
752
+ } else {
753
+ this.deltaBytesReceived = 0;
754
+ }
755
+ this.timestamp = stats.timestamp;
756
+ this.transportId = stats.transportId;
757
+ this.localCandidateId = stats.localCandidateId;
758
+ this.remoteCandidateId = stats.remoteCandidateId;
759
+ this.state = this._convertState(stats.state);
760
+ this.nominated = stats.nominated;
761
+ this.packetsSent = stats.packetsSent;
762
+ this.packetsReceived = stats.packetsReceived;
763
+ this.bytesSent = stats.bytesSent;
764
+ this.bytesReceived = stats.bytesReceived;
765
+ this.lastPacketSentTimestamp = stats.lastPacketSentTimestamp;
766
+ this.lastPacketReceivedTimestamp = stats.lastPacketReceivedTimestamp;
767
+ this.totalRoundTripTime = stats.totalRoundTripTime;
768
+ this.currentRoundTripTime = stats.currentRoundTripTime;
769
+ this.availableOutgoingBitrate = stats.availableOutgoingBitrate;
770
+ this.availableIncomingBitrate = stats.availableIncomingBitrate;
771
+ this.requestsReceived = stats.requestsReceived;
772
+ this.requestsSent = stats.requestsSent;
773
+ this.responsesReceived = stats.responsesReceived;
774
+ this.responsesSent = stats.responsesSent;
775
+ this.consentRequestsSent = stats.consentRequestsSent;
776
+ this.packetsDiscardedOnSend = stats.packetsDiscardedOnSend;
777
+ this.bytesDiscardedOnSend = stats.bytesDiscardedOnSend;
778
+ this.attachments = stats.attachments;
779
+ }
780
+ _convertState(state) {
781
+ switch (state) {
782
+ case "new":
783
+ case "in-progress":
784
+ case "waiting":
785
+ case "failed":
786
+ case "succeeded":
787
+ return state;
788
+ case "cancelled":
789
+ return "failed";
790
+ case "inprogress":
791
+ return "in-progress";
792
+ default:
793
+ return void 0;
794
+ }
795
+ }
796
+ };
797
+
798
+ // src/ObservedIceTransport.ts
799
+ var ObservedIceTransport = class {
800
+ constructor(timestamp, id, _peerConnection) {
801
+ this.timestamp = timestamp;
802
+ this.id = id;
803
+ this._peerConnection = _peerConnection;
804
+ }
805
+ timestamp;
806
+ id;
807
+ _peerConnection;
808
+ _visited = false;
809
+ appData;
810
+ packetsSent;
811
+ packetsReceived;
812
+ bytesSent;
813
+ bytesReceived;
814
+ iceRole;
815
+ iceLocalUsernameFragment;
816
+ dtlsState;
817
+ iceState;
818
+ selectedCandidatePairId;
819
+ localCertificateId;
820
+ remoteCertificateId;
821
+ tlsVersion;
822
+ dtlsCipher;
823
+ dtlsRole;
824
+ srtpCipher;
825
+ selectedCandidatePairChanges;
826
+ attachments;
827
+ deltaPacketsReceived = 0;
828
+ deltaPacketsSent = 0;
829
+ deltaBytesReceived = 0;
830
+ deltaBytesSent = 0;
831
+ get visited() {
832
+ const visited = this._visited;
833
+ this._visited = false;
834
+ return visited;
835
+ }
836
+ getPeerConnection() {
837
+ return this._peerConnection;
838
+ }
839
+ getSelectedCandidatePair() {
840
+ return this._peerConnection.observedIceCandidatesPair.get(this.selectedCandidatePairId ?? "");
841
+ }
842
+ update(stats) {
843
+ this._visited = true;
844
+ if (this.bytesReceived !== void 0 && stats.bytesReceived !== void 0 && this.bytesReceived <= stats.bytesReceived) {
845
+ this.deltaBytesReceived = stats.bytesReceived - this.bytesReceived;
846
+ } else {
847
+ this.deltaBytesReceived = 0;
848
+ }
849
+ if (this.bytesSent !== void 0 && stats.bytesSent !== void 0 && this.bytesSent <= stats.bytesSent) {
850
+ this.deltaBytesSent = stats.bytesSent - this.bytesSent;
851
+ } else {
852
+ this.deltaBytesSent = 0;
853
+ }
854
+ if (this.packetsReceived !== void 0 && stats.packetsReceived !== void 0 && this.packetsReceived <= stats.packetsReceived) {
855
+ this.deltaPacketsReceived = stats.packetsReceived - this.packetsReceived;
856
+ } else {
857
+ this.deltaPacketsReceived = 0;
858
+ }
859
+ if (this.packetsSent !== void 0 && stats.packetsSent !== void 0 && this.packetsSent <= stats.packetsSent) {
860
+ this.deltaPacketsSent = stats.packetsSent - this.packetsSent;
861
+ } else {
862
+ this.deltaPacketsSent = 0;
863
+ }
864
+ this.timestamp = stats.timestamp;
865
+ this.packetsSent = stats.packetsSent;
866
+ this.packetsReceived = stats.packetsReceived;
867
+ this.bytesSent = stats.bytesSent;
868
+ this.bytesReceived = stats.bytesReceived;
869
+ this.iceRole = stats.iceRole;
870
+ this.iceLocalUsernameFragment = stats.iceLocalUsernameFragment;
871
+ this.dtlsState = stats.dtlsState;
872
+ this.iceState = stats.iceState;
873
+ this.selectedCandidatePairId = stats.selectedCandidatePairId;
874
+ this.localCertificateId = stats.localCertificateId;
875
+ this.remoteCertificateId = stats.remoteCertificateId;
876
+ this.tlsVersion = stats.tlsVersion;
877
+ this.dtlsCipher = stats.dtlsCipher;
878
+ this.dtlsRole = stats.dtlsRole;
879
+ this.srtpCipher = stats.srtpCipher;
880
+ this.selectedCandidatePairChanges = stats.selectedCandidatePairChanges;
881
+ this.attachments = stats.attachments;
882
+ }
883
+ };
884
+
885
+ // src/ObservedMediaSource.ts
886
+ var ObservedMediaSource = class {
887
+ constructor(timestamp, id, kind, _peerConnection) {
888
+ this.timestamp = timestamp;
889
+ this.id = id;
890
+ this.kind = kind;
891
+ this._peerConnection = _peerConnection;
892
+ }
893
+ timestamp;
894
+ id;
895
+ kind;
896
+ _peerConnection;
897
+ _visited = false;
898
+ appData;
899
+ trackIdentifier;
900
+ audioLevel;
901
+ totalAudioEnergy;
902
+ totalSamplesDuration;
903
+ echoReturnLoss;
904
+ echoReturnLossEnhancement;
905
+ width;
906
+ height;
907
+ frames;
908
+ framesPerSecond;
909
+ attachments;
910
+ get visited() {
911
+ const visited = this._visited;
912
+ this._visited = false;
913
+ return visited;
914
+ }
915
+ getPeerConnection() {
916
+ return this._peerConnection;
917
+ }
918
+ getTrack() {
919
+ return this._peerConnection.observedOutboundTracks.get(this.trackIdentifier ?? "");
920
+ }
921
+ update(stats) {
922
+ this._visited = true;
923
+ this.timestamp = stats.timestamp;
924
+ this.trackIdentifier = stats.trackIdentifier;
925
+ this.audioLevel = stats.audioLevel;
926
+ this.totalAudioEnergy = stats.totalAudioEnergy;
927
+ this.totalSamplesDuration = stats.totalSamplesDuration;
928
+ this.echoReturnLoss = stats.echoReturnLoss;
929
+ this.echoReturnLossEnhancement = stats.echoReturnLossEnhancement;
930
+ this.width = stats.width;
931
+ this.height = stats.height;
932
+ this.frames = stats.frames;
933
+ this.framesPerSecond = stats.framesPerSecond;
934
+ this.attachments = stats.attachments;
935
+ }
936
+ };
937
+
938
+ // src/ObservedPeerConnectionTransport.ts
939
+ var ObservedPeerConnectionTransport = class {
940
+ constructor(timestamp, id, _peerConnection) {
941
+ this.timestamp = timestamp;
942
+ this.id = id;
943
+ this._peerConnection = _peerConnection;
944
+ }
945
+ timestamp;
946
+ id;
947
+ _peerConnection;
948
+ _visited = false;
949
+ appData;
950
+ dataChannelsOpened;
951
+ dataChannelsClosed;
952
+ attachments;
953
+ get visited() {
954
+ const visited = this._visited;
955
+ this._visited = false;
956
+ return visited;
957
+ }
958
+ getPeerConnection() {
959
+ return this._peerConnection;
960
+ }
961
+ update(stats) {
962
+ this._visited = true;
963
+ this.timestamp = stats.timestamp;
964
+ this.dataChannelsOpened = stats.dataChannelsOpened;
965
+ this.dataChannelsClosed = stats.dataChannelsClosed;
966
+ this.attachments = stats.attachments;
967
+ }
968
+ };
969
+
970
+ // src/ObservedMediaPlayout.ts
971
+ var ObservedMediaPlayout = class {
972
+ constructor(timestamp, id, kind, _peerConnection) {
973
+ this.timestamp = timestamp;
974
+ this.id = id;
975
+ this.kind = kind;
976
+ this._peerConnection = _peerConnection;
977
+ }
978
+ timestamp;
979
+ id;
980
+ kind;
981
+ _peerConnection;
982
+ _visited = false;
983
+ appData;
984
+ synthesizedSamplesDuration;
985
+ synthesizedSamplesEvents;
986
+ totalSamplesDuration;
987
+ totalPlayoutDelay;
988
+ totalSamplesCount;
989
+ attachments;
990
+ get visited() {
991
+ const visited = this._visited;
992
+ this._visited = false;
993
+ return visited;
994
+ }
995
+ getPeerConnection() {
996
+ return this._peerConnection;
997
+ }
998
+ update(stats) {
999
+ this._visited = true;
1000
+ this.timestamp = stats.timestamp;
1001
+ this.synthesizedSamplesDuration = stats.synthesizedSamplesDuration;
1002
+ this.synthesizedSamplesEvents = stats.synthesizedSamplesEvents;
1003
+ this.totalSamplesDuration = stats.totalSamplesDuration;
1004
+ this.totalPlayoutDelay = stats.totalPlayoutDelay;
1005
+ this.totalSamplesCount = stats.totalSamplesCount;
1006
+ this.attachments = stats.attachments;
1007
+ }
1008
+ };
1009
+
1010
+ // src/ObservedRemoteInboundRtp.ts
1011
+ var ObservedRemoteInboundRtp = class {
1012
+ constructor(timestamp, id, ssrc, kind, _peerConnection) {
1013
+ this.timestamp = timestamp;
1014
+ this.id = id;
1015
+ this.ssrc = ssrc;
1016
+ this.kind = kind;
1017
+ this._peerConnection = _peerConnection;
1018
+ }
1019
+ timestamp;
1020
+ id;
1021
+ ssrc;
1022
+ kind;
1023
+ _peerConnection;
1024
+ _visited = false;
1025
+ appData;
1026
+ transportId;
1027
+ codecId;
1028
+ packetsReceived;
1029
+ packetsLost;
1030
+ jitter;
1031
+ localId;
1032
+ roundTripTime;
1033
+ totalRoundTripTime;
1034
+ fractionLost;
1035
+ roundTripTimeMeasurements;
1036
+ attachments;
1037
+ get visited() {
1038
+ const visited = this._visited;
1039
+ this._visited = false;
1040
+ return visited;
1041
+ }
1042
+ getPeerConnection() {
1043
+ return this._peerConnection;
1044
+ }
1045
+ getOutboundRtp() {
1046
+ return this._peerConnection.observedOutboundRtps.get(this.ssrc);
1047
+ }
1048
+ getCodec() {
1049
+ return this._peerConnection.observedCodecs.get(this.codecId ?? "");
1050
+ }
1051
+ update(stats) {
1052
+ this._visited = true;
1053
+ this.timestamp = stats.timestamp;
1054
+ this.transportId = stats.transportId;
1055
+ this.codecId = stats.codecId;
1056
+ this.packetsReceived = stats.packetsReceived;
1057
+ this.packetsLost = stats.packetsLost;
1058
+ this.jitter = stats.jitter;
1059
+ this.localId = stats.localId;
1060
+ this.roundTripTime = stats.roundTripTime;
1061
+ this.totalRoundTripTime = stats.totalRoundTripTime;
1062
+ this.fractionLost = stats.fractionLost;
1063
+ this.roundTripTimeMeasurements = stats.roundTripTimeMeasurements;
1064
+ this.attachments = stats.attachments;
1065
+ }
1066
+ };
1067
+
1068
+ // src/ObservedRemoteOutboundRtp.ts
1069
+ var ObservedRemoteOutboundRtp = class {
1070
+ constructor(timestamp, id, ssrc, kind, _peerConnection) {
1071
+ this.timestamp = timestamp;
1072
+ this.id = id;
1073
+ this.ssrc = ssrc;
1074
+ this.kind = kind;
1075
+ this._peerConnection = _peerConnection;
1076
+ }
1077
+ timestamp;
1078
+ id;
1079
+ ssrc;
1080
+ kind;
1081
+ _peerConnection;
1082
+ _visited = false;
1083
+ appData;
1084
+ transportId;
1085
+ codecId;
1086
+ packetsSent;
1087
+ bytesSent;
1088
+ localId;
1089
+ remoteTimestamp;
1090
+ reportsSent;
1091
+ roundTripTime;
1092
+ totalRoundTripTime;
1093
+ roundTripTimeMeasurements;
1094
+ attachments;
1095
+ get visited() {
1096
+ const visited = this._visited;
1097
+ this._visited = false;
1098
+ return visited;
1099
+ }
1100
+ getPeerConnection() {
1101
+ return this._peerConnection;
1102
+ }
1103
+ getInboundRtp() {
1104
+ return this._peerConnection.observedInboundRtps.get(this.ssrc);
1105
+ }
1106
+ getCodec() {
1107
+ return this._peerConnection.observedCodecs.get(this.codecId ?? "");
1108
+ }
1109
+ update(stats) {
1110
+ this._visited = true;
1111
+ this.timestamp = stats.timestamp;
1112
+ this.transportId = stats.transportId;
1113
+ this.codecId = stats.codecId;
1114
+ this.packetsSent = stats.packetsSent;
1115
+ this.bytesSent = stats.bytesSent;
1116
+ this.localId = stats.localId;
1117
+ this.remoteTimestamp = stats.remoteTimestamp;
1118
+ this.reportsSent = stats.reportsSent;
1119
+ this.roundTripTime = stats.roundTripTime;
1120
+ this.totalRoundTripTime = stats.totalRoundTripTime;
1121
+ this.roundTripTimeMeasurements = stats.roundTripTimeMeasurements;
1122
+ this.attachments = stats.attachments;
1123
+ }
1124
+ };
1125
+
1126
+ // src/ObservedInboundTrack.ts
1127
+ var ObservedInboundTrack = class {
1128
+ constructor(timestamp, id, kind, _peerConnection, _inboundRtp, _mediaPlayout) {
1129
+ this.timestamp = timestamp;
1130
+ this.id = id;
1131
+ this.kind = kind;
1132
+ this._peerConnection = _peerConnection;
1133
+ this._inboundRtp = _inboundRtp;
1134
+ this._mediaPlayout = _mediaPlayout;
1135
+ }
1136
+ timestamp;
1137
+ id;
1138
+ kind;
1139
+ _peerConnection;
1140
+ _inboundRtp;
1141
+ _mediaPlayout;
1142
+ calculatedScore = {
1143
+ weight: 1,
1144
+ value: void 0
1145
+ };
1146
+ appData;
1147
+ remoteOutboundTrack;
1148
+ _visited = false;
1149
+ addedAt;
1150
+ removedAt;
1151
+ muted;
1152
+ attachments;
1153
+ get score() {
1154
+ return this.calculatedScore.value;
1155
+ }
1156
+ get visited() {
1157
+ const visited = this._visited;
1158
+ this._visited = false;
1159
+ return visited;
1160
+ }
1161
+ getPeerConnection() {
1162
+ return this._peerConnection;
1163
+ }
1164
+ getInboundRtp() {
1165
+ return this._inboundRtp;
1166
+ }
1167
+ getMediaPlayout() {
1168
+ return this._mediaPlayout;
1169
+ }
1170
+ update(stats) {
1171
+ this._visited = true;
1172
+ this.timestamp = stats.timestamp;
1173
+ this.calculatedScore.value = stats.score;
1174
+ this.attachments = stats.attachments;
1175
+ }
1176
+ };
1177
+
1178
+ // src/ObservedOutboundTrack.ts
1179
+ var ObservedOutboundTrack = class {
1180
+ constructor(timestamp, id, kind, _peerConnection, _outboundRtps, _mediaSource) {
1181
+ this.timestamp = timestamp;
1182
+ this.id = id;
1183
+ this.kind = kind;
1184
+ this._peerConnection = _peerConnection;
1185
+ this._outboundRtps = _outboundRtps;
1186
+ this._mediaSource = _mediaSource;
1187
+ }
1188
+ timestamp;
1189
+ id;
1190
+ kind;
1191
+ _peerConnection;
1192
+ _outboundRtps;
1193
+ _mediaSource;
1194
+ _visited = false;
1195
+ appData;
1196
+ remoteInboundTracks = /* @__PURE__ */ new Set();
1197
+ calculatedScore = {
1198
+ weight: 1,
1199
+ value: void 0
1200
+ };
1201
+ addedAt;
1202
+ removedAt;
1203
+ muted;
1204
+ attachments;
1205
+ get score() {
1206
+ return this.calculatedScore.value;
1207
+ }
1208
+ get visited() {
1209
+ const visited = this._visited;
1210
+ this._visited = false;
1211
+ return visited;
1212
+ }
1213
+ getPeerConnection() {
1214
+ return this._peerConnection;
1215
+ }
1216
+ getOutboundRtps() {
1217
+ return this._outboundRtps;
1218
+ }
1219
+ getMediaSource() {
1220
+ return this._mediaSource;
1221
+ }
1222
+ update(stats) {
1223
+ this._visited = true;
1224
+ this.timestamp = stats.timestamp;
1225
+ this.calculatedScore.value = stats.score;
1226
+ this.attachments = stats.attachments;
1227
+ }
1228
+ };
1229
+
1230
+ // src/common/utils.ts
1231
+ function getMedian(arr, copyArrayForSorting = true) {
1232
+ const sortedArr = copyArrayForSorting ? arr.slice().sort((a, b) => a - b) : arr.sort((a, b) => a - b);
1233
+ const mid = Math.floor(sortedArr.length / 2);
1234
+ if (sortedArr.length % 2 !== 0) {
1235
+ return sortedArr[mid];
1236
+ }
1237
+ return (sortedArr[mid - 1] + sortedArr[mid]) / 2;
1238
+ }
1239
+ function parseJsonAs(json) {
1240
+ if (!json) {
1241
+ return void 0;
1242
+ }
1243
+ try {
1244
+ return JSON.parse(json);
1245
+ } catch (error) {
1246
+ return void 0;
1247
+ }
1248
+ }
1249
+
1250
+ // src/ObservedPeerConnection.ts
1251
+ var logger = createLogger("ObservedPeerConnection");
1252
+ var ObservedPeerConnection = class extends import_events.EventEmitter {
1253
+ constructor(peerConnectionId, client) {
1254
+ super();
1255
+ this.peerConnectionId = peerConnectionId;
1256
+ this.client = client;
1257
+ this.setMaxListeners(Infinity);
1258
+ this.eventScope = {
1259
+ observer: client.call.observer,
1260
+ observedCall: client.call,
1261
+ observedClient: client,
1262
+ observedPeerConnection: this
1263
+ };
1264
+ }
1265
+ peerConnectionId;
1266
+ client;
1267
+ _visited = true;
1268
+ appData;
1269
+ calculatedScore = {
1270
+ weight: 1,
1271
+ value: void 0
1272
+ };
1273
+ closed = false;
1274
+ // timestamp of the PEER_CONNECTION_OPENED event
1275
+ openedAt;
1276
+ // timestamp of the PEER_CONNECTION_CLOSED event
1277
+ closedAt;
1278
+ updated = Date.now();
1279
+ connectionState;
1280
+ iceConnectionState;
1281
+ iceGatheringState;
1282
+ availableIncomingBitrate = 0;
1283
+ availableOutgoingBitrate = 0;
1284
+ totalInboundPacketsLost = 0;
1285
+ totalInboundPacketsReceived = 0;
1286
+ totalOutboundPacketsSent = 0;
1287
+ totalDataChannelBytesSent = 0;
1288
+ totalDataChannelBytesReceived = 0;
1289
+ totalDataChannelMessagesSent = 0;
1290
+ totalDataChannelMessagesReceived = 0;
1291
+ totalSentAudioBytes = 0;
1292
+ totalSentVideoBytes = 0;
1293
+ totalSentAudioPackets = 0;
1294
+ totalSentVideoPackets = 0;
1295
+ totalReceivedAudioPacktes = 0;
1296
+ totalReceivedVideoPackets = 0;
1297
+ totalReceivedAudioBytes = 0;
1298
+ totalReceivedVideoBytes = 0;
1299
+ deltaInboundPacketsLost = 0;
1300
+ deltaInboundPacketsReceived = 0;
1301
+ deltaOutboundPacketsSent = 0;
1302
+ deltaDataChannelBytesSent = 0;
1303
+ deltaDataChannelBytesReceived = 0;
1304
+ deltaDataChannelMessagesSent = 0;
1305
+ deltaDataChannelMessagesReceived = 0;
1306
+ deltaInboundReceivedBytes = 0;
1307
+ deltaOutboundSentBytes = 0;
1308
+ deltaReceivedAudioBytes = 0;
1309
+ deltaReceivedVideoBytes = 0;
1310
+ deltaReceivedAudioPackets = 0;
1311
+ deltaReceivedVideoPackets = 0;
1312
+ deltaSentAudioBytes = 0;
1313
+ deltaSentVideoBytes = 0;
1314
+ deltaSentAudioPackets = 0;
1315
+ deltaSentVideoPackets = 0;
1316
+ deltaTransportSentBytes = 0;
1317
+ deltaTransportReceivedBytes = 0;
1318
+ receivingPacketsPerSecond = 0;
1319
+ sendingPacketsPerSecond = 0;
1320
+ sendingAudioBitrate = 0;
1321
+ sendingVideoBitrate = 0;
1322
+ receivingAudioBitrate = 0;
1323
+ receivingVideoBitrate = 0;
1324
+ currentRttInMs;
1325
+ currentJitter;
1326
+ usingTCP = false;
1327
+ usingTURN = false;
1328
+ observedTurnServer;
1329
+ observedCertificates = /* @__PURE__ */ new Map();
1330
+ observedCodecs = /* @__PURE__ */ new Map();
1331
+ observedDataChannels = /* @__PURE__ */ new Map();
1332
+ observedIceCandidates = /* @__PURE__ */ new Map();
1333
+ observedIceCandidatesPair = /* @__PURE__ */ new Map();
1334
+ observedIceTransports = /* @__PURE__ */ new Map();
1335
+ observedInboundRtps = /* @__PURE__ */ new Map();
1336
+ observedInboundTracks = /* @__PURE__ */ new Map();
1337
+ observedMediaPlayouts = /* @__PURE__ */ new Map();
1338
+ observedMediaSources = /* @__PURE__ */ new Map();
1339
+ observedOutboundRtps = /* @__PURE__ */ new Map();
1340
+ observedOutboundTracks = /* @__PURE__ */ new Map();
1341
+ observedPeerConnectionTransports = /* @__PURE__ */ new Map();
1342
+ observedRemoteInboundRtps = /* @__PURE__ */ new Map();
1343
+ observedRemoteOutboundRtps = /* @__PURE__ */ new Map();
1344
+ eventScope;
1345
+ get score() {
1346
+ return this.calculatedScore.value;
1347
+ }
1348
+ get visited() {
1349
+ const visited = this._visited;
1350
+ this._visited = false;
1351
+ return visited;
1352
+ }
1353
+ get codecs() {
1354
+ return [...this.observedCodecs.values()];
1355
+ }
1356
+ get inboundRtps() {
1357
+ return [...this.observedInboundRtps.values()];
1358
+ }
1359
+ get remoteOutboundRtps() {
1360
+ return [...this.observedRemoteOutboundRtps.values()];
1361
+ }
1362
+ get outboundRtps() {
1363
+ return [...this.observedOutboundRtps.values()];
1364
+ }
1365
+ get remoteInboundRtps() {
1366
+ return [...this.observedRemoteInboundRtps.values()];
1367
+ }
1368
+ get mediaSources() {
1369
+ return [...this.observedMediaSources.values()];
1370
+ }
1371
+ get mediaPlayouts() {
1372
+ return [...this.observedMediaPlayouts.values()];
1373
+ }
1374
+ get dataChannels() {
1375
+ return [...this.observedDataChannels.values()];
1376
+ }
1377
+ get peerConnectionTransports() {
1378
+ return [...this.observedPeerConnectionTransports.values()];
1379
+ }
1380
+ get iceTransports() {
1381
+ return [...this.observedIceTransports.values()];
1382
+ }
1383
+ get iceCandidates() {
1384
+ return [...this.observedIceCandidates.values()];
1385
+ }
1386
+ get iceCandidatePairs() {
1387
+ return [...this.observedIceCandidatesPair.values()];
1388
+ }
1389
+ get certificates() {
1390
+ return [...this.observedCertificates.values()];
1391
+ }
1392
+ get selectedIceCandidatePairs() {
1393
+ return this.iceTransports.map((iceTransport) => iceTransport.getSelectedCandidatePair()).filter((pair) => pair !== void 0);
1394
+ }
1395
+ get selectedIceCandiadtePairForTurn() {
1396
+ return this.selectedIceCandidatePairs.filter(
1397
+ (pair) => pair.getLocalCandidate()?.candidateType === "relay" && pair.getRemoteCandidate()?.url?.startsWith("turn:")
1398
+ );
1399
+ }
1400
+ close() {
1401
+ if (this.closed) return;
1402
+ this.closed = true;
1403
+ this.observedCertificates.forEach((observedCertificate) => this._notify("certificate-removed", { ...this.eventScope, observedCertificate }));
1404
+ this.observedCodecs.forEach((observedCodec) => this._notify("codec-removed", { ...this.eventScope, observedCodec }));
1405
+ this.observedDataChannels.forEach((observedDataChannel) => this._notify("data-channel-removed", { ...this.eventScope, observedDataChannel }));
1406
+ this.observedIceCandidates.forEach((observedIceCandidate) => this._notify("ice-candidate-removed", { ...this.eventScope, observedIceCandidate }));
1407
+ this.observedIceCandidatesPair.forEach((pair) => this._notify("ice-candidate-pair-removed", { ...this.eventScope, observedIceCandidatePair: pair }));
1408
+ this.observedIceTransports.forEach((transport) => this._notify("ice-transport-removed", { ...this.eventScope, observedIceTransport: transport }));
1409
+ this.observedInboundRtps.forEach((rtp) => this._notify("inbound-rtp-removed", { ...this.eventScope, observedInboundRtp: rtp }));
1410
+ this.observedInboundTracks.forEach((track) => {
1411
+ this.emit("removed-inbound-track", track);
1412
+ this._notify("inbound-track-removed", { ...this.eventScope, observedInboundTrack: track });
1413
+ });
1414
+ this.observedMediaPlayouts.forEach((playout) => this._notify("media-playout-removed", { ...this.eventScope, observedMediaPlayout: playout }));
1415
+ this.observedMediaSources.forEach((source) => this._notify("media-source-removed", { ...this.eventScope, observedMediaSource: source }));
1416
+ this.observedOutboundRtps.forEach((rtp) => this._notify("outbound-rtp-removed", { ...this.eventScope, observedOutboundRtp: rtp }));
1417
+ this.observedOutboundTracks.forEach((track) => {
1418
+ this.emit("removed-outbound-track", track);
1419
+ this._notify("outbound-track-removed", { ...this.eventScope, observedOutboundTrack: track });
1420
+ });
1421
+ this.observedPeerConnectionTransports.forEach((transport) => this._notify("peer-connection-transport-removed", { ...this.eventScope, observedPeerConnectionTransport: transport }));
1422
+ this.observedRemoteInboundRtps.forEach((rtp) => this._notify("remote-inbound-rtp-removed", { ...this.eventScope, observedRemoteInboundRtp: rtp }));
1423
+ this.observedRemoteOutboundRtps.forEach((rtp) => this._notify("remote-outbound-rtp-removed", { ...this.eventScope, observedRemoteOutboundRtp: rtp }));
1424
+ this.observedCertificates.clear();
1425
+ this.observedCodecs.clear();
1426
+ this.observedDataChannels.clear();
1427
+ this.observedIceCandidates.clear();
1428
+ this.observedIceCandidatesPair.clear();
1429
+ this.observedIceTransports.clear();
1430
+ this.observedInboundRtps.clear();
1431
+ this.observedInboundTracks.clear();
1432
+ this.observedMediaPlayouts.clear();
1433
+ this.observedMediaSources.clear();
1434
+ this.observedOutboundRtps.clear();
1435
+ this.observedOutboundTracks.clear();
1436
+ this.observedPeerConnectionTransports.clear();
1437
+ this.observedRemoteInboundRtps.clear();
1438
+ this.observedRemoteOutboundRtps.clear();
1439
+ this.client.call.observer.observedTURN.removePeerConnection(this);
1440
+ if (!this.closedAt) this.closedAt = Date.now();
1441
+ this.emit("close");
1442
+ this._notify("peer-connection-closed", { ...this.eventScope });
1443
+ }
1444
+ accept(sample, context) {
1445
+ if (this.closed) return;
1446
+ this._visited = true;
1447
+ if (context) this.appData = { ...this.appData, ...context };
1448
+ this.availableIncomingBitrate = 0;
1449
+ this.availableOutgoingBitrate = 0;
1450
+ this.deltaInboundPacketsLost = 0;
1451
+ this.deltaInboundPacketsReceived = 0;
1452
+ this.deltaOutboundPacketsSent = 0;
1453
+ this.deltaDataChannelBytesSent = 0;
1454
+ this.deltaDataChannelBytesReceived = 0;
1455
+ this.deltaInboundReceivedBytes = 0;
1456
+ this.deltaOutboundSentBytes = 0;
1457
+ this.deltaReceivedAudioBytes = 0;
1458
+ this.deltaReceivedVideoBytes = 0;
1459
+ this.deltaReceivedAudioPackets = 0;
1460
+ this.deltaReceivedVideoPackets = 0;
1461
+ this.deltaSentAudioBytes = 0;
1462
+ this.deltaSentVideoBytes = 0;
1463
+ this.deltaSentAudioPackets = 0;
1464
+ this.deltaSentVideoPackets = 0;
1465
+ this.deltaTransportReceivedBytes = 0;
1466
+ this.deltaTransportSentBytes = 0;
1467
+ this.sendingAudioBitrate = 0;
1468
+ this.sendingVideoBitrate = 0;
1469
+ this.receivingAudioBitrate = 0;
1470
+ this.receivingVideoBitrate = 0;
1471
+ const now = Date.now();
1472
+ const elapsedTimeInMs = now - this.updated;
1473
+ const elapsedTimeInSec = elapsedTimeInMs / 1e3;
1474
+ const rttMeasurementsInSec = [];
1475
+ const jitterMeasurements = [];
1476
+ if (sample.certificates) {
1477
+ for (const certificate of sample.certificates) {
1478
+ this._updateCertificateStats(certificate);
1479
+ }
1480
+ }
1481
+ if (sample.codecs) {
1482
+ for (const codec of sample.codecs) {
1483
+ this._updateCodecStats(codec);
1484
+ }
1485
+ }
1486
+ if (sample.dataChannels) {
1487
+ for (const dataChannel of sample.dataChannels) {
1488
+ const observedDataChannel = this._updateDataChannelStats(dataChannel);
1489
+ if (!observedDataChannel) continue;
1490
+ this.deltaDataChannelBytesSent += observedDataChannel.deltaBytesSent;
1491
+ this.deltaDataChannelBytesReceived += observedDataChannel.deltaBytesReceived;
1492
+ this.deltaDataChannelMessagesSent += observedDataChannel.deltaMessagesSent;
1493
+ this.deltaDataChannelMessagesReceived += observedDataChannel.deltaMessagesReceived;
1494
+ }
1495
+ }
1496
+ if (sample.iceCandidates) {
1497
+ for (const iceCandidate of sample.iceCandidates) {
1498
+ this._updateIceCandidateStats(iceCandidate);
1499
+ }
1500
+ }
1501
+ if (sample.iceCandidatePairs) {
1502
+ for (const iceCandidatePair of sample.iceCandidatePairs) {
1503
+ const observedCandidatePair = this._updateIceCandidatePairStats(iceCandidatePair);
1504
+ if (!observedCandidatePair) continue;
1505
+ if (observedCandidatePair.currentRoundTripTime) {
1506
+ rttMeasurementsInSec.push(observedCandidatePair.currentRoundTripTime);
1507
+ }
1508
+ if (observedCandidatePair.availableIncomingBitrate) {
1509
+ this.availableIncomingBitrate += observedCandidatePair.availableIncomingBitrate;
1510
+ }
1511
+ if (observedCandidatePair.availableOutgoingBitrate) {
1512
+ this.availableOutgoingBitrate += observedCandidatePair.availableOutgoingBitrate;
1513
+ }
1514
+ }
1515
+ }
1516
+ if (sample.iceTransports) {
1517
+ for (const iceTransport of sample.iceTransports) {
1518
+ const observedIceTransport = this._updateIceTransportStats(iceTransport);
1519
+ if (!observedIceTransport) continue;
1520
+ }
1521
+ }
1522
+ if (sample.inboundRtps) {
1523
+ for (const inboundRtp of sample.inboundRtps) {
1524
+ const observedInboundRtp = this._updateInboundRtpStats(inboundRtp);
1525
+ if (!observedInboundRtp) continue;
1526
+ this.deltaInboundPacketsLost += observedInboundRtp.deltaLostPackets;
1527
+ this.deltaInboundPacketsReceived += observedInboundRtp.deltaReceivedPackets;
1528
+ this.deltaInboundReceivedBytes += observedInboundRtp.deltaBytesReceived;
1529
+ switch (inboundRtp.kind) {
1530
+ case "audio":
1531
+ this.deltaReceivedAudioBytes += observedInboundRtp.deltaBytesReceived;
1532
+ this.deltaReceivedAudioPackets += observedInboundRtp.deltaReceivedPackets;
1533
+ break;
1534
+ case "video":
1535
+ this.deltaReceivedVideoBytes += observedInboundRtp.deltaBytesReceived;
1536
+ this.deltaReceivedVideoPackets += observedInboundRtp.deltaReceivedPackets;
1537
+ break;
1538
+ }
1539
+ if (observedInboundRtp.jitter) {
1540
+ jitterMeasurements.push(observedInboundRtp.jitter);
1541
+ }
1542
+ }
1543
+ }
1544
+ if (sample.mediaPlayouts) {
1545
+ for (const mediaPlayout of sample.mediaPlayouts) {
1546
+ this._updateMediaPlayoutStats(mediaPlayout);
1547
+ }
1548
+ }
1549
+ if (sample.mediaSources) {
1550
+ for (const mediaSource of sample.mediaSources) {
1551
+ this._updateMediaSourceStats(mediaSource);
1552
+ }
1553
+ }
1554
+ if (sample.outboundRtps) {
1555
+ for (const outboundRtp of sample.outboundRtps) {
1556
+ const observedOutboundRtp = this._updateOutboundRtpStats(outboundRtp);
1557
+ if (!observedOutboundRtp) continue;
1558
+ this.deltaOutboundPacketsSent += observedOutboundRtp.deltaPacketsSent ?? 0;
1559
+ this.deltaOutboundSentBytes += observedOutboundRtp.deltaBytesSent ?? 0;
1560
+ switch (outboundRtp.kind) {
1561
+ case "audio":
1562
+ this.deltaSentAudioBytes += observedOutboundRtp.deltaBytesSent;
1563
+ this.deltaSentAudioPackets += observedOutboundRtp.deltaPacketsSent;
1564
+ break;
1565
+ case "video":
1566
+ this.deltaSentVideoBytes += observedOutboundRtp.deltaBytesSent;
1567
+ this.deltaSentVideoPackets += observedOutboundRtp.deltaPacketsSent;
1568
+ break;
1569
+ }
1570
+ }
1571
+ }
1572
+ if (sample.peerConnectionTransports) {
1573
+ for (const peerConnectionTransport of sample.peerConnectionTransports) {
1574
+ const observedTransport = this._updatePeerConnectionTransportStats(peerConnectionTransport);
1575
+ if (!observedTransport) continue;
1576
+ }
1577
+ }
1578
+ if (sample.remoteInboundRtps) {
1579
+ for (const remoteInboundRtp of sample.remoteInboundRtps) {
1580
+ const observedRemoteInboundRtp = this._updateRemoteInboundRtpStats(remoteInboundRtp);
1581
+ if (!observedRemoteInboundRtp) continue;
1582
+ if (observedRemoteInboundRtp.roundTripTime) {
1583
+ rttMeasurementsInSec.push(observedRemoteInboundRtp.roundTripTime);
1584
+ }
1585
+ const observedOutboundRtp = observedRemoteInboundRtp.getOutboundRtp();
1586
+ if (observedOutboundRtp) {
1587
+ if (observedRemoteInboundRtp.roundTripTime !== void 0) {
1588
+ observedOutboundRtp.remoteRttInMs = observedRemoteInboundRtp.roundTripTime * 1e3;
1589
+ }
1590
+ if (observedRemoteInboundRtp.fractionLost !== void 0) {
1591
+ observedOutboundRtp.remoteFractionLost = observedRemoteInboundRtp.fractionLost;
1592
+ }
1593
+ if (observedRemoteInboundRtp.jitter !== void 0) {
1594
+ observedOutboundRtp.remoteJitter = observedRemoteInboundRtp.jitter;
1595
+ }
1596
+ if (observedRemoteInboundRtp.packetsLost !== void 0) {
1597
+ observedOutboundRtp.remotePacketsLost = observedRemoteInboundRtp.packetsLost;
1598
+ }
1599
+ }
1600
+ }
1601
+ }
1602
+ if (sample.remoteOutboundRtps) {
1603
+ for (const remoteOutboundRtp of sample.remoteOutboundRtps) {
1604
+ const observedRemoteOutboundRtp = this._updateRemoteOutboundRtpStats(remoteOutboundRtp);
1605
+ if (!observedRemoteOutboundRtp) continue;
1606
+ const observedInboundRtp = observedRemoteOutboundRtp.getInboundRtp();
1607
+ if (observedInboundRtp) {
1608
+ if (observedRemoteOutboundRtp.roundTripTime !== void 0) {
1609
+ observedInboundRtp.remoteRttInMs = observedRemoteOutboundRtp.roundTripTime * 1e3;
1610
+ }
1611
+ if (observedRemoteOutboundRtp.bytesSent !== void 0) {
1612
+ observedInboundRtp.remoteBytesSent = observedRemoteOutboundRtp.bytesSent;
1613
+ }
1614
+ if (observedRemoteOutboundRtp.packetsSent !== void 0) {
1615
+ observedInboundRtp.remotePacketsSent = observedRemoteOutboundRtp.packetsSent;
1616
+ }
1617
+ if (observedRemoteOutboundRtp.remoteTimestamp !== void 0) {
1618
+ observedInboundRtp.remoteTimestamp = observedRemoteOutboundRtp.remoteTimestamp;
1619
+ }
1620
+ }
1621
+ }
1622
+ }
1623
+ if (sample.inboundTracks) {
1624
+ for (const inboundTrack of sample.inboundTracks) {
1625
+ this._updateInboundTrackSample(inboundTrack);
1626
+ }
1627
+ }
1628
+ if (sample.outboundTracks) {
1629
+ for (const outboundTrack of sample.outboundTracks) {
1630
+ this._updateOutboundTrackSample(outboundTrack);
1631
+ }
1632
+ }
1633
+ this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
1634
+ this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
1635
+ this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
1636
+ this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
1637
+ this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
1638
+ this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
1639
+ this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
1640
+ this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
1641
+ this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
1642
+ this.totalSentAudioBytes += this.deltaSentAudioBytes;
1643
+ this.totalSentVideoBytes += this.deltaSentVideoBytes;
1644
+ this.totalReceivedAudioPacktes += this.deltaReceivedAudioPackets;
1645
+ this.totalReceivedVideoPackets += this.deltaReceivedVideoPackets;
1646
+ this.totalSentAudioPackets += this.deltaSentAudioPackets;
1647
+ this.totalSentVideoPackets += this.deltaSentVideoPackets;
1648
+ this.receivingPacketsPerSecond = this.deltaInboundPacketsReceived / elapsedTimeInSec;
1649
+ this.sendingPacketsPerSecond = this.deltaOutboundPacketsSent / elapsedTimeInSec;
1650
+ this.sendingAudioBitrate = this.deltaSentAudioBytes * 8 / elapsedTimeInSec;
1651
+ this.sendingVideoBitrate = this.deltaSentVideoBytes * 8 / elapsedTimeInSec;
1652
+ this.receivingAudioBitrate = this.deltaReceivedAudioBytes * 8 / elapsedTimeInSec;
1653
+ this.receivingVideoBitrate = this.deltaReceivedVideoBytes * 8 / elapsedTimeInSec;
1654
+ if (rttMeasurementsInSec.length > 0) {
1655
+ this.currentRttInMs = getMedian(rttMeasurementsInSec, false) * 1e3;
1656
+ } else {
1657
+ this.currentRttInMs = void 0;
1658
+ }
1659
+ if (jitterMeasurements.length > 0) {
1660
+ this.currentJitter = getMedian(jitterMeasurements, false);
1661
+ } else {
1662
+ this.currentJitter = void 0;
1663
+ }
1664
+ const wasUsingTURN = this.usingTURN;
1665
+ const selectedIceCandidatePairs = this.selectedIceCandidatePairs;
1666
+ const selectedCandidatePairForTurn = [];
1667
+ this.usingTCP = false;
1668
+ this.usingTURN = false;
1669
+ for (const selectedCandidatePair of selectedIceCandidatePairs) {
1670
+ if (selectedCandidatePair.getLocalCandidate()?.protocol === "tcp") {
1671
+ this.usingTCP = true;
1672
+ }
1673
+ if (selectedCandidatePair.getLocalCandidate()?.candidateType === "relay" && selectedCandidatePair.getRemoteCandidate()?.url?.startsWith("turn:")) {
1674
+ selectedCandidatePairForTurn.push(selectedCandidatePair);
1675
+ this.usingTURN = true;
1676
+ }
1677
+ this.deltaTransportReceivedBytes += selectedCandidatePair.deltaBytesReceived;
1678
+ this.deltaTransportSentBytes += selectedCandidatePair.deltaBytesSent;
1679
+ }
1680
+ if (this.usingTURN) {
1681
+ if (!this.observedTurnServer) {
1682
+ this.observedTurnServer = this.client.call.observer.observedTURN.addPeerConnection(this);
1683
+ }
1684
+ this.observedTurnServer?.updateTurnUsage(...selectedCandidatePairForTurn);
1685
+ } else if (wasUsingTURN) {
1686
+ if (!this.usingTURN) {
1687
+ this.client.call.observer.observedTURN.removePeerConnection(this);
1688
+ }
1689
+ }
1690
+ this.calculatedScore.value = sample.score;
1691
+ this.updated = now;
1692
+ this._checkVisited();
1693
+ this._notify("peer-connection-updated", { ...this.eventScope, context });
1694
+ }
1695
+ _checkVisited() {
1696
+ for (const certificate of [...this.observedCertificates.values()]) {
1697
+ if (certificate.visited) continue;
1698
+ this.observedCertificates.delete(certificate.id);
1699
+ }
1700
+ for (const observedCodec of [...this.observedCodecs.values()]) {
1701
+ if (observedCodec.visited) continue;
1702
+ this.observedCodecs.delete(observedCodec.id);
1703
+ this._notify("codec-removed", { ...this.eventScope, observedCodec });
1704
+ }
1705
+ for (const observedDataChannel of [...this.observedDataChannels.values()]) {
1706
+ if (observedDataChannel.visited) continue;
1707
+ this.observedDataChannels.delete(observedDataChannel.id);
1708
+ this._notify("data-channel-removed", { ...this.eventScope, observedDataChannel });
1709
+ }
1710
+ for (const observedIceCandidate of [...this.observedIceCandidates.values()]) {
1711
+ if (observedIceCandidate.visited) continue;
1712
+ this.observedIceCandidates.delete(observedIceCandidate.id);
1713
+ this._notify("ice-candidate-removed", { ...this.eventScope, observedIceCandidate });
1714
+ }
1715
+ for (const observedIceCandidatePair of [...this.observedIceCandidatesPair.values()]) {
1716
+ if (observedIceCandidatePair.visited) continue;
1717
+ this.observedIceCandidatesPair.delete(observedIceCandidatePair.id);
1718
+ this._notify("ice-candidate-pair-removed", { ...this.eventScope, observedIceCandidatePair });
1719
+ }
1720
+ for (const observedIceTransport of [...this.observedIceTransports.values()]) {
1721
+ if (observedIceTransport.visited) continue;
1722
+ this.observedIceTransports.delete(observedIceTransport.id);
1723
+ this._notify("ice-transport-removed", { ...this.eventScope, observedIceTransport });
1724
+ }
1725
+ for (const observedInboundRtp of [...this.observedInboundRtps.values()]) {
1726
+ if (observedInboundRtp.visited) continue;
1727
+ this.observedInboundRtps.delete(observedInboundRtp.ssrc);
1728
+ this._notify("inbound-rtp-removed", { ...this.eventScope, observedInboundRtp });
1729
+ }
1730
+ for (const observedInboundTrack of [...this.observedInboundTracks.values()]) {
1731
+ if (observedInboundTrack.visited) continue;
1732
+ this.observedInboundTracks.delete(observedInboundTrack.id);
1733
+ this.emit("removed-inbound-track", observedInboundTrack);
1734
+ this._notify("inbound-track-removed", { ...this.eventScope, observedInboundTrack });
1735
+ }
1736
+ for (const observedMediaPlayout of [...this.observedMediaPlayouts.values()]) {
1737
+ if (observedMediaPlayout.visited) continue;
1738
+ this.observedMediaPlayouts.delete(observedMediaPlayout.id);
1739
+ this._notify("media-playout-removed", { ...this.eventScope, observedMediaPlayout });
1740
+ }
1741
+ for (const observedMediaSource of [...this.observedMediaSources.values()]) {
1742
+ if (observedMediaSource.visited) continue;
1743
+ this.observedMediaSources.delete(observedMediaSource.id);
1744
+ this._notify("media-source-removed", { ...this.eventScope, observedMediaSource });
1745
+ }
1746
+ for (const observedOutboundRtp of [...this.observedOutboundRtps.values()]) {
1747
+ if (observedOutboundRtp.visited) continue;
1748
+ this.observedOutboundRtps.delete(observedOutboundRtp.ssrc);
1749
+ this._notify("outbound-rtp-removed", { ...this.eventScope, observedOutboundRtp });
1750
+ }
1751
+ for (const observedOutboundTrack of [...this.observedOutboundTracks.values()]) {
1752
+ if (observedOutboundTrack.visited) continue;
1753
+ this.observedOutboundTracks.delete(observedOutboundTrack.id);
1754
+ this.emit("removed-outbound-track", observedOutboundTrack);
1755
+ this._notify("outbound-track-removed", { ...this.eventScope, observedOutboundTrack });
1756
+ }
1757
+ for (const observedPeerConnectionTransport of [...this.observedPeerConnectionTransports.values()]) {
1758
+ if (observedPeerConnectionTransport.visited) continue;
1759
+ this.observedPeerConnectionTransports.delete(observedPeerConnectionTransport.id);
1760
+ this._notify("peer-connection-transport-removed", { ...this.eventScope, observedPeerConnectionTransport });
1761
+ }
1762
+ for (const observedRemoteInboundRtp of [...this.observedRemoteInboundRtps.values()]) {
1763
+ if (observedRemoteInboundRtp.visited) continue;
1764
+ this.observedRemoteInboundRtps.delete(observedRemoteInboundRtp.ssrc);
1765
+ this._notify("remote-inbound-rtp-removed", { ...this.eventScope, observedRemoteInboundRtp });
1766
+ }
1767
+ for (const observedRemoteOutboundRtp of [...this.observedRemoteOutboundRtps.values()]) {
1768
+ if (observedRemoteOutboundRtp.visited) continue;
1769
+ this.observedRemoteOutboundRtps.delete(observedRemoteOutboundRtp.ssrc);
1770
+ this._notify("remote-outbound-rtp-removed", { ...this.eventScope, observedRemoteOutboundRtp });
1771
+ }
1772
+ }
1773
+ _updateCertificateStats(stats) {
1774
+ let observedCertificate = this.observedCertificates.get(stats.id);
1775
+ if (!observedCertificate) {
1776
+ if (!stats.timestamp || !stats.id || !stats.fingerprint) {
1777
+ return logger.warn(
1778
+ `ObservedPeerConnection received an invalid CertificateStats (missing timestamp OR id OR fingerprint field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1779
+ stats
1780
+ );
1781
+ }
1782
+ observedCertificate = new ObservedCertificate(stats.timestamp, stats.id, this);
1783
+ observedCertificate.update(stats);
1784
+ this.observedCertificates.set(stats.id, observedCertificate);
1785
+ this._notify("certificate-added", { ...this.eventScope, observedCertificate });
1786
+ } else {
1787
+ observedCertificate.update(stats);
1788
+ this._notify("certificate-updated", { ...this.eventScope, observedCertificate });
1789
+ }
1790
+ return observedCertificate;
1791
+ }
1792
+ _updateCodecStats(stats) {
1793
+ let observedCodec = this.observedCodecs.get(stats.id);
1794
+ if (!observedCodec) {
1795
+ if (!stats.timestamp || !stats.id || !stats.mimeType) {
1796
+ return logger.warn(
1797
+ `ObservedPeerConnection received an invalid CodecStats (missing timestamp OR id OR mimeType field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1798
+ stats
1799
+ );
1800
+ }
1801
+ observedCodec = new ObservedCodec(stats.timestamp, stats.id, stats.mimeType, this);
1802
+ observedCodec.update(stats);
1803
+ this.observedCodecs.set(stats.id, observedCodec);
1804
+ this._notify("codec-added", { ...this.eventScope, observedCodec });
1805
+ } else {
1806
+ observedCodec.update(stats);
1807
+ }
1808
+ this._notify("codec-updated", { ...this.eventScope, observedCodec });
1809
+ return observedCodec;
1810
+ }
1811
+ _updateDataChannelStats(stats) {
1812
+ let observedDataChannel = this.observedDataChannels.get(stats.id);
1813
+ if (!observedDataChannel) {
1814
+ if (!stats.timestamp || !stats.id) {
1815
+ return logger.warn(
1816
+ `ObservedPeerConnection received an invalid DataChannelStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1817
+ stats
1818
+ );
1819
+ }
1820
+ observedDataChannel = new ObservedDataChannel(stats.timestamp, stats.id, this);
1821
+ observedDataChannel.update(stats);
1822
+ this.observedDataChannels.set(stats.id, observedDataChannel);
1823
+ this._notify("data-channel-added", { ...this.eventScope, observedDataChannel });
1824
+ } else {
1825
+ observedDataChannel.update(stats);
1826
+ }
1827
+ this._notify("data-channel-updated", { ...this.eventScope, observedDataChannel });
1828
+ return observedDataChannel;
1829
+ }
1830
+ _updateIceCandidateStats(stats) {
1831
+ let observedIceCandidate = this.observedIceCandidates.get(stats.id);
1832
+ if (!observedIceCandidate) {
1833
+ if (!stats.timestamp || !stats.id) {
1834
+ return logger.warn(
1835
+ `ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1836
+ stats
1837
+ );
1838
+ }
1839
+ observedIceCandidate = new ObservedIceCandidate(stats.timestamp, stats.id, this);
1840
+ observedIceCandidate.update(stats);
1841
+ this.observedIceCandidates.set(stats.id, observedIceCandidate);
1842
+ this._notify("ice-candidate-added", { ...this.eventScope, observedIceCandidate });
1843
+ } else {
1844
+ observedIceCandidate.update(stats);
1845
+ }
1846
+ this._notify("ice-candidate-updated", { ...this.eventScope, observedIceCandidate });
1847
+ return observedIceCandidate;
1848
+ }
1849
+ _updateIceCandidatePairStats(stats) {
1850
+ let observedIceCandidatePair = this.observedIceCandidatesPair.get(stats.id);
1851
+ if (!observedIceCandidatePair) {
1852
+ if (!stats.timestamp || !stats.id) {
1853
+ return logger.warn(
1854
+ `ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1855
+ stats
1856
+ );
1857
+ }
1858
+ observedIceCandidatePair = new ObservedIceCandidatePair(stats.timestamp, stats.id, this);
1859
+ observedIceCandidatePair.update(stats);
1860
+ this.observedIceCandidatesPair.set(stats.id, observedIceCandidatePair);
1861
+ this._notify("ice-candidate-pair-added", { ...this.eventScope, observedIceCandidatePair });
1862
+ } else {
1863
+ observedIceCandidatePair.update(stats);
1864
+ }
1865
+ this._notify("ice-candidate-pair-updated", { ...this.eventScope, observedIceCandidatePair });
1866
+ return observedIceCandidatePair;
1867
+ }
1868
+ _updateIceTransportStats(stats) {
1869
+ let observedIceTransport = this.observedIceTransports.get(stats.id);
1870
+ if (!observedIceTransport) {
1871
+ if (!stats.timestamp || !stats.id) {
1872
+ return logger.warn(
1873
+ `ObservedPeerConnection received an invalid IceCandidateStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1874
+ stats
1875
+ );
1876
+ }
1877
+ observedIceTransport = new ObservedIceTransport(stats.timestamp, stats.id, this);
1878
+ observedIceTransport.update(stats);
1879
+ this.observedIceTransports.set(stats.id, observedIceTransport);
1880
+ this._notify("ice-transport-added", { ...this.eventScope, observedIceTransport });
1881
+ } else {
1882
+ observedIceTransport.update(stats);
1883
+ }
1884
+ this._notify("ice-transport-updated", { ...this.eventScope, observedIceTransport });
1885
+ return observedIceTransport;
1886
+ }
1887
+ _updateInboundRtpStats(stats) {
1888
+ let observedInboundRtp = this.observedInboundRtps.get(stats.ssrc);
1889
+ if (!observedInboundRtp) {
1890
+ if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind || !stats.trackIdentifier) {
1891
+ return logger.warn(
1892
+ `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}`,
1893
+ stats
1894
+ );
1895
+ }
1896
+ observedInboundRtp = new ObservedInboundRtp(
1897
+ stats.timestamp,
1898
+ stats.id,
1899
+ stats.ssrc,
1900
+ stats.kind,
1901
+ stats.trackIdentifier,
1902
+ this
1903
+ );
1904
+ observedInboundRtp.update(stats);
1905
+ this.observedInboundRtps.set(stats.ssrc, observedInboundRtp);
1906
+ this._notify("inbound-rtp-added", { ...this.eventScope, observedInboundRtp });
1907
+ } else {
1908
+ observedInboundRtp.update(stats);
1909
+ }
1910
+ this._notify("inbound-rtp-updated", { ...this.eventScope, observedInboundRtp });
1911
+ return observedInboundRtp;
1912
+ }
1913
+ _updateInboundTrackSample(stats) {
1914
+ let observedInboundTrack = this.observedInboundTracks.get(stats.id);
1915
+ if (!observedInboundTrack) {
1916
+ if (!stats.timestamp || !stats.id || !stats.kind) {
1917
+ return logger.warn(
1918
+ `ObservedPeerConnection received an invalid InboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1919
+ stats
1920
+ );
1921
+ }
1922
+ const inboundRtp = [...this.observedInboundRtps.values()].find((inbRtp) => inbRtp.trackIdentifier === stats.id);
1923
+ const mediaPlayout = inboundRtp ? [...this.observedMediaPlayouts.values()].find((mp) => mp.id === inboundRtp.playoutId) : void 0;
1924
+ observedInboundTrack = new ObservedInboundTrack(
1925
+ stats.timestamp,
1926
+ stats.id,
1927
+ stats.kind,
1928
+ this,
1929
+ inboundRtp,
1930
+ mediaPlayout
1931
+ );
1932
+ observedInboundTrack.update(stats);
1933
+ this.observedInboundTracks.set(stats.id, observedInboundTrack);
1934
+ this._notify("inbound-track-added", { ...this.eventScope, observedInboundTrack });
1935
+ } else {
1936
+ observedInboundTrack.update(stats);
1937
+ }
1938
+ this._notify("inbound-track-updated", { ...this.eventScope, observedInboundTrack });
1939
+ return observedInboundTrack;
1940
+ }
1941
+ _updateMediaPlayoutStats(stats) {
1942
+ let observedMediaPlayout = this.observedMediaPlayouts.get(stats.id);
1943
+ if (!observedMediaPlayout) {
1944
+ if (!stats.timestamp || !stats.id || !stats.kind) {
1945
+ return logger.warn(
1946
+ `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}`,
1947
+ stats
1948
+ );
1949
+ }
1950
+ observedMediaPlayout = new ObservedMediaPlayout(
1951
+ stats.timestamp,
1952
+ stats.id,
1953
+ stats.kind,
1954
+ this
1955
+ );
1956
+ observedMediaPlayout.update(stats);
1957
+ this.observedMediaPlayouts.set(stats.id, observedMediaPlayout);
1958
+ this._notify("media-playout-added", { ...this.eventScope, observedMediaPlayout });
1959
+ } else {
1960
+ observedMediaPlayout.update(stats);
1961
+ }
1962
+ this._notify("media-playout-updated", { ...this.eventScope, observedMediaPlayout });
1963
+ return observedMediaPlayout;
1964
+ }
1965
+ _updateMediaSourceStats(stats) {
1966
+ let observedMediaSource = this.observedMediaSources.get(stats.id);
1967
+ if (!observedMediaSource) {
1968
+ if (!stats.timestamp || !stats.id || !stats.kind) {
1969
+ return logger.warn(
1970
+ `ObservedPeerConnection received an invalid InboundRtpStats (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
1971
+ stats
1972
+ );
1973
+ }
1974
+ observedMediaSource = new ObservedMediaSource(
1975
+ stats.timestamp,
1976
+ stats.id,
1977
+ stats.kind,
1978
+ this
1979
+ );
1980
+ observedMediaSource.update(stats);
1981
+ this.observedMediaSources.set(stats.id, observedMediaSource);
1982
+ this._notify("media-source-added", { ...this.eventScope, observedMediaSource });
1983
+ } else {
1984
+ observedMediaSource.update(stats);
1985
+ }
1986
+ this._notify("media-source-updated", { ...this.eventScope, observedMediaSource });
1987
+ return observedMediaSource;
1988
+ }
1989
+ _updateOutboundRtpStats(stats) {
1990
+ let observedOutboundRtp = this.observedOutboundRtps.get(stats.ssrc);
1991
+ if (!observedOutboundRtp) {
1992
+ if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
1993
+ return logger.warn(
1994
+ `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}`,
1995
+ stats
1996
+ );
1997
+ }
1998
+ observedOutboundRtp = new ObservedOutboundRtp(
1999
+ stats.timestamp,
2000
+ stats.id,
2001
+ stats.ssrc,
2002
+ stats.kind,
2003
+ this
2004
+ );
2005
+ observedOutboundRtp.update(stats);
2006
+ this.observedOutboundRtps.set(stats.ssrc, observedOutboundRtp);
2007
+ this._notify("outbound-rtp-added", { ...this.eventScope, observedOutboundRtp });
2008
+ } else {
2009
+ observedOutboundRtp.update(stats);
2010
+ }
2011
+ this._notify("outbound-rtp-updated", { ...this.eventScope, observedOutboundRtp });
2012
+ return observedOutboundRtp;
2013
+ }
2014
+ _updateOutboundTrackSample(stats) {
2015
+ let observedOutboundTrack = this.observedOutboundTracks.get(stats.id);
2016
+ if (!observedOutboundTrack) {
2017
+ if (!stats.timestamp || !stats.id || !stats.kind) {
2018
+ return logger.warn(
2019
+ `ObservedPeerConnection received an invalid OutboundTrackSample (missing timestamp OR id OR kind field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
2020
+ stats
2021
+ );
2022
+ }
2023
+ const observedMediaSource = [...this.observedMediaSources.values()].find((mediaSource) => mediaSource.trackIdentifier === stats.id);
2024
+ const outboundRtps = observedMediaSource ? [...this.observedOutboundRtps.values()].filter((outboundRtp) => outboundRtp.mediaSourceId === observedMediaSource?.id) : void 0;
2025
+ observedOutboundTrack = new ObservedOutboundTrack(
2026
+ stats.timestamp,
2027
+ stats.id,
2028
+ stats.kind,
2029
+ this,
2030
+ outboundRtps,
2031
+ observedMediaSource
2032
+ );
2033
+ observedOutboundTrack.update(stats);
2034
+ this.observedOutboundTracks.set(stats.id, observedOutboundTrack);
2035
+ this._notify("outbound-track-added", { ...this.eventScope, observedOutboundTrack });
2036
+ } else {
2037
+ observedOutboundTrack.update(stats);
2038
+ }
2039
+ this._notify("outbound-track-updated", { ...this.eventScope, observedOutboundTrack });
2040
+ return observedOutboundTrack;
2041
+ }
2042
+ _updatePeerConnectionTransportStats(stats) {
2043
+ let observedPeerConnectionTransport = this.observedPeerConnectionTransports.get(stats.id);
2044
+ if (!observedPeerConnectionTransport) {
2045
+ if (!stats.timestamp || !stats.id) {
2046
+ return logger.warn(
2047
+ `ObservedPeerConnection received an invalid PeerConnectionTransportStats (missing timestamp OR id field). PeerConnectionId: ${this.peerConnectionId} ClientId: ${this.client.clientId}, CallId: ${this.client.call.callId}`,
2048
+ stats
2049
+ );
2050
+ }
2051
+ observedPeerConnectionTransport = new ObservedPeerConnectionTransport(stats.timestamp, stats.id, this);
2052
+ observedPeerConnectionTransport.update(stats);
2053
+ this.observedPeerConnectionTransports.set(stats.id, observedPeerConnectionTransport);
2054
+ this._notify("peer-connection-transport-added", { ...this.eventScope, observedPeerConnectionTransport });
2055
+ } else {
2056
+ observedPeerConnectionTransport.update(stats);
2057
+ }
2058
+ this._notify("peer-connection-transport-updated", { ...this.eventScope, observedPeerConnectionTransport });
2059
+ return observedPeerConnectionTransport;
2060
+ }
2061
+ _updateRemoteInboundRtpStats(stats) {
2062
+ let observedRemoteInboundRtp = this.observedRemoteInboundRtps.get(stats.ssrc);
2063
+ if (!observedRemoteInboundRtp) {
2064
+ if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
2065
+ return logger.warn(
2066
+ `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}`,
2067
+ stats
2068
+ );
2069
+ }
2070
+ observedRemoteInboundRtp = new ObservedRemoteInboundRtp(
2071
+ stats.timestamp,
2072
+ stats.id,
2073
+ stats.ssrc,
2074
+ stats.kind,
2075
+ this
2076
+ );
2077
+ observedRemoteInboundRtp.update(stats);
2078
+ this.observedRemoteInboundRtps.set(stats.ssrc, observedRemoteInboundRtp);
2079
+ this._notify("remote-inbound-rtp-added", { ...this.eventScope, observedRemoteInboundRtp });
2080
+ } else {
2081
+ observedRemoteInboundRtp.update(stats);
2082
+ }
2083
+ this._notify("remote-inbound-rtp-updated", { ...this.eventScope, observedRemoteInboundRtp });
2084
+ return observedRemoteInboundRtp;
2085
+ }
2086
+ _updateRemoteOutboundRtpStats(stats) {
2087
+ let observedRemoteOutboundRtp = this.observedRemoteOutboundRtps.get(stats.ssrc);
2088
+ if (!observedRemoteOutboundRtp) {
2089
+ if (!stats.timestamp || !stats.id || !stats.ssrc || !stats.kind) {
2090
+ return logger.warn(
2091
+ `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}`,
2092
+ stats
2093
+ );
2094
+ }
2095
+ observedRemoteOutboundRtp = new ObservedRemoteOutboundRtp(
2096
+ stats.timestamp,
2097
+ stats.id,
2098
+ stats.ssrc,
2099
+ stats.kind,
2100
+ this
2101
+ );
2102
+ observedRemoteOutboundRtp.update(stats);
2103
+ this.observedRemoteOutboundRtps.set(stats.ssrc, observedRemoteOutboundRtp);
2104
+ this._notify("remote-outbound-rtp-added", { ...this.eventScope, observedRemoteOutboundRtp });
2105
+ } else {
2106
+ observedRemoteOutboundRtp.update(stats);
2107
+ }
2108
+ this._notify("remote-outbound-rtp-updated", { ...this.eventScope, observedRemoteOutboundRtp });
2109
+ return observedRemoteOutboundRtp;
2110
+ }
2111
+ /** Emit an Observer-bus event scoped to this peer connection. */
2112
+ _notify(type, ...args) {
2113
+ this.client.call.observer.emit(type, ...args);
2114
+ }
2115
+ };
2116
+
2117
+ // src/schema/ClientEventTypes.ts
2118
+ var ClientEventTypes = /* @__PURE__ */ ((ClientEventTypes2) => {
2119
+ ClientEventTypes2["CLIENT_JOINED"] = "CLIENT_JOINED";
2120
+ ClientEventTypes2["CLIENT_LEFT"] = "CLIENT_LEFT";
2121
+ ClientEventTypes2["PEER_CONNECTION_OPENED"] = "PEER_CONNECTION_OPENED";
2122
+ ClientEventTypes2["PEER_CONNECTION_CLOSED"] = "PEER_CONNECTION_CLOSED";
2123
+ ClientEventTypes2["MEDIA_TRACK_ADDED"] = "MEDIA_TRACK_ADDED";
2124
+ ClientEventTypes2["MEDIA_TRACK_REMOVED"] = "MEDIA_TRACK_REMOVED";
2125
+ ClientEventTypes2["MEDIA_TRACK_RESUMED"] = "MEDIA_TRACK_RESUMED";
2126
+ ClientEventTypes2["MEDIA_TRACK_MUTED"] = "MEDIA_TRACK_MUTED";
2127
+ ClientEventTypes2["MEDIA_TRACK_UNMUTED"] = "MEDIA_TRACK_UNMUTED";
2128
+ ClientEventTypes2["ICE_GATHERING_STATE_CHANGED"] = "ICE_GATHERING_STATE_CHANGED";
2129
+ ClientEventTypes2["PEER_CONNECTION_STATE_CHANGED"] = "PEER_CONNECTION_STATE_CHANGED";
2130
+ ClientEventTypes2["ICE_CONNECTION_STATE_CHANGED"] = "ICE_CONNECTION_STATE_CHANGED";
2131
+ ClientEventTypes2["DATA_CHANNEL_OPEN"] = "DATA_CHANNEL_OPEN";
2132
+ ClientEventTypes2["DATA_CHANNEL_CLOSED"] = "DATA_CHANNEL_CLOSED";
2133
+ ClientEventTypes2["DATA_CHANNEL_ERROR"] = "DATA_CHANNEL_ERROR";
2134
+ ClientEventTypes2["NEGOTIATION_NEEDED"] = "NEGOTIATION_NEEDED";
2135
+ ClientEventTypes2["SIGNALING_STATE_CHANGE"] = "SIGNALING_STATE_CHANGE";
2136
+ ClientEventTypes2["ICE_CANDIDATE"] = "ICE_CANDIDATE";
2137
+ ClientEventTypes2["ICE_CANDIDATE_ERROR"] = "ICE_CANDIDATE_ERROR";
2138
+ ClientEventTypes2["PRODUCER_ADDED"] = "PRODUCER_ADDED";
2139
+ ClientEventTypes2["PRODUCER_REMOVED"] = "PRODUCER_REMOVED";
2140
+ ClientEventTypes2["PRODUCER_PAUSED"] = "PRODUCER_PAUSED";
2141
+ ClientEventTypes2["PRODUCER_RESUMED"] = "PRODUCER_RESUMED";
2142
+ ClientEventTypes2["CONSUMER_ADDED"] = "CONSUMER_ADDED";
2143
+ ClientEventTypes2["CONSUMER_REMOVED"] = "CONSUMER_REMOVED";
2144
+ ClientEventTypes2["CONSUMER_PAUSED"] = "CONSUMER_PAUSED";
2145
+ ClientEventTypes2["CONSUMER_RESUMED"] = "CONSUMER_RESUMED";
2146
+ ClientEventTypes2["DATA_PRODUCER_CREATED"] = "DATA_PRODUCER_CREATED";
2147
+ ClientEventTypes2["DATA_PRODUCER_CLOSED"] = "DATA_PRODUCER_CLOSED";
2148
+ ClientEventTypes2["DATA_CONSUMER_CREATED"] = "DATA_CONSUMER_CREATED";
2149
+ ClientEventTypes2["DATA_CONSUMER_CLOSED"] = "DATA_CONSUMER_CLOSED";
2150
+ return ClientEventTypes2;
2151
+ })(ClientEventTypes || {});
2152
+
2153
+ // src/schema/ClientMetaTypes.ts
2154
+ var ClientMetaTypes = /* @__PURE__ */ ((ClientMetaTypes2) => {
2155
+ ClientMetaTypes2["MEDIA_CONSTRAINT"] = "MEDIA_CONSTRAINT";
2156
+ ClientMetaTypes2["MEDIA_DEVICE"] = "MEDIA_DEVICE";
2157
+ ClientMetaTypes2["MEDIA_DEVICES_SUPPORTED_CONSTRAINTS"] = "MEDIA_DEVICES_SUPPORTED_CONSTRAINTS";
2158
+ ClientMetaTypes2["USER_MEDIA_ERROR"] = "USER_MEDIA_ERROR";
2159
+ ClientMetaTypes2["LOCAL_SDP"] = "LOCAL_SDP";
2160
+ ClientMetaTypes2["OPERATION_SYSTEM"] = "OPERATION_SYSTEM";
2161
+ ClientMetaTypes2["ENGINE"] = "ENGINE";
2162
+ ClientMetaTypes2["PLATFORM"] = "PLATFORM";
2163
+ ClientMetaTypes2["BROWSER"] = "BROWSER";
2164
+ return ClientMetaTypes2;
2165
+ })(ClientMetaTypes || {});
2166
+
2167
+ // src/ObservedClient.ts
2168
+ var logger2 = createLogger("ObservedClient");
2169
+ var ObservedClient = class extends import_events2.EventEmitter {
2170
+ constructor(settings, call) {
2171
+ super();
2172
+ this.call = call;
2173
+ this.setMaxListeners(Infinity);
2174
+ this.eventScope = { observer: call.observer, observedCall: call, observedClient: this };
2175
+ this.sink = call.observer.config.createClientSink?.({ clientId: settings.clientId, observedCall: call });
2176
+ this.clientId = settings.clientId;
2177
+ this.appData = settings.appData ?? {};
2178
+ this.settings = {
2179
+ closeClientIfIdleForMs: settings.closeClientIfIdleForMs
2180
+ };
2181
+ if (this.sink) {
2182
+ const onError = (err) => logger2.warn("ClientSampleSink error for client %s: %o", this.clientId, err);
2183
+ this.sink.once("close", () => this.sink?.off("error", onError));
2184
+ this.sink.on("error", onError);
2185
+ }
2186
+ }
2187
+ call;
2188
+ clientId;
2189
+ observedPeerConnections = /* @__PURE__ */ new Map();
2190
+ /** Per-client sink (from `ObserverConfig.createClientSink`), if any. */
2191
+ sink;
2192
+ /** Ancestry base shared by all Observer-bus events originating at this client. */
2193
+ eventScope;
2194
+ calculatedScore = {
2195
+ weight: 1,
2196
+ value: void 0
2197
+ };
2198
+ settings;
2199
+ appData;
2200
+ attachments;
2201
+ updated = Date.now();
2202
+ acceptedSamples = 0;
2203
+ closed = false;
2204
+ joinedAt;
2205
+ leftAt;
2206
+ closedAt;
2207
+ lastSampleTimestamp;
2208
+ // the timestamp of the CLIENT_JOINED event
2209
+ operationSystem;
2210
+ engine;
2211
+ platform;
2212
+ browser;
2213
+ mediaConstraints = [];
2214
+ usingTURN = false;
2215
+ usingTCP = false;
2216
+ availableOutgoingBitrate = 0;
2217
+ availableIncomingBitrate = 0;
2218
+ deltaReceivedAudioBytes = 0;
2219
+ deltaReceivedVideoBytes = 0;
2220
+ deltaSentAudioBytes = 0;
2221
+ deltaSentVideoBytes = 0;
2222
+ deltaDataChannelBytesSent = 0;
2223
+ deltaDataChannelBytesReceived = 0;
2224
+ deltaDataChannelMessagesSent = 0;
2225
+ deltaDataChannelMessagesReceived = 0;
2226
+ deltaInboundPacketsLost = 0;
2227
+ deltaInboundPacketsReceived = 0;
2228
+ deltaOutboundPacketsSent = 0;
2229
+ deltaTransportSentBytes = 0;
2230
+ deltaTransportReceivedBytes = 0;
2231
+ deltaRttLt50Measurements = 0;
2232
+ deltaRttLt150Measurements = 0;
2233
+ deltaRttLt300Measurements = 0;
2234
+ deltaRttGtOrEq300Measurements = 0;
2235
+ currentMaxRttInMs;
2236
+ currentMinRttInMs;
2237
+ currentAvgRttInMs;
2238
+ sendingAudioBitrate = 0;
2239
+ sendingVideoBitrate = 0;
2240
+ receivingAudioBitrate = 0;
2241
+ receivingVideoBitrate = 0;
2242
+ numberOfInboundRtpStreams = 0;
2243
+ numberOfInbundTracks = 0;
2244
+ numberOfOutboundRtpStreams = 0;
2245
+ numberOfOutboundTracks = 0;
2246
+ numberOfDataChannels = 0;
2247
+ deltaNumberOfIssues = 0;
2248
+ totalScoreSum = 0;
2249
+ numberOfScoreMeasurements = 0;
2250
+ // public totalNumberOfIssues = 0;
2251
+ mediaDevices = [];
2252
+ issues = [];
2253
+ _pendingInjections = {};
2254
+ _activeSample;
2255
+ closeTimer;
2256
+ get numberOfPeerConnections() {
2257
+ return this.observedPeerConnections.size;
2258
+ }
2259
+ get score() {
2260
+ return this.calculatedScore.value;
2261
+ }
2262
+ close() {
2263
+ if (this.closed) return;
2264
+ this._flushPendingInjections();
2265
+ this.closed = true;
2266
+ Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
2267
+ if (!this.leftAt) {
2268
+ this.leftAt = this.lastSampleTimestamp;
2269
+ if (this.leftAt) {
2270
+ this.emit("left");
2271
+ this._notify("client-left", { ...this.eventScope });
2272
+ }
2273
+ }
2274
+ this.closedAt = Date.now();
2275
+ this.emit("close");
2276
+ this._notify("client-closed", { ...this.eventScope });
2277
+ try {
2278
+ this.sink?.end();
2279
+ } catch (err) {
2280
+ logger2.warn("ClientSampleSink.end failed for client %s: %o", this.clientId, err);
2281
+ }
2282
+ }
2283
+ accept(sample, context) {
2284
+ if (this.closed) {
2285
+ logger2.warn("Attempted to accept a sample on a closed client %s", this.clientId);
2286
+ return;
2287
+ }
2288
+ if (this.closeTimer) {
2289
+ clearTimeout(this.closeTimer);
2290
+ this.closeTimer = void 0;
2291
+ }
2292
+ const now = Date.now();
2293
+ const elapsedInMs = now - this.updated;
2294
+ const elapsedInSeconds = elapsedInMs / 1e3;
2295
+ let sumOfRtts = 0;
2296
+ let numberOfRttMeasurements = 0;
2297
+ ++this.acceptedSamples;
2298
+ this.availableIncomingBitrate = 0;
2299
+ this.availableOutgoingBitrate = 0;
2300
+ this.deltaDataChannelBytesReceived = 0;
2301
+ this.deltaDataChannelBytesSent = 0;
2302
+ this.deltaDataChannelMessagesReceived = 0;
2303
+ this.deltaDataChannelMessagesSent = 0;
2304
+ this.deltaInboundPacketsLost = 0;
2305
+ this.deltaInboundPacketsReceived = 0;
2306
+ this.deltaOutboundPacketsSent = 0;
2307
+ this.deltaReceivedAudioBytes = 0;
2308
+ this.deltaReceivedVideoBytes = 0;
2309
+ this.deltaSentAudioBytes = 0;
2310
+ this.deltaSentVideoBytes = 0;
2311
+ this.deltaTransportReceivedBytes = 0;
2312
+ this.deltaTransportSentBytes = 0;
2313
+ this.deltaRttLt50Measurements = 0;
2314
+ this.deltaRttLt150Measurements = 0;
2315
+ this.deltaRttLt300Measurements = 0;
2316
+ this.deltaRttGtOrEq300Measurements = 0;
2317
+ this.deltaNumberOfIssues = 0;
2318
+ this.numberOfDataChannels = 0;
2319
+ this.numberOfInboundRtpStreams = 0;
2320
+ this.numberOfInbundTracks = 0;
2321
+ this.numberOfOutboundRtpStreams = 0;
2322
+ this.numberOfOutboundTracks = 0;
2323
+ this.usingTURN = false;
2324
+ this.usingTCP = false;
2325
+ this.currentMinRttInMs = void 0;
2326
+ this.currentMaxRttInMs = void 0;
2327
+ this._mergePendingInjections(sample);
2328
+ this._activeSample = sample;
2329
+ const clientEventsPostBuffer = [];
2330
+ for (const clientEvent of sample.clientEvents ?? []) {
2331
+ this._processClientEvent(clientEvent, clientEventsPostBuffer);
2332
+ }
2333
+ for (const metaData of sample.clientMetaItems ?? []) {
2334
+ this.addMetadata(metaData);
2335
+ }
2336
+ for (const issue of sample.clientIssues ?? []) {
2337
+ this.addIssue(issue);
2338
+ ++this.deltaNumberOfIssues;
2339
+ }
2340
+ for (const extensionStat of sample.extensionStats ?? []) {
2341
+ this.addExtensionStats(extensionStat);
2342
+ }
2343
+ for (const pcSample of sample.peerConnections ?? []) {
2344
+ const observedPeerConnection = this._updatePeerConnection(pcSample, context);
2345
+ if (!observedPeerConnection) continue;
2346
+ this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
2347
+ this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
2348
+ this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
2349
+ this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
2350
+ this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
2351
+ this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
2352
+ this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
2353
+ this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
2354
+ this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
2355
+ this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
2356
+ this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
2357
+ this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
2358
+ this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
2359
+ this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
2360
+ this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
2361
+ this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
2362
+ this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
2363
+ this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
2364
+ this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
2365
+ this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
2366
+ if (observedPeerConnection.usingTURN) {
2367
+ this.usingTURN = true;
2368
+ }
2369
+ if (observedPeerConnection.usingTCP) {
2370
+ this.usingTCP = true;
2371
+ }
2372
+ if (observedPeerConnection.currentRttInMs) {
2373
+ if (this.currentMinRttInMs === void 0 || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {
2374
+ this.currentMinRttInMs = observedPeerConnection.currentRttInMs;
2375
+ }
2376
+ if (this.currentMaxRttInMs === void 0 || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {
2377
+ this.currentMaxRttInMs = observedPeerConnection.currentRttInMs;
2378
+ }
2379
+ if (observedPeerConnection.currentRttInMs < 50) {
2380
+ this.deltaRttLt50Measurements += 1;
2381
+ } else if (observedPeerConnection.currentRttInMs < 150) {
2382
+ this.deltaRttLt150Measurements += 1;
2383
+ } else if (observedPeerConnection.currentRttInMs < 300) {
2384
+ this.deltaRttLt300Measurements += 1;
2385
+ } else if (300 <= observedPeerConnection.currentRttInMs) {
2386
+ this.deltaRttGtOrEq300Measurements += 1;
2387
+ }
2388
+ sumOfRtts += observedPeerConnection.currentRttInMs;
2389
+ ++numberOfRttMeasurements;
2390
+ }
2391
+ }
2392
+ for (const clientEvent of clientEventsPostBuffer) {
2393
+ this._processClientEvent(clientEvent);
2394
+ }
2395
+ this.attachments = sample.attachments;
2396
+ this.receivingAudioBitrate = this.deltaReceivedAudioBytes * 8 / elapsedInSeconds;
2397
+ this.receivingVideoBitrate = this.deltaReceivedVideoBytes * 8 / elapsedInSeconds;
2398
+ this.sendingAudioBitrate = this.deltaSentAudioBytes * 8 / elapsedInSeconds;
2399
+ this.sendingVideoBitrate = this.deltaSentVideoBytes * 8 / elapsedInSeconds;
2400
+ this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : void 0;
2401
+ this.calculatedScore.value = sample.score;
2402
+ this.lastSampleTimestamp = sample.timestamp;
2403
+ const elapsedTimeInMs = now - this.updated;
2404
+ this.emit("update", sample, elapsedTimeInMs, context);
2405
+ this._notify("client-updated", { ...this.eventScope, sample, elapsedTimeInMs, context });
2406
+ this.updated = now;
2407
+ if (this.calculatedScore.value) {
2408
+ this.totalScoreSum += this.calculatedScore.value;
2409
+ ++this.numberOfScoreMeasurements;
2410
+ }
2411
+ if (this.settings.closeClientIfIdleForMs !== void 0) {
2412
+ this.closeTimer = setTimeout(() => {
2413
+ this.close();
2414
+ }, this.settings.closeClientIfIdleForMs);
2415
+ }
2416
+ this._activeSample = void 0;
2417
+ try {
2418
+ this.sink?.write(sample);
2419
+ } catch (err) {
2420
+ logger2.warn("ClientSampleSink.write failed for client %s: %o", this.clientId, err);
2421
+ }
2422
+ }
2423
+ injectMetaData(metaData) {
2424
+ if (this.closed) return;
2425
+ if (this._activeSample) {
2426
+ if (!this._activeSample.clientMetaItems) this._activeSample.clientMetaItems = [];
2427
+ this._activeSample.clientMetaItems.push(metaData);
2428
+ this.addMetadata(metaData);
2429
+ return;
2430
+ }
2431
+ if (!this._pendingInjections.clientMetaItems) this._pendingInjections.clientMetaItems = [];
2432
+ this._pendingInjections.clientMetaItems.push(metaData);
2433
+ }
2434
+ injectEvent(event) {
2435
+ if (this.closed) return;
2436
+ if (this._activeSample) {
2437
+ if (!this._activeSample.clientEvents) this._activeSample.clientEvents = [];
2438
+ this._activeSample.clientEvents.push(event);
2439
+ this._processClientEvent(event);
2440
+ return;
2441
+ }
2442
+ if (!this._pendingInjections.clientEvents) this._pendingInjections.clientEvents = [];
2443
+ this._pendingInjections.clientEvents.push(event);
2444
+ }
2445
+ injectIssue(issue) {
2446
+ if (this.closed) return;
2447
+ if (this._activeSample) {
2448
+ if (!this._activeSample.clientIssues) this._activeSample.clientIssues = [];
2449
+ this._activeSample.clientIssues.push(issue);
2450
+ this.addIssue(issue);
2451
+ ++this.deltaNumberOfIssues;
2452
+ return;
2453
+ }
2454
+ if (!this._pendingInjections.clientIssues) this._pendingInjections.clientIssues = [];
2455
+ this._pendingInjections.clientIssues.push(issue);
2456
+ }
2457
+ injectExtensionStat(stat) {
2458
+ if (this.closed) return;
2459
+ if (this._activeSample) {
2460
+ if (!this._activeSample.extensionStats) this._activeSample.extensionStats = [];
2461
+ this._activeSample.extensionStats.push(stat);
2462
+ this.addExtensionStats(stat);
2463
+ return;
2464
+ }
2465
+ if (!this._pendingInjections.extensionStats) this._pendingInjections.extensionStats = [];
2466
+ this._pendingInjections.extensionStats.push(stat);
2467
+ }
2468
+ injectAttachment(attachments) {
2469
+ if (this.closed) return;
2470
+ if (this._activeSample) {
2471
+ if (!this._activeSample.attachments) this._activeSample.attachments = {};
2472
+ Object.assign(this._activeSample.attachments, attachments);
2473
+ this.attachments = this._activeSample.attachments;
2474
+ return;
2475
+ }
2476
+ if (!this._pendingInjections.attachments) this._pendingInjections.attachments = {};
2477
+ Object.assign(this._pendingInjections.attachments, attachments);
2478
+ }
2479
+ addMetadata(metadata) {
2480
+ if (this.closed) return;
2481
+ switch (metadata.type) {
2482
+ case "BROWSER" /* BROWSER */: {
2483
+ this.browser = parseJsonAs(metadata.payload);
2484
+ break;
2485
+ }
2486
+ case "ENGINE" /* ENGINE */: {
2487
+ this.engine = parseJsonAs(metadata.payload);
2488
+ break;
2489
+ }
2490
+ case "PLATFORM" /* PLATFORM */: {
2491
+ this.platform = parseJsonAs(metadata.payload);
2492
+ break;
2493
+ }
2494
+ case "OPERATION_SYSTEM" /* OPERATION_SYSTEM */: {
2495
+ this.operationSystem = parseJsonAs(metadata.payload);
2496
+ break;
2497
+ }
2498
+ }
2499
+ this._notify("client-metadata", { ...this.eventScope, metaData: metadata });
2500
+ }
2501
+ addIssue(issue) {
2502
+ if (this.closed) return;
2503
+ this._notify("client-issue", { ...this.eventScope, issue });
2504
+ }
2505
+ addExtensionStats(stats) {
2506
+ this._notify("client-extension-stats", { ...this.eventScope, extensionStats: stats });
2507
+ }
2508
+ _processClientEvent(event, postBuffer) {
2509
+ switch (event.type) {
2510
+ case "CLIENT_JOINED" /* CLIENT_JOINED */: {
2511
+ if (event.timestamp) {
2512
+ if (!this.joinedAt) {
2513
+ this.joinedAt = event.timestamp;
2514
+ this.emit("joined");
2515
+ this._notify("client-joined", { ...this.eventScope });
2516
+ } else if (this.joinedAt < event.timestamp) {
2517
+ this._notify("client-rejoined", { ...this.eventScope, timestamp: event.timestamp });
2518
+ } else {
2519
+ this.joinedAt = event.timestamp;
2520
+ logger2.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);
2521
+ }
2522
+ }
2523
+ logger2.debug("Client %s joined at %o", this.clientId, event);
2524
+ break;
2525
+ }
2526
+ case "CLIENT_LEFT" /* CLIENT_LEFT */: {
2527
+ if (event.timestamp) {
2528
+ if (!this.leftAt) {
2529
+ this.leftAt = event.timestamp;
2530
+ this.emit("left");
2531
+ this._notify("client-left", { ...this.eventScope });
2532
+ } else {
2533
+ logger2.warn(`Client ${this.clientId} leftAt timestamp was already set`);
2534
+ }
2535
+ }
2536
+ logger2.debug("Client %s left at %o", this.clientId, event);
2537
+ break;
2538
+ }
2539
+ case "PEER_CONNECTION_OPENED" /* PEER_CONNECTION_OPENED */: {
2540
+ const payload = parseJsonAs(event.payload);
2541
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string") {
2542
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2543
+ if (observedPeerConnection) {
2544
+ observedPeerConnection.openedAt = event.timestamp;
2545
+ } else if (postBuffer) {
2546
+ postBuffer.push(event);
2547
+ } else {
2548
+ logger2.warn("Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection: %o", event);
2549
+ }
2550
+ }
2551
+ break;
2552
+ }
2553
+ case "PEER_CONNECTION_CLOSED" /* PEER_CONNECTION_CLOSED */: {
2554
+ const payload = parseJsonAs(event.payload);
2555
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string") {
2556
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2557
+ if (observedPeerConnection) {
2558
+ observedPeerConnection.closedAt = event.timestamp;
2559
+ } else if (postBuffer) {
2560
+ postBuffer.push(event);
2561
+ } else {
2562
+ logger2.warn("Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection: %o", event);
2563
+ }
2564
+ }
2565
+ break;
2566
+ }
2567
+ case "MEDIA_TRACK_ADDED" /* MEDIA_TRACK_ADDED */: {
2568
+ const payload = parseJsonAs(event.payload);
2569
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2570
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2571
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2572
+ if (observedTrack) {
2573
+ observedTrack.addedAt = event.timestamp;
2574
+ } else if (postBuffer) {
2575
+ postBuffer.push(event);
2576
+ } else {
2577
+ logger2.warn("Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack: %o", event);
2578
+ }
2579
+ }
2580
+ break;
2581
+ }
2582
+ case "MEDIA_TRACK_REMOVED" /* MEDIA_TRACK_REMOVED */: {
2583
+ const payload = parseJsonAs(event.payload);
2584
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2585
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2586
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2587
+ if (observedTrack) {
2588
+ observedTrack.removedAt = event.timestamp;
2589
+ } else if (postBuffer) {
2590
+ postBuffer.push(event);
2591
+ } else {
2592
+ logger2.warn("Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack: %o", event);
2593
+ }
2594
+ }
2595
+ break;
2596
+ }
2597
+ case "DATA_CHANNEL_OPEN" /* DATA_CHANNEL_OPEN */: {
2598
+ const payload = parseJsonAs(event.payload);
2599
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.dataChannelId && typeof payload.dataChannelId === "string") {
2600
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2601
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
2602
+ if (observedDataChannel) {
2603
+ observedDataChannel.addedAt = event.timestamp;
2604
+ } else if (postBuffer) {
2605
+ postBuffer.push(event);
2606
+ } else {
2607
+ logger2.warn("Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel: %o", event);
2608
+ }
2609
+ }
2610
+ break;
2611
+ }
2612
+ case "DATA_CHANNEL_CLOSED" /* DATA_CHANNEL_CLOSED */: {
2613
+ const payload = parseJsonAs(event.payload);
2614
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.dataChannelId && typeof payload.dataChannelId === "string") {
2615
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2616
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
2617
+ if (observedDataChannel) {
2618
+ observedDataChannel.removedAt = event.timestamp;
2619
+ } else if (postBuffer) {
2620
+ postBuffer.push(event);
2621
+ } else {
2622
+ logger2.warn("Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel: %o", event);
2623
+ }
2624
+ }
2625
+ break;
2626
+ }
2627
+ case "MEDIA_TRACK_MUTED" /* MEDIA_TRACK_MUTED */: {
2628
+ const payload = parseJsonAs(event.payload);
2629
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2630
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2631
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
2632
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2633
+ if (observedPeerConnection) {
2634
+ if (observedInboundTrack) {
2635
+ observedInboundTrack.muted = true;
2636
+ this._notify("inbound-track-muted", { ...this.eventScope, observedPeerConnection, observedInboundTrack });
2637
+ } else if (observedOutboundTrack) {
2638
+ observedOutboundTrack.muted = true;
2639
+ this._notify("outbound-track-muted", { ...this.eventScope, observedPeerConnection, observedOutboundTrack });
2640
+ }
2641
+ } else if (postBuffer) {
2642
+ postBuffer.push(event);
2643
+ } else {
2644
+ logger2.warn("Received MEDIA_TRACK_MUTED event without a corresponding observedPeerConnection or observedTrack: %o", event);
2645
+ }
2646
+ }
2647
+ break;
2648
+ }
2649
+ case "MEDIA_TRACK_UNMUTED" /* MEDIA_TRACK_UNMUTED */: {
2650
+ const payload = parseJsonAs(event.payload);
2651
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2652
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2653
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
2654
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2655
+ if (observedPeerConnection) {
2656
+ if (observedInboundTrack) {
2657
+ observedInboundTrack.muted = false;
2658
+ this._notify("inbound-track-unmuted", { ...this.eventScope, observedPeerConnection, observedInboundTrack });
2659
+ } else if (observedOutboundTrack) {
2660
+ observedOutboundTrack.muted = false;
2661
+ this._notify("outbound-track-unmuted", { ...this.eventScope, observedPeerConnection, observedOutboundTrack });
2662
+ }
2663
+ } else if (postBuffer) {
2664
+ postBuffer.push(event);
2665
+ } else {
2666
+ logger2.warn("Received MEDIA_TRACK_UNMUTED event without a corresponding observedPeerConnection or observedTrack: %o", event);
2667
+ }
2668
+ }
2669
+ break;
2670
+ }
2671
+ case "ICE_CONNECTION_STATE_CHANGED" /* ICE_CONNECTION_STATE_CHANGED */: {
2672
+ const payload = parseJsonAs(event.payload);
2673
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.iceConnectionState && typeof payload.iceConnectionState === "string") {
2674
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2675
+ if (observedPeerConnection) {
2676
+ observedPeerConnection.iceConnectionState = payload.iceConnectionState;
2677
+ this._notify("ice-connection-state-changed", { ...this.eventScope, observedPeerConnection, state: payload.iceConnectionState });
2678
+ } else if (postBuffer) {
2679
+ postBuffer.push(event);
2680
+ } else {
2681
+ logger2.warn("Received ICE_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o", event);
2682
+ }
2683
+ }
2684
+ break;
2685
+ }
2686
+ case "ICE_GATHERING_STATE_CHANGED" /* ICE_GATHERING_STATE_CHANGED */: {
2687
+ const payload = parseJsonAs(event.payload);
2688
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.iceGatheringState && typeof payload.iceGatheringState === "string") {
2689
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2690
+ if (observedPeerConnection) {
2691
+ observedPeerConnection.iceGatheringState = payload.iceGatheringState;
2692
+ this._notify("ice-gathering-state-changed", { ...this.eventScope, observedPeerConnection, state: payload.iceGatheringState });
2693
+ } else if (postBuffer) {
2694
+ postBuffer.push(event);
2695
+ } else {
2696
+ logger2.warn("Received ICE_GATHERING_STATE_CHANGED event without a corresponding observedPeerConnection: %o", event);
2697
+ }
2698
+ }
2699
+ break;
2700
+ }
2701
+ case "PEER_CONNECTION_STATE_CHANGED" /* PEER_CONNECTION_STATE_CHANGED */: {
2702
+ const payload = parseJsonAs(event.payload);
2703
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.peerConnectionState && typeof payload.peerConnectionState === "string") {
2704
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2705
+ if (observedPeerConnection) {
2706
+ observedPeerConnection.connectionState = payload.peerConnectionState;
2707
+ this._notify("connection-state-changed", { ...this.eventScope, observedPeerConnection, state: payload.peerConnectionState });
2708
+ } else if (postBuffer) {
2709
+ postBuffer.push(event);
2710
+ } else {
2711
+ logger2.warn("Received PEER_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o", event);
2712
+ }
2713
+ }
2714
+ break;
2715
+ }
2716
+ }
2717
+ this._notify("client-event", { ...this.eventScope, event });
2718
+ }
2719
+ _updatePeerConnection(sample, context) {
2720
+ let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
2721
+ if (!observedPeerConnection) {
2722
+ if (!sample.peerConnectionId) {
2723
+ return logger2.warn(
2724
+ `ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
2725
+ sample
2726
+ ), void 0;
2727
+ }
2728
+ const newObservedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
2729
+ newObservedPeerConnection.once("close", () => {
2730
+ this.observedPeerConnections.delete(sample.peerConnectionId);
2731
+ });
2732
+ this.observedPeerConnections.set(sample.peerConnectionId, newObservedPeerConnection);
2733
+ this._notify("peer-connection-added", { ...this.eventScope, observedPeerConnection: newObservedPeerConnection });
2734
+ observedPeerConnection = newObservedPeerConnection;
2735
+ }
2736
+ observedPeerConnection.accept(sample, context);
2737
+ return observedPeerConnection;
2738
+ }
2739
+ _mergePendingInjections(sample) {
2740
+ if (this.closed) return sample;
2741
+ if (this._pendingInjections.clientEvents) {
2742
+ if (!sample.clientEvents) sample.clientEvents = [];
2743
+ sample.clientEvents.push(...this._pendingInjections.clientEvents);
2744
+ this._pendingInjections.clientEvents = void 0;
2745
+ }
2746
+ if (this._pendingInjections.clientIssues) {
2747
+ if (!sample.clientIssues) sample.clientIssues = [];
2748
+ sample.clientIssues.push(...this._pendingInjections.clientIssues);
2749
+ this._pendingInjections.clientIssues = void 0;
2750
+ }
2751
+ if (this._pendingInjections.extensionStats) {
2752
+ if (!sample.extensionStats) sample.extensionStats = [];
2753
+ sample.extensionStats.push(...this._pendingInjections.extensionStats);
2754
+ this._pendingInjections.extensionStats = void 0;
2755
+ }
2756
+ if (this._pendingInjections.attachments) {
2757
+ if (!sample.attachments) sample.attachments = {};
2758
+ Object.assign(sample.attachments, this._pendingInjections.attachments);
2759
+ this._pendingInjections.attachments = void 0;
2760
+ }
2761
+ if (this._pendingInjections.clientMetaItems) {
2762
+ if (!sample.clientMetaItems) sample.clientMetaItems = [];
2763
+ sample.clientMetaItems.push(...this._pendingInjections.clientMetaItems);
2764
+ this._pendingInjections.clientMetaItems = void 0;
2765
+ }
2766
+ return sample;
2767
+ }
2768
+ _flushPendingInjections() {
2769
+ const hasPending = Boolean(
2770
+ this._pendingInjections.clientEvents || this._pendingInjections.clientIssues || this._pendingInjections.extensionStats || this._pendingInjections.clientMetaItems || this._pendingInjections.attachments
2771
+ );
2772
+ if (!hasPending) return;
2773
+ const finalSample = { timestamp: Date.now() };
2774
+ this._mergePendingInjections(finalSample);
2775
+ for (const clientEvent of finalSample.clientEvents ?? []) this._processClientEvent(clientEvent);
2776
+ for (const metaData of finalSample.clientMetaItems ?? []) this.addMetadata(metaData);
2777
+ for (const issue of finalSample.clientIssues ?? []) this.addIssue(issue);
2778
+ for (const extensionStat of finalSample.extensionStats ?? []) this.addExtensionStats(extensionStat);
2779
+ if (finalSample.attachments) this.attachments = { ...this.attachments, ...finalSample.attachments };
2780
+ try {
2781
+ this.sink?.write(finalSample);
2782
+ } catch (err) {
2783
+ logger2.warn("ClientSampleSink.write failed during injection flush for client %s: %o", this.clientId, err);
2784
+ }
2785
+ }
2786
+ /** Emit an Observer-bus event scoped to this client (or a peer connection under it). */
2787
+ _notify(type, ...args) {
2788
+ this.call.observer.emit(type, ...args);
2789
+ }
2790
+ };
2791
+
2792
+ // src/scores/DefaultCallScoreCalculator.ts
2793
+ var DefaultCallScoreCalculator = class {
2794
+ constructor(observedCall) {
2795
+ this.observedCall = observedCall;
2796
+ }
2797
+ observedCall;
2798
+ update() {
2799
+ let totalScore = 0;
2800
+ let totalWeight = 0;
2801
+ for (const client of this.observedCall.observedClients.values()) {
2802
+ if (client.score === void 0) continue;
2803
+ totalScore += client.score * client.calculatedScore.weight;
2804
+ totalWeight += client.calculatedScore.weight;
2805
+ }
2806
+ this.observedCall.calculatedScore.value = totalWeight ? totalScore / totalWeight : void 0;
2807
+ }
2808
+ };
2809
+
2810
+ // src/updaters/OnAllClientCallUpdater.ts
2811
+ var OnAllClientCallUpdater = class {
2812
+ constructor(_observedCall) {
2813
+ this._observedCall = _observedCall;
2814
+ this._onNewObservedClient = this._onNewObservedClient.bind(this);
2815
+ this._observedCall.once("close", () => {
2816
+ this._observedCall.off("newclient", this._onNewObservedClient);
2817
+ });
2818
+ this._observedCall.on("newclient", this._onNewObservedClient);
2819
+ }
2820
+ _observedCall;
2821
+ name = "OnAllClientCallUpdater";
2822
+ description = "Call the update() method of the ObservedCall once all client has been updated";
2823
+ _updatedClients = /* @__PURE__ */ new Set();
2824
+ closed = false;
2825
+ close() {
2826
+ if (this.closed) return;
2827
+ this.closed = true;
2828
+ this._updatedClients.clear();
2829
+ }
2830
+ _onNewObservedClient(observedClient) {
2831
+ if (this.closed) return;
2832
+ const onUpdate = (...args) => this._onClientUpdate(observedClient, args[2]);
2833
+ observedClient.once("close", () => {
2834
+ observedClient.off("update", onUpdate);
2835
+ this._updatedClients.delete(observedClient.clientId);
2836
+ this._updateIfEveryClientUpdated();
2837
+ });
2838
+ observedClient.on("update", onUpdate);
2839
+ }
2840
+ _onClientUpdate(observedClient, context) {
2841
+ if (observedClient.closed) return;
2842
+ this._updatedClients.add(observedClient.clientId);
2843
+ this._updateIfEveryClientUpdated(context);
2844
+ }
2845
+ _updateIfEveryClientUpdated(context) {
2846
+ if (this._updatedClients.size < this._observedCall.observedClients.size) {
2847
+ return;
2848
+ } else if (this.closed) {
2849
+ return;
2850
+ }
2851
+ this._updatedClients.clear();
2852
+ this._observedCall.update(context);
2853
+ }
2854
+ };
2855
+
2856
+ // src/updaters/OnAnyClientCallUpdater.ts
2857
+ var OnAnyClientCallUpdater = class {
2858
+ constructor(_observedCall) {
2859
+ this._observedCall = _observedCall;
2860
+ this._onNewObservedClient = this._onNewObservedClient.bind(this);
2861
+ this._observedCall.once("close", () => {
2862
+ this._observedCall.off("newclient", this._onNewObservedClient);
2863
+ });
2864
+ this._observedCall.on("newclient", this._onNewObservedClient);
2865
+ }
2866
+ _observedCall;
2867
+ name = "OnAnyClientCallUpdater";
2868
+ description = "Call the update() method of the ObservedCall when any of the client has been updated";
2869
+ closed = false;
2870
+ close() {
2871
+ if (this.closed) return;
2872
+ this.closed = true;
2873
+ }
2874
+ _onNewObservedClient(observedClient) {
2875
+ if (this.closed) return;
2876
+ const onUpdate = (...args) => {
2877
+ if (this.closed) return;
2878
+ this._observedCall.update(args[2]);
2879
+ };
2880
+ observedClient.once("close", () => {
2881
+ observedClient.off("update", onUpdate);
2882
+ });
2883
+ observedClient.on("update", onUpdate);
2884
+ }
2885
+ };
2886
+
2887
+ // src/detectors/Detectors.ts
2888
+ var logger3 = createLogger("Detectors");
2889
+ var Detectors = class {
2890
+ _detectors;
2891
+ constructor(...detectors) {
2892
+ this._detectors = detectors;
2893
+ }
2894
+ get listOfNames() {
2895
+ return this._detectors.map((d) => d.name);
2896
+ }
2897
+ add(detector) {
2898
+ this._detectors.push(detector);
2899
+ }
2900
+ remove(detector) {
2901
+ this._detectors = this._detectors.filter((d) => d !== detector);
2902
+ }
2903
+ update() {
2904
+ for (const detector of this._detectors) {
2905
+ try {
2906
+ detector.update();
2907
+ } catch (err) {
2908
+ logger3.warn(`Error updating detector ${detector?.name}`, err);
2909
+ }
2910
+ }
2911
+ }
2912
+ clear() {
2913
+ this._detectors = [];
2914
+ }
2915
+ };
2916
+
2917
+ // src/ObservedCall.ts
2918
+ var logger4 = createLogger("ObservedCall");
2919
+ var ObservedCall = class extends import_events3.EventEmitter {
2920
+ constructor(settings, observer) {
2921
+ super();
2922
+ this.observer = observer;
2923
+ this.setMaxListeners(Infinity);
2924
+ this.eventScope = { observer: this.observer, observedCall: this };
2925
+ this.callId = settings.callId;
2926
+ this.appData = settings.appData ?? {};
2927
+ this.scoreCalculator = new DefaultCallScoreCalculator(this);
2928
+ this.detectors = new Detectors();
2929
+ switch (settings.updatePolicy) {
2930
+ case "update-on-any-client-updated":
2931
+ this.updater = new OnAnyClientCallUpdater(this);
2932
+ break;
2933
+ case "update-when-all-client-updated":
2934
+ this.updater = new OnAllClientCallUpdater(this);
2935
+ break;
2936
+ case "none":
2937
+ break;
2938
+ }
2939
+ this.settings = {
2940
+ closeCallIfEmptyForMs: settings.closeCallIfEmptyForMs
2941
+ };
2942
+ }
2943
+ observer;
2944
+ updater;
2945
+ scoreCalculator;
2946
+ detectors;
2947
+ callId;
2948
+ observedClients = /* @__PURE__ */ new Map();
2949
+ clientsUsedTurn = /* @__PURE__ */ new Set();
2950
+ calculatedScore = {
2951
+ weight: 1,
2952
+ value: void 0
2953
+ };
2954
+ remoteTrackResolver;
2955
+ totalAddedClients = 0;
2956
+ totalRemovedClients = 0;
2957
+ numberOfIssues = 0;
2958
+ numberOfPeerConnections = 0;
2959
+ numberOfInboundRtpStreams = 0;
2960
+ numberOfOutboundRtpStreams = 0;
2961
+ numberOfDataChannels = 0;
2962
+ maxNumberOfClients = 0;
2963
+ deltaNumberOfIssues = 0;
2964
+ // public deltaRttLt50Measurements = 0;
2965
+ // public deltaRttLt150Measurements = 0;
2966
+ // public deltaRttLt300Measurements = 0;
2967
+ // public deltaRttGtOrEq300Measurements = 0;
2968
+ appData;
2969
+ closed = false;
2970
+ startedAt;
2971
+ endedAt;
2972
+ closedAt;
2973
+ settings;
2974
+ /** Ancestry base shared by all Observer-bus events originating at this call. */
2975
+ eventScope;
2976
+ closeTimer;
2977
+ get numberOfClients() {
2978
+ return this.observedClients.size;
2979
+ }
2980
+ get score() {
2981
+ return this.calculatedScore.value;
2982
+ }
2983
+ /** Raise a call-level (server-side) issue; surfaced on the Observer bus as `call-issue`. */
2984
+ addIssue(issue) {
2985
+ if (this.closed) return;
2986
+ this._notify("call-issue", { ...this.eventScope, issue });
2987
+ }
2988
+ close() {
2989
+ if (this.closed) return;
2990
+ this.update();
2991
+ this.closed = true;
2992
+ this.updater?.close();
2993
+ let minSampleTimestamps;
2994
+ let maxSampleTimestamps;
2995
+ for (const client of this.observedClients.values()) {
2996
+ client.close();
2997
+ if (client.joinedAt) minSampleTimestamps = Math.min(minSampleTimestamps ?? client.joinedAt, client.joinedAt);
2998
+ if (client.leftAt) maxSampleTimestamps = Math.max(maxSampleTimestamps ?? client.leftAt, client.leftAt);
2999
+ }
3000
+ if (this.startedAt === void 0) this.startedAt = minSampleTimestamps;
3001
+ if (this.endedAt === void 0) this.endedAt = maxSampleTimestamps;
3002
+ this.closedAt = Date.now();
3003
+ this.emit("close");
3004
+ this._notify("call-closed", { ...this.eventScope });
3005
+ }
3006
+ getObservedClient(clientId) {
3007
+ if (this.closed || !this.observedClients.has(clientId)) return;
3008
+ return this.observedClients.get(clientId);
3009
+ }
3010
+ createObservedClient(settings) {
3011
+ if (this.closed) {
3012
+ logger4.warn("Attempted to create a client (clientId: %s) on a closed call %s", settings.clientId, this.callId);
3013
+ return void 0;
3014
+ }
3015
+ if (this.observedClients.has(settings.clientId)) {
3016
+ logger4.warn("Client with id %s already exists in call %s; returning the existing instance", settings.clientId, this.callId);
3017
+ return this.observedClients.get(settings.clientId);
3018
+ }
3019
+ if (!settings.closeClientIfIdleForMs) {
3020
+ settings.closeClientIfIdleForMs = this.observer.config.closeClientIfIdleForMs;
3021
+ }
3022
+ if (settings.appData === void 0) {
3023
+ settings.appData = this.observer.config.createClientAppData?.({ clientId: settings.clientId, observedCall: this });
3024
+ }
3025
+ const result = new ObservedClient(settings, this);
3026
+ const wasEmpty = this.observedClients.size === 0;
3027
+ const onUpdate = () => this._onClientUpdate(result);
3028
+ const joined = () => this._clientJoined(result);
3029
+ const left = () => this._clientLeft(result);
3030
+ result.once("close", () => {
3031
+ result.off("update", onUpdate);
3032
+ result.off("joined", joined);
3033
+ result.off("left", left);
3034
+ this.observedClients.delete(settings.clientId);
3035
+ if (this.observedClients.size === 0) {
3036
+ this.emit("empty");
3037
+ this._notify("call-empty", { ...this.eventScope });
3038
+ if (this.settings.closeCallIfEmptyForMs) {
3039
+ this.closeTimer = setTimeout(() => {
3040
+ this.close();
3041
+ }, this.settings.closeCallIfEmptyForMs);
3042
+ }
3043
+ }
3044
+ ++this.totalRemovedClients;
3045
+ });
3046
+ result.on("update", onUpdate);
3047
+ result.on("joined", joined);
3048
+ result.on("left", left);
3049
+ ++this.totalAddedClients;
3050
+ this.observedClients.set(settings.clientId, result);
3051
+ this.maxNumberOfClients = Math.max(this.maxNumberOfClients, this.observedClients.size);
3052
+ if (this.closeTimer) {
3053
+ clearTimeout(this.closeTimer);
3054
+ this.closeTimer = void 0;
3055
+ }
3056
+ this.emit("newclient", result);
3057
+ this._notify("client-added", { ...this.eventScope, observedClient: result });
3058
+ if (result.sink) {
3059
+ this._notify("client-sink-created", { ...this.eventScope, observedClient: result, sink: result.sink });
3060
+ }
3061
+ if (wasEmpty) {
3062
+ this.emit("not-empty");
3063
+ this._notify("call-not-empty", { ...this.eventScope });
3064
+ }
3065
+ return result;
3066
+ }
3067
+ getOrCreateObservedClient(settings) {
3068
+ return this.getObservedClient(settings.clientId) ?? this.createObservedClient(settings);
3069
+ }
3070
+ update(context) {
3071
+ if (this.closed) return;
3072
+ this.numberOfInboundRtpStreams = 0;
3073
+ this.numberOfOutboundRtpStreams = 0;
3074
+ this.numberOfPeerConnections = 0;
3075
+ this.numberOfDataChannels = 0;
3076
+ for (const client of this.observedClients.values()) {
3077
+ this.numberOfInboundRtpStreams += client.numberOfInboundRtpStreams;
3078
+ this.numberOfOutboundRtpStreams += client.numberOfOutboundRtpStreams;
3079
+ this.numberOfPeerConnections += client.numberOfPeerConnections;
3080
+ this.numberOfDataChannels += client.numberOfDataChannels;
3081
+ }
3082
+ this.scoreCalculator.update();
3083
+ this.detectors.update();
3084
+ this.emit("update");
3085
+ this._notify("call-updated", { ...this.eventScope, context });
3086
+ this.deltaNumberOfIssues = 0;
3087
+ }
3088
+ _onClientUpdate(client) {
3089
+ this.deltaNumberOfIssues += client.deltaNumberOfIssues;
3090
+ this.numberOfIssues += client.deltaNumberOfIssues;
3091
+ if (client.usingTURN) {
3092
+ this.clientsUsedTurn.add(client.clientId);
3093
+ }
3094
+ }
3095
+ _clientJoined(client) {
3096
+ if (!client.joinedAt) return;
3097
+ this.startedAt = Math.min(this.startedAt ?? client.joinedAt, client.joinedAt);
3098
+ }
3099
+ _clientLeft(client) {
3100
+ if (!client.leftAt) return;
3101
+ this.endedAt = Math.max(this.endedAt ?? client.leftAt, client.leftAt);
3102
+ }
3103
+ /** Emit an Observer-bus event scoped to this call. */
3104
+ _notify(type, ...args) {
3105
+ this.observer.emit(type, ...args);
3106
+ }
3107
+ };
3108
+
3109
+ // src/Observer.ts
3110
+ var import_events6 = require("events");
3111
+
3112
+ // src/ObservedTURN.ts
3113
+ var import_events4 = require("events");
3114
+
3115
+ // src/ObservedTurnServer.ts
3116
+ var ObservedTurnServer = class {
3117
+ constructor(url, observedTURN) {
3118
+ this.url = url;
3119
+ this.observedTURN = observedTURN;
3120
+ }
3121
+ url;
3122
+ observedTURN;
3123
+ totalBytesSent = 0;
3124
+ totalBytesReceived = 0;
3125
+ totalPacketsSent = 0;
3126
+ totalPacketsReceived = 0;
3127
+ packetsSentPerSecond = 0;
3128
+ packetsReceivedPerSecond = 0;
3129
+ outboundBitrate = 0;
3130
+ inboundBitrate = 0;
3131
+ deltaBytesSent = 0;
3132
+ deltaBytesReceived = 0;
3133
+ deltaPacketsSent = 0;
3134
+ deltaPacketsReceived = 0;
3135
+ observedPeerConnections = /* @__PURE__ */ new Map();
3136
+ updated = Date.now();
3137
+ updateTurnUsage(...selectedcandidatepairs) {
3138
+ for (const selectedcandidatepair of selectedcandidatepairs) {
3139
+ this.deltaBytesReceived += selectedcandidatepair.deltaBytesReceived;
3140
+ this.deltaBytesSent += selectedcandidatepair.deltaBytesSent;
3141
+ this.deltaPacketsReceived += selectedcandidatepair.deltaPacketsReceived;
3142
+ this.deltaPacketsSent += selectedcandidatepair.deltaPacketsSent;
3143
+ }
3144
+ }
3145
+ update() {
3146
+ const now = Date.now();
3147
+ const deltaInS = (now - this.updated) / 1e3;
3148
+ this.packetsSentPerSecond = this.deltaPacketsSent / deltaInS;
3149
+ this.packetsReceivedPerSecond = this.deltaPacketsReceived / deltaInS;
3150
+ this.outboundBitrate = this.deltaBytesReceived * 8 / deltaInS;
3151
+ this.inboundBitrate = this.deltaBytesSent * 8 / deltaInS;
3152
+ this.totalBytesSent += this.deltaBytesSent;
3153
+ this.totalBytesReceived += this.deltaBytesReceived;
3154
+ this.totalPacketsSent += this.deltaPacketsSent;
3155
+ this.totalPacketsReceived += this.deltaPacketsReceived;
3156
+ this.observedTURN.totalBytesSent += this.deltaBytesSent;
3157
+ this.observedTURN.totalBytesReceived += this.deltaBytesReceived;
3158
+ this.observedTURN.totalPacketsSent += this.deltaPacketsSent;
3159
+ this.observedTURN.totalPacketsReceived += this.deltaPacketsReceived;
3160
+ this.observedTURN.inboundBitrate += this.inboundBitrate;
3161
+ this.observedTURN.outboundBitrate += this.outboundBitrate;
3162
+ this.observedTURN.packetsReceivedPerSecond += this.packetsReceivedPerSecond;
3163
+ this.observedTURN.packetsSentPerSecond += this.packetsSentPerSecond;
3164
+ this.deltaBytesSent = 0;
3165
+ this.deltaBytesReceived = 0;
3166
+ this.deltaPacketsSent = 0;
3167
+ this.deltaPacketsReceived = 0;
3168
+ this.updated = now;
3169
+ }
3170
+ };
3171
+
3172
+ // src/ObservedTURN.ts
3173
+ var logger5 = createLogger("ObservedTURN");
3174
+ var ObservedTURN = class extends import_events4.EventEmitter {
3175
+ totalBytesSent = 0;
3176
+ totalBytesReceived = 0;
3177
+ totalPacketsSent = 0;
3178
+ totalPacketsReceived = 0;
3179
+ packetsSentPerSecond = 0;
3180
+ packetsReceivedPerSecond = 0;
3181
+ outboundBitrate = 0;
3182
+ inboundBitrate = 0;
3183
+ numberOfClients = 0;
3184
+ servers = /* @__PURE__ */ new Map();
3185
+ constructor() {
3186
+ super();
3187
+ }
3188
+ update() {
3189
+ const clientIds = /* @__PURE__ */ new Set();
3190
+ this.packetsReceivedPerSecond = 0;
3191
+ this.packetsSentPerSecond = 0;
3192
+ this.outboundBitrate = 0;
3193
+ this.inboundBitrate = 0;
3194
+ for (const server of this.servers.values()) {
3195
+ server.update();
3196
+ server.observedPeerConnections.forEach((pc) => clientIds.add(pc.client.clientId));
3197
+ }
3198
+ this.numberOfClients = clientIds.size;
3199
+ }
3200
+ addPeerConnection(peerConnection) {
3201
+ const turnPairs = peerConnection.selectedIceCandidatePairs.filter((pair) => pair.getLocalCandidate()?.candidateType === "relay" && pair.getRemoteCandidate()?.url?.startsWith("turn:"));
3202
+ if (turnPairs.length !== 1) {
3203
+ return logger5.warn(`Expected exactly one TURN pair, but found for peerconnection ${peerConnection.peerConnectionId}`, turnPairs.length), void 0;
3204
+ }
3205
+ const candidatePair = turnPairs[0];
3206
+ const rawUrl = candidatePair.getRemoteCandidate()?.url;
3207
+ if (!rawUrl) {
3208
+ return logger5.warn(`No remote candidate URL found for peerconnection ${peerConnection.peerConnectionId}`), void 0;
3209
+ }
3210
+ const turnUrl = new URL(rawUrl);
3211
+ const turnServerUrl = `${turnUrl.protocol}//${turnUrl.hostname}:${turnUrl.port}`;
3212
+ let turnServer = this.servers.get(turnServerUrl);
3213
+ if (!turnServer) {
3214
+ turnServer = new ObservedTurnServer(turnServerUrl, this);
3215
+ }
3216
+ return turnServer;
3217
+ }
3218
+ removePeerConnection(peerConnection) {
3219
+ for (const turnServer of this.servers.values()) {
3220
+ turnServer.observedPeerConnections.delete(peerConnection.peerConnectionId);
3221
+ }
3222
+ }
3223
+ };
3224
+
3225
+ // src/updaters/OnAllCallObserverUpdater.ts
3226
+ var OnAllCallObserverUpdater = class {
3227
+ constructor(observer) {
3228
+ this.observer = observer;
3229
+ this._onNewObservedCall = this._onNewObservedCall.bind(this);
3230
+ this.observer.once("observer-closed", () => {
3231
+ this.observer.off("call-added", this._onNewObservedCall);
3232
+ });
3233
+ this.observer.on("call-added", this._onNewObservedCall);
3234
+ }
3235
+ observer;
3236
+ name = "OnAllCallObserverUpdater";
3237
+ description = "Call Observer's update() method when all of the ObservedCalls are updated";
3238
+ _updatedCalls = /* @__PURE__ */ new Set();
3239
+ closed = false;
3240
+ close() {
3241
+ if (this.closed) return;
3242
+ this.closed = true;
3243
+ this._updatedCalls.clear();
3244
+ }
3245
+ _onNewObservedCall({ observedCall }) {
3246
+ if (this.closed) return;
3247
+ const onUpdate = () => this._onObservedCallUpdated(observedCall);
3248
+ observedCall.once("close", () => {
3249
+ observedCall.off("update", onUpdate);
3250
+ this._updatedCalls.delete(observedCall.callId);
3251
+ this._updateIfEveryCallUpdated();
3252
+ });
3253
+ observedCall.on("update", onUpdate);
3254
+ }
3255
+ _onObservedCallUpdated(observedCall) {
3256
+ if (observedCall.closed) return;
3257
+ this._updatedCalls.add(observedCall.callId);
3258
+ this._updateIfEveryCallUpdated();
3259
+ }
3260
+ _updateIfEveryCallUpdated() {
3261
+ if (this._updatedCalls.size < this.observer.observedCalls.size) return;
3262
+ else if (this.closed) return;
3263
+ this._updatedCalls.clear();
3264
+ this.observer.update();
3265
+ }
3266
+ };
3267
+
3268
+ // src/updaters/OnAnyCallObserverUpdater.ts
3269
+ var OnAnyCallObserverUpdater = class {
3270
+ constructor(observver) {
3271
+ this.observver = observver;
3272
+ this._onNewObservedCall = this._onNewObservedCall.bind(this);
3273
+ this.observver.once("observer-closed", () => {
3274
+ this.observver.off("call-added", this._onNewObservedCall);
3275
+ });
3276
+ this.observver.on("call-added", this._onNewObservedCall);
3277
+ }
3278
+ observver;
3279
+ name = "OnAnyCallObserverUpdater";
3280
+ description = "Call Observer's update() method on any of the ObservedCall is updated";
3281
+ closed = false;
3282
+ close() {
3283
+ if (this.closed) return;
3284
+ this.closed = true;
3285
+ }
3286
+ _onNewObservedCall({ observedCall }) {
3287
+ if (this.closed) return;
3288
+ const onUpdate = () => {
3289
+ if (this.closed) return;
3290
+ this.observver.update();
3291
+ };
3292
+ observedCall.once("close", () => {
3293
+ observedCall.off("update", onUpdate);
3294
+ });
3295
+ observedCall.on("update", onUpdate);
3296
+ }
3297
+ };
3298
+
3299
+ // src/common/Middleware.ts
3300
+ var Executor = class {
3301
+ constructor(stack, finalCallback) {
3302
+ this.stack = stack;
3303
+ this.finalCallback = finalCallback;
3304
+ }
3305
+ stack;
3306
+ finalCallback;
3307
+ done = false;
3308
+ index = 0;
3309
+ prevIndex = -1;
3310
+ // Executes the middleware stack
3311
+ execute(input) {
3312
+ if (this.index <= this.prevIndex) {
3313
+ throw new Error("Middleware must call next() only once!");
3314
+ } else if (this.done) {
3315
+ throw new Error("Middleware stack has already been executed!");
3316
+ }
3317
+ this.prevIndex = this.index;
3318
+ const middleware = this.stack[this.index];
3319
+ this.index++;
3320
+ if (middleware) {
3321
+ return middleware(input, (nextInput) => this.execute(nextInput));
3322
+ }
3323
+ this.done = true;
3324
+ this.finalCallback?.(input);
3325
+ }
3326
+ };
3327
+ var MiddlewareProcessor = class {
3328
+ stack = [];
3329
+ finalCallback;
3330
+ addMiddleware(...middlewares) {
3331
+ if (middlewares && middlewares.length > 0) {
3332
+ this.stack.push(...middlewares);
3333
+ }
3334
+ return this;
3335
+ }
3336
+ removeMiddleware(...middlewares) {
3337
+ if (middlewares && middlewares.length > 0) {
3338
+ for (const middleware of middlewares) {
3339
+ const index = this.stack.indexOf(middleware);
3340
+ if (index >= 0) {
3341
+ this.stack.splice(index, 1);
3342
+ }
3343
+ }
3344
+ }
3345
+ return this;
3346
+ }
3347
+ process(value) {
3348
+ if (this.stack.length === 0) {
3349
+ return this.finalCallback?.(value);
3350
+ }
3351
+ const executor = new Executor(this.stack, this.finalCallback);
3352
+ executor.execute(value);
3353
+ }
3354
+ };
3355
+
3356
+ // src/ObservedMediasoupRouter.ts
3357
+ var import_events5 = require("events");
3358
+ var logger6 = createLogger("ObservedMediasoupRouter");
3359
+ var ObservedMediasoupRouter = class extends import_events5.EventEmitter {
3360
+ router;
3361
+ sample;
3362
+ appData;
3363
+ webrtcTransportIds = /* @__PURE__ */ new Set();
3364
+ get attachments() {
3365
+ return this.sample.attachments;
3366
+ }
3367
+ closed = false;
3368
+ constructor(settings) {
3369
+ super();
3370
+ this.router = settings.router;
3371
+ this.appData = settings.appData ?? {};
3372
+ this.sample = {
3373
+ routerId: this.router.id,
3374
+ attachments: settings.attachments ?? {},
3375
+ createdAt: Date.now(),
3376
+ producers: [],
3377
+ consumers: [],
3378
+ dataProducers: [],
3379
+ dataConsumers: [],
3380
+ transports: []
3381
+ };
3382
+ this.attachRouterListeners();
3383
+ }
3384
+ get id() {
3385
+ return this.router.id;
3386
+ }
3387
+ addTransport = (transport) => {
3388
+ let transportType = transport.type;
3389
+ if (!transportType) {
3390
+ if (transport.constructor.name === "WebRtcTransport") transportType = "webrtc";
3391
+ else if (transport.constructor.name === "PlainTransport") transportType = "plain";
3392
+ else if (transport.constructor.name === "PipeTransport") transportType = "pipe";
3393
+ else if (transport.constructor.name === "DirectTransport") transportType = "direct";
3394
+ }
3395
+ if (!transportType) return logger6.warn(`Unknown transport type for transport ${transport.id}: ${transport.constructor.name}`);
3396
+ switch (transportType) {
3397
+ case "webrtc":
3398
+ return this.addWebRtcTransport(transport);
3399
+ case "plain":
3400
+ return this.addPlainTransport(transport);
3401
+ case "pipe":
3402
+ return this.addPipeTransport(transport);
3403
+ case "direct":
3404
+ return this.addDirectTransport(transport);
3405
+ default:
3406
+ return logger6.warn(`Unsupported transport type for transport ${transport.id}: ${transportType}`);
3407
+ }
3408
+ };
3409
+ addWebRtcTransport(transport) {
3410
+ const history = [];
3411
+ const transportSample = {
3412
+ id: transport.id,
3413
+ type: "webrtc",
3414
+ createdAt: Date.now(),
3415
+ tuple: transport.iceSelectedTuple,
3416
+ history
3417
+ };
3418
+ this.sample.transports.push(transportSample);
3419
+ const onIceStateChange = (iceState) => {
3420
+ history.push({
3421
+ type: `icestate-changed-to-${iceState}`,
3422
+ timestamp: Date.now()
3423
+ });
3424
+ };
3425
+ const onIceSelectedTupleChange = (tuple) => {
3426
+ transportSample.tuple = tuple;
3427
+ history.push({
3428
+ type: "iceselectedtuple-changed",
3429
+ timestamp: Date.now(),
3430
+ ...tuple
3431
+ });
3432
+ };
3433
+ const onDtlsStateChange = (dtlsState) => {
3434
+ history.push({
3435
+ type: `dtlsstate-changed-to-${dtlsState}`,
3436
+ timestamp: Date.now()
3437
+ });
3438
+ if (dtlsState === "connected" && transportSample.connectedAt === void 0) {
3439
+ transportSample.connectedAt = Date.now();
3440
+ }
3441
+ };
3442
+ const onSctpStateChange = (sctpState) => {
3443
+ history.push({
3444
+ type: `sctpstate-changed-to-${sctpState}`,
3445
+ timestamp: Date.now()
3446
+ });
3447
+ };
3448
+ this._attachTransportObserverListeners(transport, transportSample, () => {
3449
+ transport.observer.off("icestatechange", onIceStateChange);
3450
+ transport.observer.off("iceselectedtuplechange", onIceSelectedTupleChange);
3451
+ transport.observer.off("dtlsstatechange", onDtlsStateChange);
3452
+ transport.observer.off("sctpstatechange", onSctpStateChange);
3453
+ this.webrtcTransportIds.delete(transport.id);
3454
+ });
3455
+ transport.observer.on("icestatechange", onIceStateChange);
3456
+ transport.observer.on("iceselectedtuplechange", onIceSelectedTupleChange);
3457
+ transport.observer.on("dtlsstatechange", onDtlsStateChange);
3458
+ transport.observer.on("sctpstatechange", onSctpStateChange);
3459
+ this.webrtcTransportIds.add(transport.id);
3460
+ }
3461
+ addPlainTransport(transport) {
3462
+ const history = [];
3463
+ const transportSample = {
3464
+ id: transport.id,
3465
+ type: "plain",
3466
+ createdAt: Date.now(),
3467
+ tuple: transport.tuple,
3468
+ rtcpTuple: transport.rtcpTuple,
3469
+ history
3470
+ };
3471
+ this.sample.transports.push(transportSample);
3472
+ const onTuple = (tuple) => {
3473
+ transportSample.tuple = tuple;
3474
+ if (transportSample.connectedAt === void 0) transportSample.connectedAt = Date.now();
3475
+ history.push({ type: "tuple-changed", timestamp: Date.now(), ...tuple });
3476
+ };
3477
+ const onRtcpTuple = (rtcpTuple) => {
3478
+ transportSample.rtcpTuple = rtcpTuple;
3479
+ history.push({ type: "rtcptuple-changed", timestamp: Date.now(), ...rtcpTuple });
3480
+ };
3481
+ const onSctpStateChange = (sctpState) => {
3482
+ if (sctpState === "connected" && transportSample.connectedAt === void 0) {
3483
+ transportSample.connectedAt = Date.now();
3484
+ }
3485
+ history.push({
3486
+ type: `sctpstate-changed-to-${sctpState}`,
3487
+ timestamp: Date.now()
3488
+ });
3489
+ };
3490
+ this._attachTransportObserverListeners(transport, transportSample, () => {
3491
+ transport.observer.off("tuple", onTuple);
3492
+ transport.observer.off("rtcptuple", onRtcpTuple);
3493
+ transport.observer.off("sctpstatechange", onSctpStateChange);
3494
+ });
3495
+ transport.observer.on("tuple", onTuple);
3496
+ transport.observer.on("rtcptuple", onRtcpTuple);
3497
+ transport.observer.on("sctpstatechange", onSctpStateChange);
3498
+ }
3499
+ addPipeTransport(transport) {
3500
+ const history = [];
3501
+ const transportSample = {
3502
+ id: transport.id,
3503
+ type: "pipe",
3504
+ createdAt: Date.now(),
3505
+ tuple: transport.tuple,
3506
+ history
3507
+ };
3508
+ this.sample.transports.push(transportSample);
3509
+ const onSctpStateChange = (sctpState) => {
3510
+ if (sctpState === "connected" && transportSample.connectedAt === void 0) {
3511
+ transportSample.connectedAt = Date.now();
3512
+ }
3513
+ history.push({
3514
+ type: `sctpstate-changed-to-${sctpState}`,
3515
+ timestamp: Date.now()
3516
+ });
3517
+ };
3518
+ this._attachTransportObserverListeners(transport, transportSample, () => {
3519
+ transport.observer.off("sctpstatechange", onSctpStateChange);
3520
+ });
3521
+ transport.observer.on("sctpstatechange", onSctpStateChange);
3522
+ }
3523
+ addDirectTransport(transport) {
3524
+ const now = Date.now();
3525
+ const transportSample = {
3526
+ id: transport.id,
3527
+ type: "direct",
3528
+ createdAt: now,
3529
+ // A DirectTransport has no network layer — it is connected the instant it exists.
3530
+ connectedAt: now,
3531
+ history: []
3532
+ };
3533
+ this.sample.transports.push(transportSample);
3534
+ this._attachTransportObserverListeners(transport, transportSample);
3535
+ }
3536
+ addProducer(transport, producer) {
3537
+ const firstCodec = producer.rtpParameters.codecs[0];
3538
+ const codecInfo = {
3539
+ mimeType: firstCodec?.mimeType ?? "unknown/unknown",
3540
+ payloadType: firstCodec?.payloadType ?? 0,
3541
+ clockRate: firstCodec?.clockRate ?? 0,
3542
+ channels: firstCodec?.channels,
3543
+ parameters: firstCodec?.parameters,
3544
+ rtcpFeedback: firstCodec?.rtcpFeedback
3545
+ };
3546
+ const producerSample = {
3547
+ id: producer.id,
3548
+ createdAt: Date.now(),
3549
+ kind: producer.kind,
3550
+ codecInfo,
3551
+ ssrcs: producer.rtpParameters.encodings?.map((encoding) => encoding.ssrc).filter((ssrc) => typeof ssrc === "number"),
3552
+ rids: producer.rtpParameters.encodings?.map((encoding) => encoding.rid).filter((rid) => typeof rid === "string"),
3553
+ history: [],
3554
+ transportId: transport.id
3555
+ };
3556
+ this.sample.producers.push(producerSample);
3557
+ const onPause = () => {
3558
+ producerSample.history.push({
3559
+ type: "pause",
3560
+ timestamp: Date.now()
3561
+ });
3562
+ };
3563
+ const onResume = () => {
3564
+ producerSample.history.push({
3565
+ type: "resume",
3566
+ timestamp: Date.now()
3567
+ });
3568
+ };
3569
+ producer.observer.once("close", () => {
3570
+ producer.observer.off("pause", onPause);
3571
+ producer.observer.off("resume", onResume);
3572
+ producerSample.closedAt = Date.now();
3573
+ });
3574
+ producer.observer.on("pause", onPause);
3575
+ producer.observer.on("resume", onResume);
3576
+ }
3577
+ addConsumer(transport, consumer) {
3578
+ const consumerSample = {
3579
+ id: consumer.id,
3580
+ producerId: consumer.producerId,
3581
+ transportId: transport.id,
3582
+ createdAt: Date.now(),
3583
+ kind: consumer.kind,
3584
+ history: []
3585
+ };
3586
+ this.sample.consumers.push(consumerSample);
3587
+ const onPause = () => {
3588
+ consumerSample.history.push({
3589
+ type: "pause",
3590
+ timestamp: Date.now()
3591
+ });
3592
+ };
3593
+ const onResume = () => {
3594
+ consumerSample.history.push({
3595
+ type: "resume",
3596
+ timestamp: Date.now()
3597
+ });
3598
+ };
3599
+ const onProducerPause = () => {
3600
+ consumerSample.history.push({
3601
+ type: "producerPaused",
3602
+ timestamp: Date.now()
3603
+ });
3604
+ };
3605
+ const onProducerResume = () => {
3606
+ consumerSample.history.push({
3607
+ type: "producerResumed",
3608
+ timestamp: Date.now()
3609
+ });
3610
+ };
3611
+ consumer.observer.once("close", () => {
3612
+ consumer.observer.off("pause", onPause);
3613
+ consumer.observer.off("resume", onResume);
3614
+ consumer.off("producerresume", onProducerResume);
3615
+ consumer.off("producerpause", onProducerPause);
3616
+ consumerSample.closedAt = Date.now();
3617
+ });
3618
+ consumer.observer.on("pause", onPause);
3619
+ consumer.observer.on("resume", onResume);
3620
+ consumer.on("producerpause", onProducerPause);
3621
+ consumer.on("producerresume", onProducerResume);
3622
+ }
3623
+ addDataProducer(transport, dataProducer) {
3624
+ const dataProducerSample = {
3625
+ id: dataProducer.id,
3626
+ transportId: transport.id,
3627
+ createdAt: Date.now(),
3628
+ label: dataProducer.label,
3629
+ protocol: dataProducer.protocol
3630
+ };
3631
+ this.sample.dataProducers.push(dataProducerSample);
3632
+ dataProducer.observer.once("close", () => {
3633
+ dataProducerSample.closedAt = Date.now();
3634
+ });
3635
+ }
3636
+ addDataConsumer(transport, dataConsumer) {
3637
+ const dataConsumerSample = {
3638
+ id: dataConsumer.id,
3639
+ dataProducerId: dataConsumer.dataProducerId,
3640
+ transportId: transport.id,
3641
+ createdAt: Date.now(),
3642
+ label: dataConsumer.label,
3643
+ protocol: dataConsumer.protocol
3644
+ };
3645
+ this.sample.dataConsumers.push(dataConsumerSample);
3646
+ dataConsumer.observer.once("close", () => {
3647
+ dataConsumerSample.closedAt = Date.now();
3648
+ });
3649
+ }
3650
+ close() {
3651
+ if (this.closed) return;
3652
+ this.closed = true;
3653
+ this.emit("close");
3654
+ }
3655
+ attachRouterListeners() {
3656
+ this.router.observer.once("close", () => {
3657
+ this.router.observer.off("newtransport", this.addTransport);
3658
+ this.sample.closedAt = Date.now();
3659
+ this.close();
3660
+ });
3661
+ this.router.observer.on("newtransport", this.addTransport);
3662
+ }
3663
+ _attachTransportObserverListeners(transport, transportSample, onClose) {
3664
+ const onNewProducer = (producer) => {
3665
+ this.addProducer(transport, producer);
3666
+ };
3667
+ const onNewConsumer = (consumer) => {
3668
+ this.addConsumer(transport, consumer);
3669
+ };
3670
+ const onNewDataProducer = (dataProducer) => {
3671
+ this.addDataProducer(transport, dataProducer);
3672
+ };
3673
+ const onNewDataConsumer = (dataConsumer) => {
3674
+ this.addDataConsumer(transport, dataConsumer);
3675
+ };
3676
+ transport.observer.once("close", () => {
3677
+ transport.observer.off("newproducer", onNewProducer);
3678
+ transport.observer.off("newconsumer", onNewConsumer);
3679
+ transport.observer.off("newdataproducer", onNewDataProducer);
3680
+ transport.observer.off("newdataconsumer", onNewDataConsumer);
3681
+ onClose?.();
3682
+ transportSample.closedAt = Date.now();
3683
+ });
3684
+ transport.observer.on("newproducer", onNewProducer);
3685
+ transport.observer.on("newconsumer", onNewConsumer);
3686
+ transport.observer.on("newdataproducer", onNewDataProducer);
3687
+ transport.observer.on("newdataconsumer", onNewDataConsumer);
3688
+ }
3689
+ };
3690
+
3691
+ // src/Observer.ts
3692
+ var logger7 = createLogger("Observer");
3693
+ var Observer = class extends import_events6.EventEmitter {
3694
+ constructor(config = {
3695
+ updatePolicy: "update-when-all-call-updated",
3696
+ appData: {}
3697
+ }) {
3698
+ super();
3699
+ this.config = config;
3700
+ this.setMaxListeners(Infinity);
3701
+ this.update = this.update.bind(this);
3702
+ const currentUpdatePolicy = config?.updatePolicy ?? "update-when-all-call-updated";
3703
+ switch (currentUpdatePolicy) {
3704
+ case "update-on-any-call-updated":
3705
+ this.updater = new OnAnyCallObserverUpdater(this);
3706
+ break;
3707
+ case "update-when-all-call-updated":
3708
+ this.updater = new OnAllCallObserverUpdater(this);
3709
+ break;
3710
+ case "none":
3711
+ break;
3712
+ }
3713
+ }
3714
+ config;
3715
+ observedTURN = new ObservedTURN();
3716
+ observedCalls = /* @__PURE__ */ new Map();
3717
+ observedMediasoupRouters = /* @__PURE__ */ new Map();
3718
+ updater;
3719
+ /** Ancestry base shared by all Observer-bus events originating at the observer. */
3720
+ eventScope = { observer: this };
3721
+ closed = false;
3722
+ totalAddedCall = 0;
3723
+ totalRemovedCall = 0;
3724
+ numberOfClientsUsingTurn = 0;
3725
+ numberOfClients = 0;
3726
+ numberOfInboundRtpStreams = 0;
3727
+ numberOfOutboundRtpStreams = 0;
3728
+ numberOfDataChannels = 0;
3729
+ numberOfPeerConnections = 0;
3730
+ /** Global, pre-dispatch middleware chain run on every accepted sample. */
3731
+ acceptMiddlewares = new MiddlewareProcessor();
3732
+ get numberOfCalls() {
3733
+ return this.observedCalls.size;
3734
+ }
3735
+ get appData() {
3736
+ return this.config.appData;
3737
+ }
3738
+ getObservedCall(callId) {
3739
+ if (this.closed || !this.observedCalls.has(callId)) return;
3740
+ return this.observedCalls.get(callId);
3741
+ }
3742
+ createObservedCall(settings) {
3743
+ if (this.closed) {
3744
+ logger7.warn("Attempted to create a call (callId: %s) on a closed observer", settings.callId);
3745
+ return void 0;
3746
+ }
3747
+ if (this.observedCalls.has(settings.callId)) {
3748
+ logger7.warn("Observed Call with id %s already exists; returning the existing instance", settings.callId);
3749
+ return this.observedCalls.get(settings.callId);
3750
+ }
3751
+ const callSettings = {
3752
+ ...settings,
3753
+ updatePolicy: settings.updatePolicy ?? this.config.defaultCallUpdatePolicy,
3754
+ closeCallIfEmptyForMs: settings.closeCallIfEmptyForMs ?? this.config.closeCallIfEmptyForMs,
3755
+ appData: settings.appData ?? this.config.createCallAppData?.({ callId: settings.callId, observer: this })
3756
+ };
3757
+ const observedCall = new ObservedCall(callSettings, this);
3758
+ observedCall.remoteTrackResolver = this.config.createTrackResolver?.(observedCall);
3759
+ observedCall.once("close", () => {
3760
+ this.observedCalls.delete(observedCall.callId);
3761
+ ++this.totalRemovedCall;
3762
+ });
3763
+ this.observedCalls.set(observedCall.callId, observedCall);
3764
+ ++this.totalAddedCall;
3765
+ this._notify("call-added", { ...this.eventScope, observedCall });
3766
+ return observedCall;
3767
+ }
3768
+ getOrCreateObservedCall(settings) {
3769
+ return this.getObservedCall(settings.callId) ?? this.createObservedCall(settings);
3770
+ }
3771
+ createObservedMediasoupRouter(settings) {
3772
+ if (this.closed) {
3773
+ logger7.warn("Attempted to create mediasoup router (id: %d) on a closed observer", settings.router.id);
3774
+ return void 0;
3775
+ }
3776
+ if (this.observedMediasoupRouters.has(settings.router.id)) {
3777
+ logger7.warn("Observed Mediasoup Router (id %s) already exists; returning the existing instance", settings.router.id);
3778
+ return this.observedMediasoupRouters.get(settings.router.id);
3779
+ }
3780
+ const observedMediasoupRouter = new ObservedMediasoupRouter(settings);
3781
+ const observedMediasoupRouterScope = {
3782
+ observedMediasoupRouter,
3783
+ observer: this
3784
+ };
3785
+ if (settings.matchPeerConnectionByWebRtcTransportId) {
3786
+ const onPeerConnectionAdded = (observedPeerConnectionScope) => {
3787
+ if (!observedMediasoupRouter.webrtcTransportIds.has(observedPeerConnectionScope.observedPeerConnection.peerConnectionId)) return;
3788
+ this.emit("mediasoup-router-matched-with-peer-connection", {
3789
+ ...observedMediasoupRouterScope,
3790
+ ...observedPeerConnectionScope
3791
+ });
3792
+ };
3793
+ const stopMatching = () => this.off("peer-connection-added", onPeerConnectionAdded);
3794
+ this.on("peer-connection-added", onPeerConnectionAdded);
3795
+ this.once("observer-closed", stopMatching);
3796
+ observedMediasoupRouter.once("close", stopMatching);
3797
+ }
3798
+ observedMediasoupRouter.once("close", () => {
3799
+ this.observedMediasoupRouters.delete(observedMediasoupRouter.id);
3800
+ this.emit("mediasoup-router-removed", observedMediasoupRouterScope);
3801
+ });
3802
+ this.observedMediasoupRouters.set(observedMediasoupRouter.id, observedMediasoupRouter);
3803
+ this.emit("mediasoup-router-added", observedMediasoupRouterScope);
3804
+ return observedMediasoupRouter;
3805
+ }
3806
+ close() {
3807
+ if (this.closed) {
3808
+ return logger7.debug("Attempted to close twice");
3809
+ }
3810
+ this.closed = true;
3811
+ this.observedCalls.forEach((call) => call.close());
3812
+ this._notify("observer-closed", { ...this.eventScope });
3813
+ }
3814
+ accept(sample, context) {
3815
+ if (this.closed) {
3816
+ return this._notify("sample-rejected", { ...this.eventScope, reason: "observer-closed", sample });
3817
+ }
3818
+ try {
3819
+ this.acceptMiddlewares.process({ sample, context });
3820
+ } catch (err) {
3821
+ logger7.warn("An accept middleware threw; dropping the sample. %o", err);
3822
+ }
3823
+ if (!sample.callId) {
3824
+ this._notify("sample-rejected", { ...this.eventScope, reason: "missing-callId", sample });
3825
+ return;
3826
+ }
3827
+ if (!sample.clientId) {
3828
+ this._notify("sample-rejected", { ...this.eventScope, reason: "missing-clientId", sample });
3829
+ return;
3830
+ }
3831
+ let call = this.getObservedCall(sample.callId);
3832
+ if (!call) {
3833
+ call = this.createObservedCall({
3834
+ callId: sample.callId,
3835
+ appData: this.config.createCallAppData?.({ callId: sample.callId, observer: this })
3836
+ });
3837
+ }
3838
+ if (!call) return;
3839
+ let client = call.getObservedClient(sample.clientId);
3840
+ if (!client) {
3841
+ client = call.createObservedClient({
3842
+ clientId: sample.clientId,
3843
+ appData: this.config.createClientAppData?.({ clientId: sample.clientId, observedCall: call })
3844
+ });
3845
+ }
3846
+ if (!client) return;
3847
+ client.accept(sample, context);
3848
+ }
3849
+ update() {
3850
+ if (this.closed) {
3851
+ return;
3852
+ }
3853
+ this.numberOfInboundRtpStreams = 0;
3854
+ this.numberOfOutboundRtpStreams = 0;
3855
+ this.numberOfPeerConnections = 0;
3856
+ this.numberOfDataChannels = 0;
3857
+ this.numberOfClients = 0;
3858
+ this.numberOfClientsUsingTurn = 0;
3859
+ for (const call of this.observedCalls.values()) {
3860
+ this.numberOfInboundRtpStreams += call.numberOfInboundRtpStreams;
3861
+ this.numberOfOutboundRtpStreams += call.numberOfOutboundRtpStreams;
3862
+ this.numberOfPeerConnections += call.numberOfPeerConnections;
3863
+ this.numberOfDataChannels += call.numberOfDataChannels;
3864
+ this.numberOfClients += call.numberOfClients;
3865
+ this.numberOfClientsUsingTurn += call.clientsUsedTurn.size;
3866
+ }
3867
+ this.observedTURN.update();
3868
+ this._notify("observer-updated", { ...this.eventScope });
3869
+ }
3870
+ /** Emit an Observer-bus event. */
3871
+ _notify(type, ...args) {
3872
+ this.emit(type, ...args);
3873
+ }
3874
+ };
3875
+
3876
+ // src/sinks/ClientSampleSink.ts
3877
+ var import_events7 = require("events");
3878
+ var ClientSampleSink = class extends import_events7.EventEmitter {
3879
+ };
3880
+
3881
+ // src/sinks/JsonlFileSink.ts
3882
+ var fs = __toESM(require("fs"));
3883
+ var path = __toESM(require("path"));
3884
+ var JsonlFileSink = class extends ClientSampleSink {
3885
+ /** The file this sink writes to. Read it (e.g. in a `close` handler) to upload/move the file. */
3886
+ path;
3887
+ _stream;
3888
+ _serializeSample;
3889
+ constructor(options) {
3890
+ super();
3891
+ this.path = options.path;
3892
+ this._stream = fs.createWriteStream(this.path, { flags: "a" });
3893
+ this._stream.on("close", () => this.emit("close"));
3894
+ this._stream.on("finish", () => this.emit("finish"));
3895
+ this._stream.on("drain", () => this.emit("drain"));
3896
+ this._stream.on("error", (err) => this.emit("error", err));
3897
+ this._serializeSample = options.serializeSample ?? ((sample) => JSON.stringify(sample));
3898
+ }
3899
+ write(sample) {
3900
+ return this._stream.write(`${this._serializeSample(sample)}
3901
+ `);
3902
+ }
3903
+ end() {
3904
+ this._stream.end();
3905
+ }
3906
+ };
3907
+ function createJsonlFileSink(options) {
3908
+ return new JsonlFileSink(options);
3909
+ }
3910
+ function createJsonlFileSinkFactory(options) {
3911
+ return ({ clientId, observedCall }) => {
3912
+ const filename = options.getFileName?.({ callId: observedCall.callId, clientId }) ?? `${observedCall.callId}__${clientId}.jsonl`;
3913
+ return createJsonlFileSink({
3914
+ path: path.join(options.directory, filename),
3915
+ serializeSample: options.serializeSample
3916
+ });
3917
+ };
3918
+ }
3919
+
3920
+ // src/sinks/InMemorySink.ts
3921
+ var InMemorySink = class extends ClientSampleSink {
3922
+ constructor(samples = []) {
3923
+ super();
3924
+ this.samples = samples;
3925
+ }
3926
+ samples;
3927
+ write(sample) {
3928
+ this.samples.push(sample);
3929
+ return true;
3930
+ }
3931
+ end() {
3932
+ this.emit("close");
3933
+ }
3934
+ };
3935
+ function createInMemorySink(samples) {
3936
+ return new InMemorySink(samples);
3937
+ }
3938
+
3939
+ // src/utils/RemoteTrackResolver.ts
3940
+ var RemoteTrackResolver = class {
3941
+ constructor(observedCall, resolvers) {
3942
+ this.observedCall = observedCall;
3943
+ this.resolvers = resolvers;
3944
+ const observer = observedCall.observer;
3945
+ const onInboundAdded = (p) => {
3946
+ if (p.observedCall === this.observedCall) this._addInboundTrack(p.observedInboundTrack);
3947
+ };
3948
+ const onInboundRemoved = (p) => {
3949
+ if (p.observedCall === this.observedCall) this._removeInboundTrack(p.observedInboundTrack);
3950
+ };
3951
+ const onOutboundAdded = (p) => {
3952
+ if (p.observedCall === this.observedCall) this._addOutboundTrack(p.observedOutboundTrack);
3953
+ };
3954
+ const onOutboundRemoved = (p) => {
3955
+ if (p.observedCall === this.observedCall) this._removeOutboundTrack(p.observedOutboundTrack);
3956
+ };
3957
+ observedCall.once("close", () => {
3958
+ observer.off("inbound-track-added", onInboundAdded);
3959
+ observer.off("inbound-track-removed", onInboundRemoved);
3960
+ observer.off("outbound-track-added", onOutboundAdded);
3961
+ observer.off("outbound-track-removed", onOutboundRemoved);
3962
+ });
3963
+ observer.on("inbound-track-added", onInboundAdded);
3964
+ observer.on("inbound-track-removed", onInboundRemoved);
3965
+ observer.on("outbound-track-added", onOutboundAdded);
3966
+ observer.on("outbound-track-removed", onOutboundRemoved);
3967
+ }
3968
+ observedCall;
3969
+ resolvers;
3970
+ _publisherIdToOutboundTrack = /* @__PURE__ */ new Map();
3971
+ _subscriberIdToInboundTrack = /* @__PURE__ */ new Map();
3972
+ /** The published (outbound) track for a publisher id, if any. */
3973
+ getOutboundTrackByPublisherId(publisherId) {
3974
+ return this._publisherIdToOutboundTrack.get(publisherId);
3975
+ }
3976
+ /** The subscribed (inbound) track for a subscriber id, if the strategy resolves subscriber ids. */
3977
+ getInboundTrackBySubscriberId(subscriberId) {
3978
+ return this._subscriberIdToInboundTrack.get(subscriberId);
3979
+ }
3980
+ // RemoteTrackResolver interface — thin readers over the links maintained on the tracks.
3981
+ resolveRemoteOutboundTrack(inboundTrack) {
3982
+ return inboundTrack.remoteOutboundTrack;
3983
+ }
3984
+ resolveRemoteInboundTracks(outboundTrack) {
3985
+ return [...outboundTrack.remoteInboundTracks];
3986
+ }
3987
+ _addInboundTrack(inboundTrack) {
3988
+ const publisherId = this.resolvers.resolveInboundTrackPublisherId(inboundTrack);
3989
+ if (!publisherId) return;
3990
+ const subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);
3991
+ if (subscriberId) {
3992
+ this._subscriberIdToInboundTrack.set(subscriberId, inboundTrack);
3993
+ }
3994
+ const outboundTrack = this._publisherIdToOutboundTrack.get(publisherId);
3995
+ if (!outboundTrack) return;
3996
+ outboundTrack.remoteInboundTracks.add(inboundTrack);
3997
+ inboundTrack.remoteOutboundTrack = outboundTrack;
3998
+ }
3999
+ _removeInboundTrack(inboundTrack) {
4000
+ inboundTrack.remoteOutboundTrack?.remoteInboundTracks.delete(inboundTrack);
4001
+ inboundTrack.remoteOutboundTrack = void 0;
4002
+ const subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);
4003
+ if (subscriberId) {
4004
+ this._subscriberIdToInboundTrack.delete(subscriberId);
4005
+ }
4006
+ }
4007
+ _addOutboundTrack(outboundTrack) {
4008
+ const publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);
4009
+ if (!publisherId) return;
4010
+ this._publisherIdToOutboundTrack.set(publisherId, outboundTrack);
4011
+ for (const observedClient of this.observedCall.observedClients.values()) {
4012
+ for (const observedPeerConnection of observedClient.observedPeerConnections.values()) {
4013
+ for (const inboundTrack of observedPeerConnection.observedInboundTracks.values()) {
4014
+ if (this.resolvers.resolveInboundTrackPublisherId(inboundTrack) !== publisherId) continue;
4015
+ outboundTrack.remoteInboundTracks.add(inboundTrack);
4016
+ inboundTrack.remoteOutboundTrack = outboundTrack;
4017
+ }
4018
+ }
4019
+ }
4020
+ }
4021
+ _removeOutboundTrack(outboundTrack) {
4022
+ const publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);
4023
+ if (publisherId && this._publisherIdToOutboundTrack.get(publisherId) === outboundTrack) {
4024
+ this._publisherIdToOutboundTrack.delete(publisherId);
4025
+ }
4026
+ for (const inboundTrack of outboundTrack.remoteInboundTracks) {
4027
+ inboundTrack.remoteOutboundTrack = void 0;
4028
+ }
4029
+ outboundTrack.remoteInboundTracks.clear();
4030
+ }
4031
+ };
4032
+
4033
+ // src/utils/RemoteTrackResolverFactories.ts
4034
+ function createDefaultMediasoupRemoteTrackResolverFactory() {
4035
+ return (observedCall) => new RemoteTrackResolver(observedCall, {
4036
+ resolveInboundTrackPublisherId: (inboundTrack) => inboundTrack.attachments?.producerId,
4037
+ resolveInboundTrackSubscriberId: (inboundTrack) => inboundTrack.attachments?.consumerId,
4038
+ resolveOutboundTrackPublisherId: (outboundTrack) => outboundTrack.attachments?.producerId
4039
+ });
4040
+ }
4041
+ function createP2pRemoteTrackResolverFactory() {
4042
+ return (observedCall) => new RemoteTrackResolver(observedCall, {
4043
+ resolveInboundTrackPublisherId: (inboundTrack) => {
4044
+ const ssrc = inboundTrack.getInboundRtp()?.ssrc;
4045
+ return ssrc ? `${ssrc}` : void 0;
4046
+ },
4047
+ resolveInboundTrackSubscriberId: (inboundTrack) => {
4048
+ const ssrc = inboundTrack.getInboundRtp()?.ssrc;
4049
+ return ssrc ? `${ssrc}` : void 0;
4050
+ },
4051
+ resolveOutboundTrackPublisherId: (outboundTrack) => {
4052
+ const rtps = outboundTrack.getOutboundRtps();
4053
+ if (!rtps || rtps.length === 0) return void 0;
4054
+ return rtps.map((rtp) => rtp.ssrc).join(",");
4055
+ }
4056
+ });
4057
+ }
4058
+ // Annotate the CommonJS export names for ESM import in node:
4059
+ 0 && (module.exports = {
4060
+ ClientEventTypes,
4061
+ ClientMetaTypes,
4062
+ ClientSampleSink,
4063
+ Detectors,
4064
+ InMemorySink,
4065
+ JsonlFileSink,
4066
+ ObservedCall,
4067
+ ObservedCertificate,
4068
+ ObservedClient,
4069
+ ObservedCodec,
4070
+ ObservedDataChannel,
4071
+ ObservedIceCandidate,
4072
+ ObservedIceCandidatePair,
4073
+ ObservedIceTransport,
4074
+ ObservedInboundRtp,
4075
+ ObservedInboundTrack,
4076
+ ObservedMediaPlayout,
4077
+ ObservedMediaSource,
4078
+ ObservedMediasoupRouter,
4079
+ ObservedOutboundRtp,
4080
+ ObservedOutboundTrack,
4081
+ ObservedPeerConnection,
4082
+ ObservedPeerConnectionTransport,
4083
+ ObservedRemoteInboundRtp,
4084
+ ObservedRemoteOutboundRtp,
4085
+ Observer,
4086
+ RemoteTrackResolver,
4087
+ createDefaultMediasoupRemoteTrackResolverFactory,
4088
+ createInMemorySink,
4089
+ createJsonlFileSink,
4090
+ createJsonlFileSinkFactory,
4091
+ createLogger,
4092
+ createP2pRemoteTrackResolverFactory,
4093
+ setObserverLogger
4094
+ });
4095
+ //# sourceMappingURL=index.js.map