@observertc/observer-js 1.0.0-beta.3 → 1.0.0-beta.5

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