@observertc/observer-js 1.0.0-beta.4 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -330,8 +330,7 @@ var ObservedOutboundRtp = class {
330
330
  return this._peerConnection.observedMediaSources.get(this.mediaSourceId ?? "");
331
331
  }
332
332
  getTrack() {
333
- var _a;
334
- return (_a = this.getMediaSource()) == null ? void 0 : _a.getTrack();
333
+ return this.getMediaSource()?.getTrack();
335
334
  }
336
335
  update(stats) {
337
336
  this._visited = true;
@@ -1064,20 +1063,6 @@ var ObservedInboundTrack = class {
1064
1063
  this._peerConnection = _peerConnection;
1065
1064
  this._inboundRtp = _inboundRtp;
1066
1065
  this._mediaPlayout = _mediaPlayout;
1067
- this.report = {
1068
- trackId: this.id,
1069
- kind: this.kind,
1070
- fractionLostDistribution: {
1071
- gtOrEq050: 0,
1072
- lt001: 0,
1073
- lt005: 0,
1074
- lt010: 0,
1075
- lt020: 0,
1076
- lt050: 0,
1077
- count: 0,
1078
- sum: 0
1079
- }
1080
- };
1081
1066
  }
1082
1067
  timestamp;
1083
1068
  id;
@@ -1090,7 +1075,7 @@ var ObservedInboundTrack = class {
1090
1075
  value: void 0
1091
1076
  };
1092
1077
  appData;
1093
- report;
1078
+ remoteOutboundTrack;
1094
1079
  _visited = false;
1095
1080
  addedAt;
1096
1081
  removedAt;
@@ -1113,27 +1098,11 @@ var ObservedInboundTrack = class {
1113
1098
  getMediaPlayout() {
1114
1099
  return this._mediaPlayout;
1115
1100
  }
1116
- getRemoteOutboundTrack() {
1117
- var _a;
1118
- return (_a = this._peerConnection.client.call.remoteTrackResolver) == null ? void 0 : _a.resolveRemoteOutboundTrack(this);
1119
- }
1120
1101
  update(stats) {
1121
- var _a;
1122
1102
  this._visited = true;
1123
1103
  this.timestamp = stats.timestamp;
1124
1104
  this.calculatedScore.value = stats.score;
1125
1105
  this.attachments = stats.attachments;
1126
- const fl = (_a = this._inboundRtp) == null ? void 0 : _a.fractionLost;
1127
- if (fl !== void 0) {
1128
- if (fl < 0.01) this.report.fractionLostDistribution.lt001 += 1;
1129
- else if (fl < 0.05) this.report.fractionLostDistribution.lt005 += 1;
1130
- else if (fl < 0.1) this.report.fractionLostDistribution.lt010 += 1;
1131
- else if (fl < 0.2) this.report.fractionLostDistribution.lt020 += 1;
1132
- else if (fl < 0.5) this.report.fractionLostDistribution.lt050 += 1;
1133
- else this.report.fractionLostDistribution.gtOrEq050 += 1;
1134
- this.report.fractionLostDistribution.count += 1;
1135
- this.report.fractionLostDistribution.sum += fl;
1136
- }
1137
1106
  }
1138
1107
  };
1139
1108
 
@@ -1146,10 +1115,6 @@ var ObservedOutboundTrack = class {
1146
1115
  this._peerConnection = _peerConnection;
1147
1116
  this._outboundRtps = _outboundRtps;
1148
1117
  this._mediaSource = _mediaSource;
1149
- this.report = {
1150
- trackId: this.id,
1151
- kind: this.kind
1152
- };
1153
1118
  }
1154
1119
  timestamp;
1155
1120
  id;
@@ -1159,7 +1124,7 @@ var ObservedOutboundTrack = class {
1159
1124
  _mediaSource;
1160
1125
  _visited = false;
1161
1126
  appData;
1162
- report;
1127
+ remoteInboundTracks = /* @__PURE__ */ new Set();
1163
1128
  calculatedScore = {
1164
1129
  weight: 1,
1165
1130
  value: void 0
@@ -1185,10 +1150,6 @@ var ObservedOutboundTrack = class {
1185
1150
  getMediaSource() {
1186
1151
  return this._mediaSource;
1187
1152
  }
1188
- getRemoteInboundTracks() {
1189
- var _a;
1190
- return (_a = this._peerConnection.client.call.remoteTrackResolver) == null ? void 0 : _a.resolveRemoteInboundTracks(this);
1191
- }
1192
1153
  update(stats) {
1193
1154
  this._visited = true;
1194
1155
  this.timestamp = stats.timestamp;
@@ -1364,10 +1325,7 @@ var ObservedPeerConnection = class extends EventEmitter {
1364
1325
  }
1365
1326
  get selectedIceCandiadtePairForTurn() {
1366
1327
  return this.selectedIceCandidatePairs.filter(
1367
- (pair) => {
1368
- var _a, _b, _c;
1369
- return ((_a = pair.getLocalCandidate()) == null ? void 0 : _a.candidateType) === "relay" && ((_c = (_b = pair.getRemoteCandidate()) == null ? void 0 : _b.url) == null ? void 0 : _c.startsWith("turn:"));
1370
- }
1328
+ (pair) => pair.getLocalCandidate()?.candidateType === "relay" && pair.getRemoteCandidate()?.url?.startsWith("turn:")
1371
1329
  );
1372
1330
  }
1373
1331
  close() {
@@ -1415,7 +1373,6 @@ var ObservedPeerConnection = class extends EventEmitter {
1415
1373
  this._notify("peer-connection-closed", { ...this.eventScope });
1416
1374
  }
1417
1375
  accept(sample, context) {
1418
- var _a, _b, _c, _d, _e;
1419
1376
  if (this.closed) return;
1420
1377
  this._visited = true;
1421
1378
  if (context) this.appData = { ...this.appData, ...context };
@@ -1641,10 +1598,10 @@ var ObservedPeerConnection = class extends EventEmitter {
1641
1598
  this.usingTCP = false;
1642
1599
  this.usingTURN = false;
1643
1600
  for (const selectedCandidatePair of selectedIceCandidatePairs) {
1644
- if (((_a = selectedCandidatePair.getLocalCandidate()) == null ? void 0 : _a.protocol) === "tcp") {
1601
+ if (selectedCandidatePair.getLocalCandidate()?.protocol === "tcp") {
1645
1602
  this.usingTCP = true;
1646
1603
  }
1647
- if (((_b = selectedCandidatePair.getLocalCandidate()) == null ? void 0 : _b.candidateType) === "relay" && ((_d = (_c = selectedCandidatePair.getRemoteCandidate()) == null ? void 0 : _c.url) == null ? void 0 : _d.startsWith("turn:"))) {
1604
+ if (selectedCandidatePair.getLocalCandidate()?.candidateType === "relay" && selectedCandidatePair.getRemoteCandidate()?.url?.startsWith("turn:")) {
1648
1605
  selectedCandidatePairForTurn.push(selectedCandidatePair);
1649
1606
  this.usingTURN = true;
1650
1607
  }
@@ -1655,7 +1612,7 @@ var ObservedPeerConnection = class extends EventEmitter {
1655
1612
  if (!this.observedTurnServer) {
1656
1613
  this.observedTurnServer = this.client.call.observer.observedTURN.addPeerConnection(this);
1657
1614
  }
1658
- (_e = this.observedTurnServer) == null ? void 0 : _e.updateTurnUsage(...selectedCandidatePairForTurn);
1615
+ this.observedTurnServer?.updateTurnUsage(...selectedCandidatePairForTurn);
1659
1616
  } else if (wasUsingTURN) {
1660
1617
  if (!this.usingTURN) {
1661
1618
  this.client.call.observer.observedTURN.removePeerConnection(this);
@@ -1995,7 +1952,7 @@ var ObservedPeerConnection = class extends EventEmitter {
1995
1952
  );
1996
1953
  }
1997
1954
  const observedMediaSource = [...this.observedMediaSources.values()].find((mediaSource) => mediaSource.trackIdentifier === stats.id);
1998
- const outboundRtps = observedMediaSource ? [...this.observedOutboundRtps.values()].filter((outboundRtp) => outboundRtp.mediaSourceId === (observedMediaSource == null ? void 0 : observedMediaSource.id)) : void 0;
1955
+ const outboundRtps = observedMediaSource ? [...this.observedOutboundRtps.values()].filter((outboundRtp) => outboundRtp.mediaSourceId === observedMediaSource?.id) : void 0;
1999
1956
  observedOutboundTrack = new ObservedOutboundTrack(
2000
1957
  stats.timestamp,
2001
1958
  stats.id,
@@ -2142,60 +2099,19 @@ var ClientMetaTypes = /* @__PURE__ */ ((ClientMetaTypes2) => {
2142
2099
  var logger2 = createLogger("ObservedClient");
2143
2100
  var ObservedClient = class extends EventEmitter2 {
2144
2101
  constructor(settings, call) {
2145
- var _a, _b;
2146
2102
  super();
2147
2103
  this.call = call;
2148
2104
  this.setMaxListeners(Infinity);
2149
2105
  this.eventScope = { observer: call.observer, observedCall: call, observedClient: this };
2150
- this.sink = (_b = (_a = call.observer.config).createClientSink) == null ? void 0 : _b.call(_a, { clientId: settings.clientId, observedCall: call });
2106
+ this.sink = call.observer.config.createClientSink?.({ clientId: settings.clientId, observedCall: call });
2151
2107
  this.clientId = settings.clientId;
2152
2108
  this.appData = settings.appData ?? {};
2153
2109
  this.settings = {
2154
2110
  closeClientIfIdleForMs: settings.closeClientIfIdleForMs
2155
2111
  };
2156
- this.report = {
2157
- callId: this.call.callId,
2158
- clientId: this.clientId,
2159
- rttDistribution: {
2160
- gtOrEq300ms: 0,
2161
- lt50ms: 0,
2162
- lt150ms: 0,
2163
- lt300ms: 0,
2164
- count: 0,
2165
- sum: 0
2166
- },
2167
- scoreDistribution: {
2168
- "0": 0,
2169
- "1": 0,
2170
- "2": 0,
2171
- "3": 0,
2172
- "4": 0,
2173
- "5": 0,
2174
- count: 0,
2175
- sum: 0
2176
- },
2177
- issues: {},
2178
- totalAudioBytesReceived: 0,
2179
- totalVideoBytesReceived: 0,
2180
- totalAudioBytesSent: 0,
2181
- totalVideoBytesSent: 0,
2182
- totalDataChannelBytesReceived: 0,
2183
- totalDataChannelBytesSent: 0,
2184
- totalDataChannelMessagesReceived: 0,
2185
- totalDataChannelMessagesSent: 0,
2186
- totalInboundRtpBytesReceived: 0,
2187
- totalInboundRtpPacketsLost: 0,
2188
- totalInboundRtpPacketsReceived: 0,
2189
- totalOutboundRtpBytesSent: 0,
2190
- totalOutboundRtpPacketsSent: 0,
2191
- totalNumberOfIssues: 0
2192
- };
2193
2112
  if (this.sink) {
2194
2113
  const onError = (err) => logger2.warn("ClientSampleSink error for client %s: %o", this.clientId, err);
2195
- this.sink.once("close", () => {
2196
- var _a2;
2197
- return (_a2 = this.sink) == null ? void 0 : _a2.off("error", onError);
2198
- });
2114
+ this.sink.once("close", () => this.sink?.off("error", onError));
2199
2115
  this.sink.on("error", onError);
2200
2116
  }
2201
2117
  }
@@ -2263,7 +2179,6 @@ var ObservedClient = class extends EventEmitter2 {
2263
2179
  totalScoreSum = 0;
2264
2180
  numberOfScoreMeasurements = 0;
2265
2181
  // public totalNumberOfIssues = 0;
2266
- report;
2267
2182
  mediaDevices = [];
2268
2183
  issues = [];
2269
2184
  _injections = {};
@@ -2275,13 +2190,12 @@ var ObservedClient = class extends EventEmitter2 {
2275
2190
  return this.calculatedScore.value;
2276
2191
  }
2277
2192
  close() {
2278
- var _a, _b, _c, _d, _e;
2279
2193
  if (this.closed) return;
2280
2194
  this.closed = true;
2281
- (_a = this._injections.clientEvents) == null ? void 0 : _a.forEach((clientEvent) => this._processClientEvent(clientEvent));
2282
- (_b = this._injections.clientIssues) == null ? void 0 : _b.forEach((clientIssue) => this.addIssue(clientIssue));
2283
- (_c = this._injections.extensionStats) == null ? void 0 : _c.forEach((extensionStat) => this.addExtensionStats(extensionStat));
2284
- (_d = this._injections.clientMetaItems) == null ? void 0 : _d.forEach((clientMetaItem) => this.addMetadata(clientMetaItem));
2195
+ this._injections.clientEvents?.forEach((clientEvent) => this._processClientEvent(clientEvent));
2196
+ this._injections.clientIssues?.forEach((clientIssue) => this.addIssue(clientIssue));
2197
+ this._injections.extensionStats?.forEach((extensionStat) => this.addExtensionStats(extensionStat));
2198
+ this._injections.clientMetaItems?.forEach((clientMetaItem) => this.addMetadata(clientMetaItem));
2285
2199
  Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
2286
2200
  if (!this.leftAt) {
2287
2201
  this.leftAt = this.lastSampleTimestamp;
@@ -2294,18 +2208,17 @@ var ObservedClient = class extends EventEmitter2 {
2294
2208
  this.emit("close");
2295
2209
  this._notify("client-closed", { ...this.eventScope });
2296
2210
  try {
2297
- (_e = this.sink) == null ? void 0 : _e.end();
2211
+ this.sink?.end();
2298
2212
  } catch (err) {
2299
2213
  logger2.warn("ClientSampleSink.end failed for client %s: %o", this.clientId, err);
2300
2214
  }
2301
2215
  }
2302
2216
  accept(sample, context) {
2303
- var _a;
2304
2217
  if (this.closed) {
2305
2218
  logger2.warn("Attempted to accept a sample on a closed client %s", this.clientId);
2306
2219
  return;
2307
2220
  }
2308
- (_a = this.sink) == null ? void 0 : _a.write(sample);
2221
+ this.sink?.write(sample);
2309
2222
  if (this.closeTimer) {
2310
2223
  clearTimeout(this.closeTimer);
2311
2224
  this.closeTimer = void 0;
@@ -2398,19 +2311,13 @@ var ObservedClient = class extends EventEmitter2 {
2398
2311
  }
2399
2312
  if (observedPeerConnection.currentRttInMs < 50) {
2400
2313
  this.deltaRttLt50Measurements += 1;
2401
- this.report.rttDistribution.lt50ms += 1;
2402
2314
  } else if (observedPeerConnection.currentRttInMs < 150) {
2403
2315
  this.deltaRttLt150Measurements += 1;
2404
- this.report.rttDistribution.lt150ms += 1;
2405
2316
  } else if (observedPeerConnection.currentRttInMs < 300) {
2406
2317
  this.deltaRttLt300Measurements += 1;
2407
- this.report.rttDistribution.lt300ms += 1;
2408
2318
  } else if (300 <= observedPeerConnection.currentRttInMs) {
2409
2319
  this.deltaRttGtOrEq300Measurements += 1;
2410
- this.report.rttDistribution.gtOrEq300ms += 1;
2411
2320
  }
2412
- this.report.rttDistribution.count += 1;
2413
- this.report.rttDistribution.sum += observedPeerConnection.currentRttInMs;
2414
2321
  sumOfRtts += observedPeerConnection.currentRttInMs;
2415
2322
  ++numberOfRttMeasurements;
2416
2323
  }
@@ -2419,32 +2326,12 @@ var ObservedClient = class extends EventEmitter2 {
2419
2326
  this._processClientEvent(clientEvent);
2420
2327
  }
2421
2328
  this.attachments = sample.attachments;
2422
- this.report.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
2423
- this.report.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
2424
- this.report.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
2425
- this.report.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
2426
- this.report.totalInboundRtpPacketsLost += this.deltaInboundPacketsLost;
2427
- this.report.totalInboundRtpPacketsReceived += this.deltaInboundPacketsReceived;
2428
- this.report.totalOutboundRtpPacketsSent += this.deltaOutboundPacketsSent;
2429
- this.report.totalAudioBytesReceived += this.deltaReceivedAudioBytes;
2430
- this.report.totalVideoBytesReceived += this.deltaReceivedVideoBytes;
2431
- this.report.totalAudioBytesSent += this.deltaSentAudioBytes;
2432
- this.report.totalVideoBytesSent += this.deltaSentVideoBytes;
2433
- this.report.totalInboundRtpBytesReceived += this.deltaTransportReceivedBytes;
2434
- this.report.totalOutboundRtpBytesSent += this.deltaTransportSentBytes;
2435
- this.report.totalNumberOfIssues += this.deltaNumberOfIssues;
2436
2329
  this.receivingAudioBitrate = this.deltaReceivedAudioBytes * 8 / elapsedInSeconds;
2437
2330
  this.receivingVideoBitrate = this.deltaReceivedVideoBytes * 8 / elapsedInSeconds;
2438
2331
  this.sendingAudioBitrate = this.deltaSentAudioBytes * 8 / elapsedInSeconds;
2439
2332
  this.sendingVideoBitrate = this.deltaSentVideoBytes * 8 / elapsedInSeconds;
2440
2333
  this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : void 0;
2441
2334
  this.calculatedScore.value = sample.score;
2442
- if (sample.score !== void 0) {
2443
- const bucket = Math.floor(sample.score).toString();
2444
- this.report.scoreDistribution[bucket] = (this.report.scoreDistribution[bucket] ?? 0) + 1;
2445
- this.report.scoreDistribution.count += 1;
2446
- this.report.scoreDistribution.sum += sample.score;
2447
- }
2448
2335
  this.lastSampleTimestamp = sample.timestamp;
2449
2336
  const elapsedTimeInMs = now - this.updated;
2450
2337
  this.emit("update", sample, elapsedTimeInMs, context);
@@ -2509,7 +2396,6 @@ var ObservedClient = class extends EventEmitter2 {
2509
2396
  }
2510
2397
  addIssue(issue) {
2511
2398
  if (this.closed) return;
2512
- this.report.issues[issue.type] = (this.report.issues[issue.type] ?? 0) + 1;
2513
2399
  this._notify("client-issue", { ...this.eventScope, issue });
2514
2400
  }
2515
2401
  addExtensionStats(stats) {
@@ -2548,7 +2434,7 @@ var ObservedClient = class extends EventEmitter2 {
2548
2434
  }
2549
2435
  case "PEER_CONNECTION_OPENED" /* PEER_CONNECTION_OPENED */: {
2550
2436
  const payload = parseJsonAs(event.payload);
2551
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string") {
2437
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string") {
2552
2438
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2553
2439
  if (observedPeerConnection) {
2554
2440
  observedPeerConnection.openedAt = event.timestamp;
@@ -2562,7 +2448,7 @@ var ObservedClient = class extends EventEmitter2 {
2562
2448
  }
2563
2449
  case "PEER_CONNECTION_CLOSED" /* PEER_CONNECTION_CLOSED */: {
2564
2450
  const payload = parseJsonAs(event.payload);
2565
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string") {
2451
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string") {
2566
2452
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2567
2453
  if (observedPeerConnection) {
2568
2454
  observedPeerConnection.closedAt = event.timestamp;
@@ -2576,9 +2462,9 @@ var ObservedClient = class extends EventEmitter2 {
2576
2462
  }
2577
2463
  case "MEDIA_TRACK_ADDED" /* MEDIA_TRACK_ADDED */: {
2578
2464
  const payload = parseJsonAs(event.payload);
2579
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.trackId) && typeof payload.trackId === "string") {
2465
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2580
2466
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2581
- const observedTrack = (observedPeerConnection == null ? void 0 : observedPeerConnection.observedInboundTracks.get(payload.trackId)) ?? (observedPeerConnection == null ? void 0 : observedPeerConnection.observedOutboundTracks.get(payload.trackId));
2467
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2582
2468
  if (observedTrack) {
2583
2469
  observedTrack.addedAt = event.timestamp;
2584
2470
  } else if (postBuffer) {
@@ -2591,9 +2477,9 @@ var ObservedClient = class extends EventEmitter2 {
2591
2477
  }
2592
2478
  case "MEDIA_TRACK_REMOVED" /* MEDIA_TRACK_REMOVED */: {
2593
2479
  const payload = parseJsonAs(event.payload);
2594
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.trackId) && typeof payload.trackId === "string") {
2480
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2595
2481
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2596
- const observedTrack = (observedPeerConnection == null ? void 0 : observedPeerConnection.observedInboundTracks.get(payload.trackId)) ?? (observedPeerConnection == null ? void 0 : observedPeerConnection.observedOutboundTracks.get(payload.trackId));
2482
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2597
2483
  if (observedTrack) {
2598
2484
  observedTrack.removedAt = event.timestamp;
2599
2485
  } else if (postBuffer) {
@@ -2606,9 +2492,9 @@ var ObservedClient = class extends EventEmitter2 {
2606
2492
  }
2607
2493
  case "DATA_CHANNEL_OPEN" /* DATA_CHANNEL_OPEN */: {
2608
2494
  const payload = parseJsonAs(event.payload);
2609
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.dataChannelId) && typeof payload.dataChannelId === "string") {
2495
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.dataChannelId && typeof payload.dataChannelId === "string") {
2610
2496
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2611
- const observedDataChannel = observedPeerConnection == null ? void 0 : observedPeerConnection.observedDataChannels.get(payload.dataChannelId);
2497
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
2612
2498
  if (observedDataChannel) {
2613
2499
  observedDataChannel.addedAt = event.timestamp;
2614
2500
  } else if (postBuffer) {
@@ -2621,9 +2507,9 @@ var ObservedClient = class extends EventEmitter2 {
2621
2507
  }
2622
2508
  case "DATA_CHANNEL_CLOSED" /* DATA_CHANNEL_CLOSED */: {
2623
2509
  const payload = parseJsonAs(event.payload);
2624
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.dataChannelId) && typeof payload.dataChannelId === "string") {
2510
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.dataChannelId && typeof payload.dataChannelId === "string") {
2625
2511
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2626
- const observedDataChannel = observedPeerConnection == null ? void 0 : observedPeerConnection.observedDataChannels.get(payload.dataChannelId);
2512
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
2627
2513
  if (observedDataChannel) {
2628
2514
  observedDataChannel.removedAt = event.timestamp;
2629
2515
  } else if (postBuffer) {
@@ -2636,10 +2522,10 @@ var ObservedClient = class extends EventEmitter2 {
2636
2522
  }
2637
2523
  case "MEDIA_TRACK_MUTED" /* MEDIA_TRACK_MUTED */: {
2638
2524
  const payload = parseJsonAs(event.payload);
2639
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.trackId) && typeof payload.trackId === "string") {
2525
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2640
2526
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2641
- const observedInboundTrack = observedPeerConnection == null ? void 0 : observedPeerConnection.observedInboundTracks.get(payload.trackId);
2642
- const observedOutboundTrack = observedPeerConnection == null ? void 0 : observedPeerConnection.observedOutboundTracks.get(payload.trackId);
2527
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
2528
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2643
2529
  if (observedPeerConnection) {
2644
2530
  if (observedInboundTrack) {
2645
2531
  observedInboundTrack.muted = true;
@@ -2658,10 +2544,10 @@ var ObservedClient = class extends EventEmitter2 {
2658
2544
  }
2659
2545
  case "MEDIA_TRACK_UNMUTED" /* MEDIA_TRACK_UNMUTED */: {
2660
2546
  const payload = parseJsonAs(event.payload);
2661
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.trackId) && typeof payload.trackId === "string") {
2547
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.trackId && typeof payload.trackId === "string") {
2662
2548
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2663
- const observedInboundTrack = observedPeerConnection == null ? void 0 : observedPeerConnection.observedInboundTracks.get(payload.trackId);
2664
- const observedOutboundTrack = observedPeerConnection == null ? void 0 : observedPeerConnection.observedOutboundTracks.get(payload.trackId);
2549
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
2550
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
2665
2551
  if (observedPeerConnection) {
2666
2552
  if (observedInboundTrack) {
2667
2553
  observedInboundTrack.muted = false;
@@ -2680,7 +2566,7 @@ var ObservedClient = class extends EventEmitter2 {
2680
2566
  }
2681
2567
  case "ICE_CONNECTION_STATE_CHANGED" /* ICE_CONNECTION_STATE_CHANGED */: {
2682
2568
  const payload = parseJsonAs(event.payload);
2683
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.iceConnectionState) && typeof payload.iceConnectionState === "string") {
2569
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.iceConnectionState && typeof payload.iceConnectionState === "string") {
2684
2570
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2685
2571
  if (observedPeerConnection) {
2686
2572
  observedPeerConnection.iceConnectionState = payload.iceConnectionState;
@@ -2695,7 +2581,7 @@ var ObservedClient = class extends EventEmitter2 {
2695
2581
  }
2696
2582
  case "ICE_GATHERING_STATE_CHANGED" /* ICE_GATHERING_STATE_CHANGED */: {
2697
2583
  const payload = parseJsonAs(event.payload);
2698
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.iceGatheringState) && typeof payload.iceGatheringState === "string") {
2584
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.iceGatheringState && typeof payload.iceGatheringState === "string") {
2699
2585
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2700
2586
  if (observedPeerConnection) {
2701
2587
  observedPeerConnection.iceGatheringState = payload.iceGatheringState;
@@ -2710,7 +2596,7 @@ var ObservedClient = class extends EventEmitter2 {
2710
2596
  }
2711
2597
  case "PEER_CONNECTION_STATE_CHANGED" /* PEER_CONNECTION_STATE_CHANGED */: {
2712
2598
  const payload = parseJsonAs(event.payload);
2713
- if ((payload == null ? void 0 : payload.peerConnectionId) && typeof payload.peerConnectionId === "string" && (payload == null ? void 0 : payload.peerConnectionState) && typeof payload.peerConnectionState === "string") {
2599
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === "string" && payload?.peerConnectionState && typeof payload.peerConnectionState === "string") {
2714
2600
  const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
2715
2601
  if (observedPeerConnection) {
2716
2602
  observedPeerConnection.connectionState = payload.peerConnectionState;
@@ -2736,31 +2622,9 @@ var ObservedClient = class extends EventEmitter2 {
2736
2622
  ), void 0;
2737
2623
  }
2738
2624
  const newObservedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
2739
- const onInboundTrackRemoved = (track) => {
2740
- this._notify("client-track-report", {
2741
- ...this.eventScope,
2742
- report: {
2743
- direction: "inbound",
2744
- ...track.report
2745
- }
2746
- });
2747
- };
2748
- const onOutboundTrackRemoved = (track) => {
2749
- this._notify("client-track-report", {
2750
- ...this.eventScope,
2751
- report: {
2752
- direction: "outbound",
2753
- ...track.report
2754
- }
2755
- });
2756
- };
2757
2625
  newObservedPeerConnection.once("close", () => {
2758
- newObservedPeerConnection == null ? void 0 : newObservedPeerConnection.off("removed-inbound-track", onInboundTrackRemoved);
2759
- newObservedPeerConnection == null ? void 0 : newObservedPeerConnection.off("removed-outbound-track", onOutboundTrackRemoved);
2760
2626
  this.observedPeerConnections.delete(sample.peerConnectionId);
2761
2627
  });
2762
- newObservedPeerConnection.on("removed-inbound-track", onInboundTrackRemoved);
2763
- newObservedPeerConnection.on("removed-outbound-track", onOutboundTrackRemoved);
2764
2628
  this.observedPeerConnections.set(sample.peerConnectionId, newObservedPeerConnection);
2765
2629
  this._notify("peer-connection-added", { ...this.eventScope, observedPeerConnection: newObservedPeerConnection });
2766
2630
  observedPeerConnection = newObservedPeerConnection;
@@ -2867,21 +2731,6 @@ var OnAllClientCallUpdater = class {
2867
2731
  }
2868
2732
  };
2869
2733
 
2870
- // src/updaters/OnIntervalUpdater.ts
2871
- var OnIntervalUpdater = class {
2872
- constructor(intervalInMs, _update) {
2873
- this._update = _update;
2874
- this.timer = setInterval(() => this._update(), intervalInMs);
2875
- }
2876
- _update;
2877
- name = "OnIntervalUpdater";
2878
- description = "Call the update() method given in the constructor once the interval elapsed";
2879
- timer;
2880
- close() {
2881
- clearInterval(this.timer);
2882
- }
2883
- };
2884
-
2885
2734
  // src/updaters/OnAnyClientCallUpdater.ts
2886
2735
  var OnAnyClientCallUpdater = class {
2887
2736
  constructor(_observedCall) {
@@ -2934,7 +2783,7 @@ var Detectors = class {
2934
2783
  try {
2935
2784
  detector.update();
2936
2785
  } catch (err) {
2937
- logger3.warn(`Error updating detector ${detector == null ? void 0 : detector.name}`, err);
2786
+ logger3.warn(`Error updating detector ${detector?.name}`, err);
2938
2787
  }
2939
2788
  }
2940
2789
  }
@@ -2955,9 +2804,6 @@ var ObservedCall = class extends EventEmitter3 {
2955
2804
  this.appData = settings.appData ?? {};
2956
2805
  this.scoreCalculator = new DefaultCallScoreCalculator(this);
2957
2806
  this.detectors = new Detectors();
2958
- if (settings.updateIntervalInMs && settings.updatePolicy !== "update-on-interval") {
2959
- logger4.warn('updateIntervalInMs is ignored unless updatePolicy is "update-on-interval" (callId: %s)', settings.callId);
2960
- }
2961
2807
  switch (settings.updatePolicy) {
2962
2808
  case "update-on-any-client-updated":
2963
2809
  this.updater = new OnAnyClientCallUpdater(this);
@@ -2965,17 +2811,6 @@ var ObservedCall = class extends EventEmitter3 {
2965
2811
  case "update-when-all-client-updated":
2966
2812
  this.updater = new OnAllClientCallUpdater(this);
2967
2813
  break;
2968
- case "update-on-interval":
2969
- if (!settings.updateIntervalInMs) {
2970
- logger4.warn('updateIntervalInMs must be set when updatePolicy is "update-on-interval"; falling back to "update-when-all-client-updated" (callId: %s)', settings.callId);
2971
- this.updater = new OnAllClientCallUpdater(this);
2972
- } else {
2973
- this.updater = new OnIntervalUpdater(
2974
- settings.updateIntervalInMs,
2975
- this.update.bind(this)
2976
- );
2977
- }
2978
- break;
2979
2814
  }
2980
2815
  this.settings = {
2981
2816
  closeCallIfEmptyForMs: settings.closeCallIfEmptyForMs
@@ -3027,11 +2862,10 @@ var ObservedCall = class extends EventEmitter3 {
3027
2862
  this._notify("call-issue", { ...this.eventScope, issue });
3028
2863
  }
3029
2864
  close() {
3030
- var _a;
3031
2865
  if (this.closed) return;
3032
2866
  this.update();
3033
2867
  this.closed = true;
3034
- (_a = this.updater) == null ? void 0 : _a.close();
2868
+ this.updater?.close();
3035
2869
  let minSampleTimestamps;
3036
2870
  let maxSampleTimestamps;
3037
2871
  for (const client of this.observedClients.values()) {
@@ -3050,7 +2884,6 @@ var ObservedCall = class extends EventEmitter3 {
3050
2884
  return this.observedClients.get(clientId);
3051
2885
  }
3052
2886
  createObservedClient(settings) {
3053
- var _a, _b;
3054
2887
  if (this.closed) {
3055
2888
  logger4.warn("Attempted to create a client (clientId: %s) on a closed call %s", settings.clientId, this.callId);
3056
2889
  return void 0;
@@ -3063,7 +2896,7 @@ var ObservedCall = class extends EventEmitter3 {
3063
2896
  settings.closeClientIfIdleForMs = this.observer.config.closeClientIfIdleForMs;
3064
2897
  }
3065
2898
  if (settings.appData === void 0) {
3066
- settings.appData = (_b = (_a = this.observer.config).createClientAppData) == null ? void 0 : _b.call(_a, { clientId: settings.clientId, observedCall: this });
2899
+ settings.appData = this.observer.config.createClientAppData?.({ clientId: settings.clientId, observedCall: this });
3067
2900
  }
3068
2901
  const result = new ObservedClient(settings, this);
3069
2902
  const wasEmpty = this.observedClients.size === 0;
@@ -3241,16 +3074,12 @@ var ObservedTURN = class extends EventEmitter4 {
3241
3074
  this.numberOfClients = clientIds.size;
3242
3075
  }
3243
3076
  addPeerConnection(peerConnection) {
3244
- var _a;
3245
- const turnPairs = peerConnection.selectedIceCandidatePairs.filter((pair) => {
3246
- var _a2, _b, _c;
3247
- return ((_a2 = pair.getLocalCandidate()) == null ? void 0 : _a2.candidateType) === "relay" && ((_c = (_b = pair.getRemoteCandidate()) == null ? void 0 : _b.url) == null ? void 0 : _c.startsWith("turn:"));
3248
- });
3077
+ const turnPairs = peerConnection.selectedIceCandidatePairs.filter((pair) => pair.getLocalCandidate()?.candidateType === "relay" && pair.getRemoteCandidate()?.url?.startsWith("turn:"));
3249
3078
  if (turnPairs.length !== 1) {
3250
3079
  return logger5.warn(`Expected exactly one TURN pair, but found for peerconnection ${peerConnection.peerConnectionId}`, turnPairs.length), void 0;
3251
3080
  }
3252
3081
  const candidatePair = turnPairs[0];
3253
- const rawUrl = (_a = candidatePair.getRemoteCandidate()) == null ? void 0 : _a.url;
3082
+ const rawUrl = candidatePair.getRemoteCandidate()?.url;
3254
3083
  if (!rawUrl) {
3255
3084
  return logger5.warn(`No remote candidate URL found for peerconnection ${peerConnection.peerConnectionId}`), void 0;
3256
3085
  }
@@ -3343,122 +3172,60 @@ var OnAnyCallObserverUpdater = class {
3343
3172
  }
3344
3173
  };
3345
3174
 
3346
- // src/utils/MediasoupRemoteTrackResolver.ts
3347
- var MediasoupRemoteTrackResolver = class {
3348
- constructor(observedCall) {
3349
- this.observedCall = observedCall;
3350
- const observer = observedCall.observer;
3351
- const onInboundAdded = (p) => {
3352
- if (p.observedCall === this.observedCall) this._addInboundTrack(p.observedInboundTrack);
3353
- };
3354
- const onInboundRemoved = (p) => {
3355
- if (p.observedCall === this.observedCall) this._removeInboundTrack(p.observedInboundTrack);
3356
- };
3357
- const onOutboundAdded = (p) => {
3358
- if (p.observedCall === this.observedCall) this._addOutboundTrack(p.observedOutboundTrack);
3359
- };
3360
- const onOutboundRemoved = (p) => {
3361
- if (p.observedCall === this.observedCall) this._removeOutboundTrack(p.observedOutboundTrack);
3362
- };
3363
- observer.on("inbound-track-added", onInboundAdded);
3364
- observer.on("inbound-track-removed", onInboundRemoved);
3365
- observer.on("outbound-track-added", onOutboundAdded);
3366
- observer.on("outbound-track-removed", onOutboundRemoved);
3367
- observedCall.once("close", () => {
3368
- observer.off("inbound-track-added", onInboundAdded);
3369
- observer.off("inbound-track-removed", onInboundRemoved);
3370
- observer.off("outbound-track-added", onOutboundAdded);
3371
- observer.off("outbound-track-removed", onOutboundRemoved);
3372
- });
3373
- }
3374
- observedCall;
3375
- _consumerIdToProducerId = /* @__PURE__ */ new Map();
3376
- _producerIdToOutboundTrack = /* @__PURE__ */ new Map();
3377
- _consumerIdToInboundTrack = /* @__PURE__ */ new Map();
3378
- // private _producerIdToOutboundTrack = new Map<string, ObservedOutboundTrack>();
3379
- _inboundTrackToConsumerId = /* @__PURE__ */ new Map();
3380
- _producerIdToConsumerIds = /* @__PURE__ */ new Map();
3381
- _outboundTrackToProducerId = /* @__PURE__ */ new Map();
3382
- resolveRemoteOutboundTrack(inboundTrack) {
3383
- const consumerId = this._inboundTrackToConsumerId.get(inboundTrack.id);
3384
- if (!consumerId) return;
3385
- const producerId = this._consumerIdToProducerId.get(consumerId);
3386
- if (!producerId) return;
3387
- return this._producerIdToOutboundTrack.get(producerId);
3388
- }
3389
- resolveRemoteInboundTracks(outboundTrack) {
3390
- const producerId = this._outboundTrackToProducerId.get(outboundTrack.id);
3391
- if (!producerId) return;
3392
- const consumerIds = this._producerIdToConsumerIds.get(producerId);
3393
- if (!consumerIds) return;
3394
- return consumerIds.map((consumerId) => this._consumerIdToInboundTrack.get(consumerId)).filter((inboundTrack) => Boolean(inboundTrack));
3175
+ // src/common/Middleware.ts
3176
+ var Executor = class {
3177
+ constructor(stack, finalCallback) {
3178
+ this.stack = stack;
3179
+ this.finalCallback = finalCallback;
3180
+ }
3181
+ stack;
3182
+ finalCallback;
3183
+ done = false;
3184
+ index = 0;
3185
+ prevIndex = -1;
3186
+ // Executes the middleware stack
3187
+ execute(input) {
3188
+ if (this.index <= this.prevIndex) {
3189
+ throw new Error("Middleware must call next() only once!");
3190
+ } else if (this.done) {
3191
+ throw new Error("Middleware stack has already been executed!");
3192
+ }
3193
+ this.prevIndex = this.index;
3194
+ const middleware = this.stack[this.index];
3195
+ this.index++;
3196
+ if (middleware) {
3197
+ return middleware(input, (nextInput) => this.execute(nextInput));
3198
+ }
3199
+ this.done = true;
3200
+ this.finalCallback?.(input);
3395
3201
  }
3396
- _addInboundTrack(inboundTrack) {
3397
- const attachments = this._getInboundTrackAttachments(inboundTrack);
3398
- if (!attachments) return;
3399
- const {
3400
- producerId,
3401
- consumerId
3402
- } = attachments;
3403
- this._inboundTrackToConsumerId.set(inboundTrack.id, consumerId);
3404
- this._consumerIdToProducerId.set(consumerId, producerId);
3405
- this._consumerIdToInboundTrack.set(consumerId, inboundTrack);
3406
- let producerConsumers = this._producerIdToConsumerIds.get(producerId);
3407
- if (!producerConsumers) {
3408
- producerConsumers = [];
3409
- this._producerIdToConsumerIds.set(producerId, producerConsumers);
3410
- }
3411
- producerConsumers.push(consumerId);
3412
- }
3413
- _removeInboundTrack(inboundTrack) {
3414
- const consumerId = this._inboundTrackToConsumerId.get(inboundTrack.id);
3415
- if (!consumerId) return;
3416
- this._inboundTrackToConsumerId.delete(inboundTrack.id);
3417
- this._consumerIdToProducerId.delete(consumerId);
3418
- this._consumerIdToInboundTrack.delete(consumerId);
3419
- const producerConsumers = this._producerIdToConsumerIds.get(consumerId);
3420
- if (!producerConsumers) return;
3421
- const filteredProducerConsumers = producerConsumers.filter((id) => id !== consumerId);
3422
- if (filteredProducerConsumers.length === 0) {
3423
- this._producerIdToConsumerIds.delete(consumerId);
3424
- } else {
3425
- this._producerIdToConsumerIds.set(consumerId, filteredProducerConsumers);
3202
+ };
3203
+ var MiddlewareProcessor = class {
3204
+ stack = [];
3205
+ finalCallback;
3206
+ addMiddleware(...middlewares) {
3207
+ if (middlewares && middlewares.length > 0) {
3208
+ this.stack.push(...middlewares);
3209
+ }
3210
+ return this;
3211
+ }
3212
+ removeMiddleware(...middlewares) {
3213
+ if (middlewares && middlewares.length > 0) {
3214
+ for (const middleware of middlewares) {
3215
+ const index = this.stack.indexOf(middleware);
3216
+ if (index >= 0) {
3217
+ this.stack.splice(index, 1);
3218
+ }
3219
+ }
3426
3220
  }
3221
+ return this;
3427
3222
  }
3428
- _addOutboundTrack(outboundTrack) {
3429
- const attachments = this._getOutboundTrackAttachments(outboundTrack);
3430
- if (!attachments) return;
3431
- const {
3432
- producerId
3433
- } = attachments;
3434
- this._producerIdToOutboundTrack.set(producerId, outboundTrack);
3435
- this._outboundTrackToProducerId.set(outboundTrack.id, producerId);
3436
- }
3437
- _removeOutboundTrack(outboundTrack) {
3438
- const producerId = this._outboundTrackToProducerId.get(outboundTrack.id);
3439
- if (!producerId) return;
3440
- this._producerIdToOutboundTrack.delete(producerId);
3441
- this._outboundTrackToProducerId.delete(outboundTrack.id);
3442
- }
3443
- _getInboundTrackAttachments(inboundTrack) {
3444
- const {
3445
- producerId,
3446
- consumerId
3447
- } = inboundTrack.attachments ?? {};
3448
- if (!producerId || !consumerId || typeof producerId !== "string" || typeof consumerId !== "string") return;
3449
- return {
3450
- producerId,
3451
- consumerId
3452
- };
3453
- }
3454
- _getOutboundTrackAttachments(outboundTrack) {
3455
- const {
3456
- producerId
3457
- } = outboundTrack.attachments ?? {};
3458
- if (!producerId || typeof producerId !== "string") return;
3459
- return {
3460
- producerId
3461
- };
3223
+ process(value) {
3224
+ if (this.stack.length === 0) {
3225
+ return this.finalCallback?.(value);
3226
+ }
3227
+ const executor = new Executor(this.stack, this.finalCallback);
3228
+ executor.execute(value);
3462
3229
  }
3463
3230
  };
3464
3231
 
@@ -3473,7 +3240,7 @@ var Observer = class extends EventEmitter5 {
3473
3240
  this.config = config;
3474
3241
  this.setMaxListeners(Infinity);
3475
3242
  this.update = this.update.bind(this);
3476
- const currentUpdatePolicy = (config == null ? void 0 : config.updatePolicy) ?? "update-when-all-call-updated";
3243
+ const currentUpdatePolicy = config?.updatePolicy ?? "update-when-all-call-updated";
3477
3244
  switch (currentUpdatePolicy) {
3478
3245
  case "update-on-any-call-updated":
3479
3246
  this.updater = new OnAnyCallObserverUpdater(this);
@@ -3481,19 +3248,6 @@ var Observer = class extends EventEmitter5 {
3481
3248
  case "update-when-all-call-updated":
3482
3249
  this.updater = new OnAllCallObserverUpdater(this);
3483
3250
  break;
3484
- case "update-on-interval": {
3485
- const interval = config == null ? void 0 : config.updateIntervalInMs;
3486
- if (!interval) {
3487
- logger6.warn('updateIntervalInMs must be set when updatePolicy is "update-on-interval"; falling back to "update-when-all-call-updated"');
3488
- this.updater = new OnAllCallObserverUpdater(this);
3489
- } else {
3490
- this.updater = new OnIntervalUpdater(
3491
- interval,
3492
- this.update.bind(this)
3493
- );
3494
- }
3495
- break;
3496
- }
3497
3251
  }
3498
3252
  }
3499
3253
  config;
@@ -3511,7 +3265,8 @@ var Observer = class extends EventEmitter5 {
3511
3265
  numberOfOutboundRtpStreams = 0;
3512
3266
  numberOfDataChannels = 0;
3513
3267
  numberOfPeerConnections = 0;
3514
- _timer;
3268
+ /** Global, pre-dispatch middleware chain run on every accepted sample. */
3269
+ acceptMiddlewares = new MiddlewareProcessor();
3515
3270
  get numberOfCalls() {
3516
3271
  return this.observedCalls.size;
3517
3272
  }
@@ -3523,7 +3278,6 @@ var Observer = class extends EventEmitter5 {
3523
3278
  return this.observedCalls.get(callId);
3524
3279
  }
3525
3280
  createObservedCall(settings) {
3526
- var _a, _b;
3527
3281
  if (this.closed) {
3528
3282
  logger6.warn("Attempted to create a call (callId: %s) on a closed observer", settings.callId);
3529
3283
  return void 0;
@@ -3535,14 +3289,11 @@ var Observer = class extends EventEmitter5 {
3535
3289
  const callSettings = {
3536
3290
  ...settings,
3537
3291
  updatePolicy: settings.updatePolicy ?? this.config.defaultCallUpdatePolicy,
3538
- updateIntervalInMs: settings.updateIntervalInMs ?? this.config.defaultCallUpdateIntervalInMs,
3539
3292
  closeCallIfEmptyForMs: settings.closeCallIfEmptyForMs ?? this.config.closeCallIfEmptyForMs,
3540
- appData: settings.appData ?? ((_b = (_a = this.config).createCallAppData) == null ? void 0 : _b.call(_a, { callId: settings.callId, observer: this }))
3293
+ appData: settings.appData ?? this.config.createCallAppData?.({ callId: settings.callId, observer: this })
3541
3294
  };
3542
3295
  const observedCall = new ObservedCall(callSettings, this);
3543
- if (callSettings.remoteTrackResolvePolicy === "mediasoup-sfu") {
3544
- observedCall.remoteTrackResolver = new MediasoupRemoteTrackResolver(observedCall);
3545
- }
3296
+ observedCall.remoteTrackResolver = this.config.createTrackResolver?.(observedCall);
3546
3297
  observedCall.once("close", () => {
3547
3298
  this.observedCalls.delete(observedCall.callId);
3548
3299
  ++this.totalRemovedCall;
@@ -3560,16 +3311,17 @@ var Observer = class extends EventEmitter5 {
3560
3311
  return logger6.debug("Attempted to close twice");
3561
3312
  }
3562
3313
  this.closed = true;
3563
- clearInterval(this._timer);
3564
- this._timer = void 0;
3565
3314
  this.observedCalls.forEach((call) => call.close());
3566
3315
  this._notify("observer-closed", { ...this.eventScope });
3567
3316
  }
3568
3317
  accept(sample, context) {
3569
- var _a, _b, _c, _d;
3570
3318
  if (this.closed) {
3571
- this._notify("sample-rejected", { ...this.eventScope, reason: "observer-closed", sample });
3572
- return;
3319
+ return this._notify("sample-rejected", { ...this.eventScope, reason: "observer-closed", sample });
3320
+ }
3321
+ try {
3322
+ this.acceptMiddlewares.process({ sample, context });
3323
+ } catch (err) {
3324
+ logger6.warn("An accept middleware threw; dropping the sample. %o", err);
3573
3325
  }
3574
3326
  if (!sample.callId) {
3575
3327
  this._notify("sample-rejected", { ...this.eventScope, reason: "missing-callId", sample });
@@ -3583,7 +3335,7 @@ var Observer = class extends EventEmitter5 {
3583
3335
  if (!call) {
3584
3336
  call = this.createObservedCall({
3585
3337
  callId: sample.callId,
3586
- appData: (_b = (_a = this.config).createCallAppData) == null ? void 0 : _b.call(_a, { callId: sample.callId, observer: this })
3338
+ appData: this.config.createCallAppData?.({ callId: sample.callId, observer: this })
3587
3339
  });
3588
3340
  }
3589
3341
  if (!call) return;
@@ -3591,7 +3343,7 @@ var Observer = class extends EventEmitter5 {
3591
3343
  if (!client) {
3592
3344
  client = call.createObservedClient({
3593
3345
  clientId: sample.clientId,
3594
- appData: (_d = (_c = this.config).createClientAppData) == null ? void 0 : _d.call(_c, { clientId: sample.clientId, observedCall: call })
3346
+ appData: this.config.createClientAppData?.({ clientId: sample.clientId, observedCall: call })
3595
3347
  });
3596
3348
  }
3597
3349
  if (!client) return;
@@ -3633,11 +3385,14 @@ var ClientSampleSink = class extends EventEmitter6 {
3633
3385
  import * as fs from "fs";
3634
3386
  import * as path from "path";
3635
3387
  var JsonlFileSink = class extends ClientSampleSink {
3388
+ /** The file this sink writes to. Read it (e.g. in a `close` handler) to upload/move the file. */
3389
+ path;
3636
3390
  _stream;
3637
3391
  _serializeSample;
3638
3392
  constructor(options) {
3639
3393
  super();
3640
- this._stream = fs.createWriteStream(options.path, { flags: "a" });
3394
+ this.path = options.path;
3395
+ this._stream = fs.createWriteStream(this.path, { flags: "a" });
3641
3396
  this._stream.on("close", () => this.emit("close"));
3642
3397
  this._stream.on("finish", () => this.emit("finish"));
3643
3398
  this._stream.on("drain", () => this.emit("drain"));
@@ -3657,8 +3412,7 @@ function createJsonlFileSink(options) {
3657
3412
  }
3658
3413
  function createJsonlFileSinkFactory(options) {
3659
3414
  return ({ clientId, observedCall }) => {
3660
- var _a;
3661
- const filename = ((_a = options.getFileName) == null ? void 0 : _a.call(options, { callId: observedCall.callId, clientId })) ?? `${observedCall.callId}__${clientId}.jsonl`;
3415
+ const filename = options.getFileName?.({ callId: observedCall.callId, clientId }) ?? `${observedCall.callId}__${clientId}.jsonl`;
3662
3416
  return createJsonlFileSink({
3663
3417
  path: path.join(options.directory, filename),
3664
3418
  serializeSample: options.serializeSample
@@ -3684,6 +3438,126 @@ var InMemorySink = class extends ClientSampleSink {
3684
3438
  function createInMemorySink(samples) {
3685
3439
  return new InMemorySink(samples);
3686
3440
  }
3441
+
3442
+ // src/utils/RemoteTrackResolver.ts
3443
+ var RemoteTrackResolver = class {
3444
+ constructor(observedCall, resolvers) {
3445
+ this.observedCall = observedCall;
3446
+ this.resolvers = resolvers;
3447
+ const observer = observedCall.observer;
3448
+ const onInboundAdded = (p) => {
3449
+ if (p.observedCall === this.observedCall) this._addInboundTrack(p.observedInboundTrack);
3450
+ };
3451
+ const onInboundRemoved = (p) => {
3452
+ if (p.observedCall === this.observedCall) this._removeInboundTrack(p.observedInboundTrack);
3453
+ };
3454
+ const onOutboundAdded = (p) => {
3455
+ if (p.observedCall === this.observedCall) this._addOutboundTrack(p.observedOutboundTrack);
3456
+ };
3457
+ const onOutboundRemoved = (p) => {
3458
+ if (p.observedCall === this.observedCall) this._removeOutboundTrack(p.observedOutboundTrack);
3459
+ };
3460
+ observedCall.once("close", () => {
3461
+ observer.off("inbound-track-added", onInboundAdded);
3462
+ observer.off("inbound-track-removed", onInboundRemoved);
3463
+ observer.off("outbound-track-added", onOutboundAdded);
3464
+ observer.off("outbound-track-removed", onOutboundRemoved);
3465
+ });
3466
+ observer.on("inbound-track-added", onInboundAdded);
3467
+ observer.on("inbound-track-removed", onInboundRemoved);
3468
+ observer.on("outbound-track-added", onOutboundAdded);
3469
+ observer.on("outbound-track-removed", onOutboundRemoved);
3470
+ }
3471
+ observedCall;
3472
+ resolvers;
3473
+ _publisherIdToOutboundTrack = /* @__PURE__ */ new Map();
3474
+ _subscriberIdToInboundTrack = /* @__PURE__ */ new Map();
3475
+ /** The published (outbound) track for a publisher id, if any. */
3476
+ getOutboundTrackByPublisherId(publisherId) {
3477
+ return this._publisherIdToOutboundTrack.get(publisherId);
3478
+ }
3479
+ /** The subscribed (inbound) track for a subscriber id, if the strategy resolves subscriber ids. */
3480
+ getInboundTrackBySubscriberId(subscriberId) {
3481
+ return this._subscriberIdToInboundTrack.get(subscriberId);
3482
+ }
3483
+ // RemoteTrackResolver interface — thin readers over the links maintained on the tracks.
3484
+ resolveRemoteOutboundTrack(inboundTrack) {
3485
+ return inboundTrack.remoteOutboundTrack;
3486
+ }
3487
+ resolveRemoteInboundTracks(outboundTrack) {
3488
+ return [...outboundTrack.remoteInboundTracks];
3489
+ }
3490
+ _addInboundTrack(inboundTrack) {
3491
+ const publisherId = this.resolvers.resolveInboundTrackPublisherId(inboundTrack);
3492
+ if (!publisherId) return;
3493
+ const subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);
3494
+ if (subscriberId) {
3495
+ this._subscriberIdToInboundTrack.set(subscriberId, inboundTrack);
3496
+ }
3497
+ const outboundTrack = this._publisherIdToOutboundTrack.get(publisherId);
3498
+ if (!outboundTrack) return;
3499
+ outboundTrack.remoteInboundTracks.add(inboundTrack);
3500
+ inboundTrack.remoteOutboundTrack = outboundTrack;
3501
+ }
3502
+ _removeInboundTrack(inboundTrack) {
3503
+ inboundTrack.remoteOutboundTrack?.remoteInboundTracks.delete(inboundTrack);
3504
+ inboundTrack.remoteOutboundTrack = void 0;
3505
+ const subscriberId = this.resolvers.resolveInboundTrackSubscriberId?.(inboundTrack);
3506
+ if (subscriberId) {
3507
+ this._subscriberIdToInboundTrack.delete(subscriberId);
3508
+ }
3509
+ }
3510
+ _addOutboundTrack(outboundTrack) {
3511
+ const publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);
3512
+ if (!publisherId) return;
3513
+ this._publisherIdToOutboundTrack.set(publisherId, outboundTrack);
3514
+ for (const observedClient of this.observedCall.observedClients.values()) {
3515
+ for (const observedPeerConnection of observedClient.observedPeerConnections.values()) {
3516
+ for (const inboundTrack of observedPeerConnection.observedInboundTracks.values()) {
3517
+ if (this.resolvers.resolveInboundTrackPublisherId(inboundTrack) !== publisherId) continue;
3518
+ outboundTrack.remoteInboundTracks.add(inboundTrack);
3519
+ inboundTrack.remoteOutboundTrack = outboundTrack;
3520
+ }
3521
+ }
3522
+ }
3523
+ }
3524
+ _removeOutboundTrack(outboundTrack) {
3525
+ const publisherId = this.resolvers.resolveOutboundTrackPublisherId(outboundTrack);
3526
+ if (publisherId && this._publisherIdToOutboundTrack.get(publisherId) === outboundTrack) {
3527
+ this._publisherIdToOutboundTrack.delete(publisherId);
3528
+ }
3529
+ for (const inboundTrack of outboundTrack.remoteInboundTracks) {
3530
+ inboundTrack.remoteOutboundTrack = void 0;
3531
+ }
3532
+ outboundTrack.remoteInboundTracks.clear();
3533
+ }
3534
+ };
3535
+
3536
+ // src/utils/RemoteTrackResolverFactories.ts
3537
+ function createDefaultMediasoupRemoteTrackResolverFactory() {
3538
+ return (observedCall) => new RemoteTrackResolver(observedCall, {
3539
+ resolveInboundTrackPublisherId: (inboundTrack) => inboundTrack.attachments?.producerId,
3540
+ resolveInboundTrackSubscriberId: (inboundTrack) => inboundTrack.attachments?.consumerId,
3541
+ resolveOutboundTrackPublisherId: (outboundTrack) => outboundTrack.attachments?.producerId
3542
+ });
3543
+ }
3544
+ function createP2pRemoteTrackResolverFactory() {
3545
+ return (observedCall) => new RemoteTrackResolver(observedCall, {
3546
+ resolveInboundTrackPublisherId: (inboundTrack) => {
3547
+ const ssrc = inboundTrack.getInboundRtp()?.ssrc;
3548
+ return ssrc ? `${ssrc}` : void 0;
3549
+ },
3550
+ resolveInboundTrackSubscriberId: (inboundTrack) => {
3551
+ const ssrc = inboundTrack.getInboundRtp()?.ssrc;
3552
+ return ssrc ? `${ssrc}` : void 0;
3553
+ },
3554
+ resolveOutboundTrackPublisherId: (outboundTrack) => {
3555
+ const rtps = outboundTrack.getOutboundRtps();
3556
+ if (!rtps || rtps.length === 0) return void 0;
3557
+ return rtps.map((rtp) => rtp.ssrc).join(",");
3558
+ }
3559
+ });
3560
+ }
3687
3561
  export {
3688
3562
  ClientEventTypes,
3689
3563
  ClientMetaTypes,
@@ -3710,10 +3584,13 @@ export {
3710
3584
  ObservedRemoteInboundRtp,
3711
3585
  ObservedRemoteOutboundRtp,
3712
3586
  Observer,
3587
+ RemoteTrackResolver,
3588
+ createDefaultMediasoupRemoteTrackResolverFactory,
3713
3589
  createInMemorySink,
3714
3590
  createJsonlFileSink,
3715
3591
  createJsonlFileSinkFactory,
3716
3592
  createLogger,
3593
+ createP2pRemoteTrackResolverFactory,
3717
3594
  setObserverLogger
3718
3595
  };
3719
3596
  //# sourceMappingURL=index.mjs.map