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

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
@@ -1063,20 +1063,6 @@ var ObservedInboundTrack = class {
1063
1063
  this._peerConnection = _peerConnection;
1064
1064
  this._inboundRtp = _inboundRtp;
1065
1065
  this._mediaPlayout = _mediaPlayout;
1066
- this.report = {
1067
- trackId: this.id,
1068
- kind: this.kind,
1069
- fractionLostDistribution: {
1070
- gtOrEq050: 0,
1071
- lt001: 0,
1072
- lt005: 0,
1073
- lt010: 0,
1074
- lt020: 0,
1075
- lt050: 0,
1076
- count: 0,
1077
- sum: 0
1078
- }
1079
- };
1080
1066
  }
1081
1067
  timestamp;
1082
1068
  id;
@@ -1089,7 +1075,7 @@ var ObservedInboundTrack = class {
1089
1075
  value: void 0
1090
1076
  };
1091
1077
  appData;
1092
- report;
1078
+ remoteOutboundTrack;
1093
1079
  _visited = false;
1094
1080
  addedAt;
1095
1081
  removedAt;
@@ -1112,25 +1098,11 @@ var ObservedInboundTrack = class {
1112
1098
  getMediaPlayout() {
1113
1099
  return this._mediaPlayout;
1114
1100
  }
1115
- getRemoteOutboundTrack() {
1116
- return this._peerConnection.client.call.remoteTrackResolver?.resolveRemoteOutboundTrack(this);
1117
- }
1118
1101
  update(stats) {
1119
1102
  this._visited = true;
1120
1103
  this.timestamp = stats.timestamp;
1121
1104
  this.calculatedScore.value = stats.score;
1122
1105
  this.attachments = stats.attachments;
1123
- const fl = this._inboundRtp?.fractionLost;
1124
- if (fl !== void 0) {
1125
- if (fl < 0.01) this.report.fractionLostDistribution.lt001 += 1;
1126
- else if (fl < 0.05) this.report.fractionLostDistribution.lt005 += 1;
1127
- else if (fl < 0.1) this.report.fractionLostDistribution.lt010 += 1;
1128
- else if (fl < 0.2) this.report.fractionLostDistribution.lt020 += 1;
1129
- else if (fl < 0.5) this.report.fractionLostDistribution.lt050 += 1;
1130
- else this.report.fractionLostDistribution.gtOrEq050 += 1;
1131
- this.report.fractionLostDistribution.count += 1;
1132
- this.report.fractionLostDistribution.sum += fl;
1133
- }
1134
1106
  }
1135
1107
  };
1136
1108
 
@@ -1143,10 +1115,6 @@ var ObservedOutboundTrack = class {
1143
1115
  this._peerConnection = _peerConnection;
1144
1116
  this._outboundRtps = _outboundRtps;
1145
1117
  this._mediaSource = _mediaSource;
1146
- this.report = {
1147
- trackId: this.id,
1148
- kind: this.kind
1149
- };
1150
1118
  }
1151
1119
  timestamp;
1152
1120
  id;
@@ -1156,7 +1124,7 @@ var ObservedOutboundTrack = class {
1156
1124
  _mediaSource;
1157
1125
  _visited = false;
1158
1126
  appData;
1159
- report;
1127
+ remoteInboundTracks = /* @__PURE__ */ new Set();
1160
1128
  calculatedScore = {
1161
1129
  weight: 1,
1162
1130
  value: void 0
@@ -1182,9 +1150,6 @@ var ObservedOutboundTrack = class {
1182
1150
  getMediaSource() {
1183
1151
  return this._mediaSource;
1184
1152
  }
1185
- getRemoteInboundTracks() {
1186
- return this._peerConnection.client.call.remoteTrackResolver?.resolveRemoteInboundTracks(this);
1187
- }
1188
1153
  update(stats) {
1189
1154
  this._visited = true;
1190
1155
  this.timestamp = stats.timestamp;
@@ -2144,43 +2109,6 @@ var ObservedClient = class extends EventEmitter2 {
2144
2109
  this.settings = {
2145
2110
  closeClientIfIdleForMs: settings.closeClientIfIdleForMs
2146
2111
  };
2147
- this.report = {
2148
- callId: this.call.callId,
2149
- clientId: this.clientId,
2150
- rttDistribution: {
2151
- gtOrEq300ms: 0,
2152
- lt50ms: 0,
2153
- lt150ms: 0,
2154
- lt300ms: 0,
2155
- count: 0,
2156
- sum: 0
2157
- },
2158
- scoreDistribution: {
2159
- "0": 0,
2160
- "1": 0,
2161
- "2": 0,
2162
- "3": 0,
2163
- "4": 0,
2164
- "5": 0,
2165
- count: 0,
2166
- sum: 0
2167
- },
2168
- issues: {},
2169
- totalAudioBytesReceived: 0,
2170
- totalVideoBytesReceived: 0,
2171
- totalAudioBytesSent: 0,
2172
- totalVideoBytesSent: 0,
2173
- totalDataChannelBytesReceived: 0,
2174
- totalDataChannelBytesSent: 0,
2175
- totalDataChannelMessagesReceived: 0,
2176
- totalDataChannelMessagesSent: 0,
2177
- totalInboundRtpBytesReceived: 0,
2178
- totalInboundRtpPacketsLost: 0,
2179
- totalInboundRtpPacketsReceived: 0,
2180
- totalOutboundRtpBytesSent: 0,
2181
- totalOutboundRtpPacketsSent: 0,
2182
- totalNumberOfIssues: 0
2183
- };
2184
2112
  if (this.sink) {
2185
2113
  const onError = (err) => logger2.warn("ClientSampleSink error for client %s: %o", this.clientId, err);
2186
2114
  this.sink.once("close", () => this.sink?.off("error", onError));
@@ -2251,7 +2179,6 @@ var ObservedClient = class extends EventEmitter2 {
2251
2179
  totalScoreSum = 0;
2252
2180
  numberOfScoreMeasurements = 0;
2253
2181
  // public totalNumberOfIssues = 0;
2254
- report;
2255
2182
  mediaDevices = [];
2256
2183
  issues = [];
2257
2184
  _injections = {};
@@ -2384,19 +2311,13 @@ var ObservedClient = class extends EventEmitter2 {
2384
2311
  }
2385
2312
  if (observedPeerConnection.currentRttInMs < 50) {
2386
2313
  this.deltaRttLt50Measurements += 1;
2387
- this.report.rttDistribution.lt50ms += 1;
2388
2314
  } else if (observedPeerConnection.currentRttInMs < 150) {
2389
2315
  this.deltaRttLt150Measurements += 1;
2390
- this.report.rttDistribution.lt150ms += 1;
2391
2316
  } else if (observedPeerConnection.currentRttInMs < 300) {
2392
2317
  this.deltaRttLt300Measurements += 1;
2393
- this.report.rttDistribution.lt300ms += 1;
2394
2318
  } else if (300 <= observedPeerConnection.currentRttInMs) {
2395
2319
  this.deltaRttGtOrEq300Measurements += 1;
2396
- this.report.rttDistribution.gtOrEq300ms += 1;
2397
2320
  }
2398
- this.report.rttDistribution.count += 1;
2399
- this.report.rttDistribution.sum += observedPeerConnection.currentRttInMs;
2400
2321
  sumOfRtts += observedPeerConnection.currentRttInMs;
2401
2322
  ++numberOfRttMeasurements;
2402
2323
  }
@@ -2405,32 +2326,12 @@ var ObservedClient = class extends EventEmitter2 {
2405
2326
  this._processClientEvent(clientEvent);
2406
2327
  }
2407
2328
  this.attachments = sample.attachments;
2408
- this.report.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
2409
- this.report.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
2410
- this.report.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
2411
- this.report.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
2412
- this.report.totalInboundRtpPacketsLost += this.deltaInboundPacketsLost;
2413
- this.report.totalInboundRtpPacketsReceived += this.deltaInboundPacketsReceived;
2414
- this.report.totalOutboundRtpPacketsSent += this.deltaOutboundPacketsSent;
2415
- this.report.totalAudioBytesReceived += this.deltaReceivedAudioBytes;
2416
- this.report.totalVideoBytesReceived += this.deltaReceivedVideoBytes;
2417
- this.report.totalAudioBytesSent += this.deltaSentAudioBytes;
2418
- this.report.totalVideoBytesSent += this.deltaSentVideoBytes;
2419
- this.report.totalInboundRtpBytesReceived += this.deltaTransportReceivedBytes;
2420
- this.report.totalOutboundRtpBytesSent += this.deltaTransportSentBytes;
2421
- this.report.totalNumberOfIssues += this.deltaNumberOfIssues;
2422
2329
  this.receivingAudioBitrate = this.deltaReceivedAudioBytes * 8 / elapsedInSeconds;
2423
2330
  this.receivingVideoBitrate = this.deltaReceivedVideoBytes * 8 / elapsedInSeconds;
2424
2331
  this.sendingAudioBitrate = this.deltaSentAudioBytes * 8 / elapsedInSeconds;
2425
2332
  this.sendingVideoBitrate = this.deltaSentVideoBytes * 8 / elapsedInSeconds;
2426
2333
  this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : void 0;
2427
2334
  this.calculatedScore.value = sample.score;
2428
- if (sample.score !== void 0) {
2429
- const bucket = Math.floor(sample.score).toString();
2430
- this.report.scoreDistribution[bucket] = (this.report.scoreDistribution[bucket] ?? 0) + 1;
2431
- this.report.scoreDistribution.count += 1;
2432
- this.report.scoreDistribution.sum += sample.score;
2433
- }
2434
2335
  this.lastSampleTimestamp = sample.timestamp;
2435
2336
  const elapsedTimeInMs = now - this.updated;
2436
2337
  this.emit("update", sample, elapsedTimeInMs, context);
@@ -2495,7 +2396,6 @@ var ObservedClient = class extends EventEmitter2 {
2495
2396
  }
2496
2397
  addIssue(issue) {
2497
2398
  if (this.closed) return;
2498
- this.report.issues[issue.type] = (this.report.issues[issue.type] ?? 0) + 1;
2499
2399
  this._notify("client-issue", { ...this.eventScope, issue });
2500
2400
  }
2501
2401
  addExtensionStats(stats) {
@@ -2722,31 +2622,9 @@ var ObservedClient = class extends EventEmitter2 {
2722
2622
  ), void 0;
2723
2623
  }
2724
2624
  const newObservedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
2725
- const onInboundTrackRemoved = (track) => {
2726
- this._notify("client-track-report", {
2727
- ...this.eventScope,
2728
- report: {
2729
- direction: "inbound",
2730
- ...track.report
2731
- }
2732
- });
2733
- };
2734
- const onOutboundTrackRemoved = (track) => {
2735
- this._notify("client-track-report", {
2736
- ...this.eventScope,
2737
- report: {
2738
- direction: "outbound",
2739
- ...track.report
2740
- }
2741
- });
2742
- };
2743
2625
  newObservedPeerConnection.once("close", () => {
2744
- newObservedPeerConnection?.off("removed-inbound-track", onInboundTrackRemoved);
2745
- newObservedPeerConnection?.off("removed-outbound-track", onOutboundTrackRemoved);
2746
2626
  this.observedPeerConnections.delete(sample.peerConnectionId);
2747
2627
  });
2748
- newObservedPeerConnection.on("removed-inbound-track", onInboundTrackRemoved);
2749
- newObservedPeerConnection.on("removed-outbound-track", onOutboundTrackRemoved);
2750
2628
  this.observedPeerConnections.set(sample.peerConnectionId, newObservedPeerConnection);
2751
2629
  this._notify("peer-connection-added", { ...this.eventScope, observedPeerConnection: newObservedPeerConnection });
2752
2630
  observedPeerConnection = newObservedPeerConnection;
@@ -2853,21 +2731,6 @@ var OnAllClientCallUpdater = class {
2853
2731
  }
2854
2732
  };
2855
2733
 
2856
- // src/updaters/OnIntervalUpdater.ts
2857
- var OnIntervalUpdater = class {
2858
- constructor(intervalInMs, _update) {
2859
- this._update = _update;
2860
- this.timer = setInterval(() => this._update(), intervalInMs);
2861
- }
2862
- _update;
2863
- name = "OnIntervalUpdater";
2864
- description = "Call the update() method given in the constructor once the interval elapsed";
2865
- timer;
2866
- close() {
2867
- clearInterval(this.timer);
2868
- }
2869
- };
2870
-
2871
2734
  // src/updaters/OnAnyClientCallUpdater.ts
2872
2735
  var OnAnyClientCallUpdater = class {
2873
2736
  constructor(_observedCall) {
@@ -2941,9 +2804,6 @@ var ObservedCall = class extends EventEmitter3 {
2941
2804
  this.appData = settings.appData ?? {};
2942
2805
  this.scoreCalculator = new DefaultCallScoreCalculator(this);
2943
2806
  this.detectors = new Detectors();
2944
- if (settings.updateIntervalInMs && settings.updatePolicy !== "update-on-interval") {
2945
- logger4.warn('updateIntervalInMs is ignored unless updatePolicy is "update-on-interval" (callId: %s)', settings.callId);
2946
- }
2947
2807
  switch (settings.updatePolicy) {
2948
2808
  case "update-on-any-client-updated":
2949
2809
  this.updater = new OnAnyClientCallUpdater(this);
@@ -2951,17 +2811,6 @@ var ObservedCall = class extends EventEmitter3 {
2951
2811
  case "update-when-all-client-updated":
2952
2812
  this.updater = new OnAllClientCallUpdater(this);
2953
2813
  break;
2954
- case "update-on-interval":
2955
- if (!settings.updateIntervalInMs) {
2956
- logger4.warn('updateIntervalInMs must be set when updatePolicy is "update-on-interval"; falling back to "update-when-all-client-updated" (callId: %s)', settings.callId);
2957
- this.updater = new OnAllClientCallUpdater(this);
2958
- } else {
2959
- this.updater = new OnIntervalUpdater(
2960
- settings.updateIntervalInMs,
2961
- this.update.bind(this)
2962
- );
2963
- }
2964
- break;
2965
2814
  }
2966
2815
  this.settings = {
2967
2816
  closeCallIfEmptyForMs: settings.closeCallIfEmptyForMs
@@ -3323,122 +3172,60 @@ var OnAnyCallObserverUpdater = class {
3323
3172
  }
3324
3173
  };
3325
3174
 
3326
- // src/utils/MediasoupRemoteTrackResolver.ts
3327
- var MediasoupRemoteTrackResolver = class {
3328
- constructor(observedCall) {
3329
- this.observedCall = observedCall;
3330
- const observer = observedCall.observer;
3331
- const onInboundAdded = (p) => {
3332
- if (p.observedCall === this.observedCall) this._addInboundTrack(p.observedInboundTrack);
3333
- };
3334
- const onInboundRemoved = (p) => {
3335
- if (p.observedCall === this.observedCall) this._removeInboundTrack(p.observedInboundTrack);
3336
- };
3337
- const onOutboundAdded = (p) => {
3338
- if (p.observedCall === this.observedCall) this._addOutboundTrack(p.observedOutboundTrack);
3339
- };
3340
- const onOutboundRemoved = (p) => {
3341
- if (p.observedCall === this.observedCall) this._removeOutboundTrack(p.observedOutboundTrack);
3342
- };
3343
- observer.on("inbound-track-added", onInboundAdded);
3344
- observer.on("inbound-track-removed", onInboundRemoved);
3345
- observer.on("outbound-track-added", onOutboundAdded);
3346
- observer.on("outbound-track-removed", onOutboundRemoved);
3347
- observedCall.once("close", () => {
3348
- observer.off("inbound-track-added", onInboundAdded);
3349
- observer.off("inbound-track-removed", onInboundRemoved);
3350
- observer.off("outbound-track-added", onOutboundAdded);
3351
- observer.off("outbound-track-removed", onOutboundRemoved);
3352
- });
3353
- }
3354
- observedCall;
3355
- _consumerIdToProducerId = /* @__PURE__ */ new Map();
3356
- _producerIdToOutboundTrack = /* @__PURE__ */ new Map();
3357
- _consumerIdToInboundTrack = /* @__PURE__ */ new Map();
3358
- // private _producerIdToOutboundTrack = new Map<string, ObservedOutboundTrack>();
3359
- _inboundTrackToConsumerId = /* @__PURE__ */ new Map();
3360
- _producerIdToConsumerIds = /* @__PURE__ */ new Map();
3361
- _outboundTrackToProducerId = /* @__PURE__ */ new Map();
3362
- resolveRemoteOutboundTrack(inboundTrack) {
3363
- const consumerId = this._inboundTrackToConsumerId.get(inboundTrack.id);
3364
- if (!consumerId) return;
3365
- const producerId = this._consumerIdToProducerId.get(consumerId);
3366
- if (!producerId) return;
3367
- return this._producerIdToOutboundTrack.get(producerId);
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);
3368
3201
  }
3369
- resolveRemoteInboundTracks(outboundTrack) {
3370
- const producerId = this._outboundTrackToProducerId.get(outboundTrack.id);
3371
- if (!producerId) return;
3372
- const consumerIds = this._producerIdToConsumerIds.get(producerId);
3373
- if (!consumerIds) return;
3374
- return consumerIds.map((consumerId) => this._consumerIdToInboundTrack.get(consumerId)).filter((inboundTrack) => Boolean(inboundTrack));
3375
- }
3376
- _addInboundTrack(inboundTrack) {
3377
- const attachments = this._getInboundTrackAttachments(inboundTrack);
3378
- if (!attachments) return;
3379
- const {
3380
- producerId,
3381
- consumerId
3382
- } = attachments;
3383
- this._inboundTrackToConsumerId.set(inboundTrack.id, consumerId);
3384
- this._consumerIdToProducerId.set(consumerId, producerId);
3385
- this._consumerIdToInboundTrack.set(consumerId, inboundTrack);
3386
- let producerConsumers = this._producerIdToConsumerIds.get(producerId);
3387
- if (!producerConsumers) {
3388
- producerConsumers = [];
3389
- this._producerIdToConsumerIds.set(producerId, producerConsumers);
3390
- }
3391
- producerConsumers.push(consumerId);
3392
- }
3393
- _removeInboundTrack(inboundTrack) {
3394
- const consumerId = this._inboundTrackToConsumerId.get(inboundTrack.id);
3395
- if (!consumerId) return;
3396
- this._inboundTrackToConsumerId.delete(inboundTrack.id);
3397
- this._consumerIdToProducerId.delete(consumerId);
3398
- this._consumerIdToInboundTrack.delete(consumerId);
3399
- const producerConsumers = this._producerIdToConsumerIds.get(consumerId);
3400
- if (!producerConsumers) return;
3401
- const filteredProducerConsumers = producerConsumers.filter((id) => id !== consumerId);
3402
- if (filteredProducerConsumers.length === 0) {
3403
- this._producerIdToConsumerIds.delete(consumerId);
3404
- } else {
3405
- 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
+ }
3406
3220
  }
3221
+ return this;
3407
3222
  }
3408
- _addOutboundTrack(outboundTrack) {
3409
- const attachments = this._getOutboundTrackAttachments(outboundTrack);
3410
- if (!attachments) return;
3411
- const {
3412
- producerId
3413
- } = attachments;
3414
- this._producerIdToOutboundTrack.set(producerId, outboundTrack);
3415
- this._outboundTrackToProducerId.set(outboundTrack.id, producerId);
3416
- }
3417
- _removeOutboundTrack(outboundTrack) {
3418
- const producerId = this._outboundTrackToProducerId.get(outboundTrack.id);
3419
- if (!producerId) return;
3420
- this._producerIdToOutboundTrack.delete(producerId);
3421
- this._outboundTrackToProducerId.delete(outboundTrack.id);
3422
- }
3423
- _getInboundTrackAttachments(inboundTrack) {
3424
- const {
3425
- producerId,
3426
- consumerId
3427
- } = inboundTrack.attachments ?? {};
3428
- if (!producerId || !consumerId || typeof producerId !== "string" || typeof consumerId !== "string") return;
3429
- return {
3430
- producerId,
3431
- consumerId
3432
- };
3433
- }
3434
- _getOutboundTrackAttachments(outboundTrack) {
3435
- const {
3436
- producerId
3437
- } = outboundTrack.attachments ?? {};
3438
- if (!producerId || typeof producerId !== "string") return;
3439
- return {
3440
- producerId
3441
- };
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);
3442
3229
  }
3443
3230
  };
3444
3231
 
@@ -3461,19 +3248,6 @@ var Observer = class extends EventEmitter5 {
3461
3248
  case "update-when-all-call-updated":
3462
3249
  this.updater = new OnAllCallObserverUpdater(this);
3463
3250
  break;
3464
- case "update-on-interval": {
3465
- const interval = config?.updateIntervalInMs;
3466
- if (!interval) {
3467
- logger6.warn('updateIntervalInMs must be set when updatePolicy is "update-on-interval"; falling back to "update-when-all-call-updated"');
3468
- this.updater = new OnAllCallObserverUpdater(this);
3469
- } else {
3470
- this.updater = new OnIntervalUpdater(
3471
- interval,
3472
- this.update.bind(this)
3473
- );
3474
- }
3475
- break;
3476
- }
3477
3251
  }
3478
3252
  }
3479
3253
  config;
@@ -3491,7 +3265,8 @@ var Observer = class extends EventEmitter5 {
3491
3265
  numberOfOutboundRtpStreams = 0;
3492
3266
  numberOfDataChannels = 0;
3493
3267
  numberOfPeerConnections = 0;
3494
- _timer;
3268
+ /** Global, pre-dispatch middleware chain run on every accepted sample. */
3269
+ acceptMiddlewares = new MiddlewareProcessor();
3495
3270
  get numberOfCalls() {
3496
3271
  return this.observedCalls.size;
3497
3272
  }
@@ -3514,14 +3289,11 @@ var Observer = class extends EventEmitter5 {
3514
3289
  const callSettings = {
3515
3290
  ...settings,
3516
3291
  updatePolicy: settings.updatePolicy ?? this.config.defaultCallUpdatePolicy,
3517
- updateIntervalInMs: settings.updateIntervalInMs ?? this.config.defaultCallUpdateIntervalInMs,
3518
3292
  closeCallIfEmptyForMs: settings.closeCallIfEmptyForMs ?? this.config.closeCallIfEmptyForMs,
3519
3293
  appData: settings.appData ?? this.config.createCallAppData?.({ callId: settings.callId, observer: this })
3520
3294
  };
3521
3295
  const observedCall = new ObservedCall(callSettings, this);
3522
- if (callSettings.remoteTrackResolvePolicy === "mediasoup-sfu") {
3523
- observedCall.remoteTrackResolver = new MediasoupRemoteTrackResolver(observedCall);
3524
- }
3296
+ observedCall.remoteTrackResolver = this.config.createTrackResolver?.(observedCall);
3525
3297
  observedCall.once("close", () => {
3526
3298
  this.observedCalls.delete(observedCall.callId);
3527
3299
  ++this.totalRemovedCall;
@@ -3539,15 +3311,17 @@ var Observer = class extends EventEmitter5 {
3539
3311
  return logger6.debug("Attempted to close twice");
3540
3312
  }
3541
3313
  this.closed = true;
3542
- clearInterval(this._timer);
3543
- this._timer = void 0;
3544
3314
  this.observedCalls.forEach((call) => call.close());
3545
3315
  this._notify("observer-closed", { ...this.eventScope });
3546
3316
  }
3547
3317
  accept(sample, context) {
3548
3318
  if (this.closed) {
3549
- this._notify("sample-rejected", { ...this.eventScope, reason: "observer-closed", sample });
3550
- 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);
3551
3325
  }
3552
3326
  if (!sample.callId) {
3553
3327
  this._notify("sample-rejected", { ...this.eventScope, reason: "missing-callId", sample });
@@ -3664,6 +3438,126 @@ var InMemorySink = class extends ClientSampleSink {
3664
3438
  function createInMemorySink(samples) {
3665
3439
  return new InMemorySink(samples);
3666
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
+ }
3667
3561
  export {
3668
3562
  ClientEventTypes,
3669
3563
  ClientMetaTypes,
@@ -3690,10 +3584,13 @@ export {
3690
3584
  ObservedRemoteInboundRtp,
3691
3585
  ObservedRemoteOutboundRtp,
3692
3586
  Observer,
3587
+ RemoteTrackResolver,
3588
+ createDefaultMediasoupRemoteTrackResolverFactory,
3693
3589
  createInMemorySink,
3694
3590
  createJsonlFileSink,
3695
3591
  createJsonlFileSinkFactory,
3696
3592
  createLogger,
3593
+ createP2pRemoteTrackResolverFactory,
3697
3594
  setObserverLogger
3698
3595
  };
3699
3596
  //# sourceMappingURL=index.mjs.map