@observertc/observer-js 1.3.0-rc.4 → 1.3.0-rc.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/README.md +38 -0
- package/dist/index.d.mts +73 -3
- package/dist/index.d.ts +73 -3
- package/dist/index.js +115 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +114 -15
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1778,19 +1778,17 @@ function isPublicIpAddress(address) {
|
|
|
1778
1778
|
|
|
1779
1779
|
// src/ObservedOutboundTrack.ts
|
|
1780
1780
|
var ObservedOutboundTrack = class {
|
|
1781
|
-
constructor(timestamp, id, kind, _peerConnection,
|
|
1781
|
+
constructor(timestamp, id, kind, _peerConnection, _mediaSource) {
|
|
1782
1782
|
this.timestamp = timestamp;
|
|
1783
1783
|
this.id = id;
|
|
1784
1784
|
this.kind = kind;
|
|
1785
1785
|
this._peerConnection = _peerConnection;
|
|
1786
|
-
this._outboundRtps = _outboundRtps;
|
|
1787
1786
|
this._mediaSource = _mediaSource;
|
|
1788
1787
|
}
|
|
1789
1788
|
timestamp;
|
|
1790
1789
|
id;
|
|
1791
1790
|
kind;
|
|
1792
1791
|
_peerConnection;
|
|
1793
|
-
_outboundRtps;
|
|
1794
1792
|
_mediaSource;
|
|
1795
1793
|
_visited = false;
|
|
1796
1794
|
appData;
|
|
@@ -1841,8 +1839,11 @@ var ObservedOutboundTrack = class {
|
|
|
1841
1839
|
getPeerConnection() {
|
|
1842
1840
|
return this._peerConnection;
|
|
1843
1841
|
}
|
|
1842
|
+
/** The outbound RTPs of this track's media source, looked up on every call. */
|
|
1844
1843
|
getOutboundRtps() {
|
|
1845
|
-
|
|
1844
|
+
const mediaSource = this._mediaSource;
|
|
1845
|
+
if (!mediaSource) return void 0;
|
|
1846
|
+
return [...this._peerConnection.observedOutboundRtps.values()].filter((rtp) => rtp.mediaSourceId === mediaSource.id);
|
|
1846
1847
|
}
|
|
1847
1848
|
getMediaSource() {
|
|
1848
1849
|
return this._mediaSource;
|
|
@@ -1861,7 +1862,7 @@ var ObservedOutboundTrack = class {
|
|
|
1861
1862
|
this.remoteFractionLost = void 0;
|
|
1862
1863
|
this.remoteRttInMs = void 0;
|
|
1863
1864
|
this.qualityLimitationReason = void 0;
|
|
1864
|
-
for (const rtp of this.
|
|
1865
|
+
for (const rtp of this.getOutboundRtps() ?? []) {
|
|
1865
1866
|
this.bitrate = (this.bitrate ?? 0) + rtp.bitrate;
|
|
1866
1867
|
this.deltaPacketsSent = (this.deltaPacketsSent ?? 0) + rtp.deltaPacketsSent;
|
|
1867
1868
|
if (rtp.remoteFractionLost !== void 0) {
|
|
@@ -2526,9 +2527,7 @@ var ObservedPeerConnection = class extends EventEmitter2 {
|
|
|
2526
2527
|
}
|
|
2527
2528
|
for (const observedOutboundTrack of [...this.observedOutboundTracks.values()]) {
|
|
2528
2529
|
if (observedOutboundTrack.visited) continue;
|
|
2529
|
-
this.
|
|
2530
|
-
this.emit("removed-outbound-track", observedOutboundTrack);
|
|
2531
|
-
this._notify("outbound-track-removed", { ...this.eventScope, observedOutboundTrack });
|
|
2530
|
+
this._removeOutboundTrack(observedOutboundTrack);
|
|
2532
2531
|
}
|
|
2533
2532
|
for (const observedPeerConnectionTransport of [...this.observedPeerConnectionTransports.values()]) {
|
|
2534
2533
|
if (observedPeerConnectionTransport.visited) continue;
|
|
@@ -2789,6 +2788,11 @@ var ObservedPeerConnection = class extends EventEmitter2 {
|
|
|
2789
2788
|
}
|
|
2790
2789
|
_updateOutboundTrackSample(stats) {
|
|
2791
2790
|
let observedOutboundTrack = this.observedOutboundTracks.get(stats.id);
|
|
2791
|
+
const mediaSource = [...this.observedMediaSources.values()].filter((source) => source.trackIdentifier === stats.id).pop();
|
|
2792
|
+
if (observedOutboundTrack && observedOutboundTrack.getMediaSource() !== mediaSource) {
|
|
2793
|
+
this._removeOutboundTrack(observedOutboundTrack);
|
|
2794
|
+
observedOutboundTrack = void 0;
|
|
2795
|
+
}
|
|
2792
2796
|
if (!observedOutboundTrack) {
|
|
2793
2797
|
if (!stats.timestamp || !stats.id || !stats.kind) {
|
|
2794
2798
|
return logger3.warn(
|
|
@@ -2796,15 +2800,12 @@ var ObservedPeerConnection = class extends EventEmitter2 {
|
|
|
2796
2800
|
stats
|
|
2797
2801
|
);
|
|
2798
2802
|
}
|
|
2799
|
-
const observedMediaSource = [...this.observedMediaSources.values()].find((mediaSource) => mediaSource.trackIdentifier === stats.id);
|
|
2800
|
-
const outboundRtps = observedMediaSource ? [...this.observedOutboundRtps.values()].filter((outboundRtp) => outboundRtp.mediaSourceId === observedMediaSource?.id) : void 0;
|
|
2801
2803
|
observedOutboundTrack = new ObservedOutboundTrack(
|
|
2802
2804
|
stats.timestamp,
|
|
2803
2805
|
stats.id,
|
|
2804
2806
|
stats.kind,
|
|
2805
2807
|
this,
|
|
2806
|
-
|
|
2807
|
-
observedMediaSource
|
|
2808
|
+
mediaSource
|
|
2808
2809
|
);
|
|
2809
2810
|
observedOutboundTrack.update(stats);
|
|
2810
2811
|
this.observedOutboundTracks.set(stats.id, observedOutboundTrack);
|
|
@@ -2815,6 +2816,11 @@ var ObservedPeerConnection = class extends EventEmitter2 {
|
|
|
2815
2816
|
this._notify("outbound-track-updated", { ...this.eventScope, observedOutboundTrack });
|
|
2816
2817
|
return observedOutboundTrack;
|
|
2817
2818
|
}
|
|
2819
|
+
_removeOutboundTrack(observedOutboundTrack) {
|
|
2820
|
+
this.observedOutboundTracks.delete(observedOutboundTrack.id);
|
|
2821
|
+
this.emit("removed-outbound-track", observedOutboundTrack);
|
|
2822
|
+
this._notify("outbound-track-removed", { ...this.eventScope, observedOutboundTrack });
|
|
2823
|
+
}
|
|
2818
2824
|
_updatePeerConnectionTransportStats(stats) {
|
|
2819
2825
|
let observedPeerConnectionTransport = this.observedPeerConnectionTransports.get(stats.id);
|
|
2820
2826
|
if (!observedPeerConnectionTransport) {
|
|
@@ -7979,9 +7985,96 @@ var TrendTester = class {
|
|
|
7979
7985
|
}
|
|
7980
7986
|
};
|
|
7981
7987
|
|
|
7982
|
-
// src/sinks/
|
|
7988
|
+
// src/sinks/RollingJsonlFileSink.ts
|
|
7989
|
+
import * as fs2 from "fs";
|
|
7983
7990
|
import { EventEmitter as EventEmitter8 } from "events";
|
|
7984
|
-
var
|
|
7991
|
+
var RollingJsonlFileSink = class extends EventEmitter8 {
|
|
7992
|
+
id;
|
|
7993
|
+
_options;
|
|
7994
|
+
_serializeSample;
|
|
7995
|
+
_stream;
|
|
7996
|
+
_path;
|
|
7997
|
+
_index = -1;
|
|
7998
|
+
_openedAt = 0;
|
|
7999
|
+
_bytes = 0;
|
|
8000
|
+
_ended = false;
|
|
8001
|
+
// Resolves once every file closed so far has closed and been announced, in index order: the
|
|
8002
|
+
// streams close independently, so a later file could otherwise be announced before an earlier one.
|
|
8003
|
+
_closing = Promise.resolve();
|
|
8004
|
+
constructor(options) {
|
|
8005
|
+
super();
|
|
8006
|
+
this._options = options;
|
|
8007
|
+
this._serializeSample = options.serializeSample ?? ((record) => JSON.stringify(record));
|
|
8008
|
+
this._open();
|
|
8009
|
+
this.id = options.id ?? this._path;
|
|
8010
|
+
}
|
|
8011
|
+
/** The file currently written to. */
|
|
8012
|
+
get path() {
|
|
8013
|
+
return this._path;
|
|
8014
|
+
}
|
|
8015
|
+
/** The index of the file currently written to. */
|
|
8016
|
+
get index() {
|
|
8017
|
+
return this._index;
|
|
8018
|
+
}
|
|
8019
|
+
get ended() {
|
|
8020
|
+
return this._ended;
|
|
8021
|
+
}
|
|
8022
|
+
write(record) {
|
|
8023
|
+
if (this._ended) return false;
|
|
8024
|
+
const line = `${this._serializeSample(record)}
|
|
8025
|
+
`;
|
|
8026
|
+
const bytes = Buffer.byteLength(line);
|
|
8027
|
+
const { maxBytes, maxAgeMs } = this._options;
|
|
8028
|
+
if (maxAgeMs !== void 0 && maxAgeMs <= Date.now() - this._openedAt) this.roll();
|
|
8029
|
+
if (maxBytes !== void 0 && maxBytes < this._bytes + bytes) this.roll();
|
|
8030
|
+
this._bytes += bytes;
|
|
8031
|
+
return this._stream.write(line);
|
|
8032
|
+
}
|
|
8033
|
+
/** Close the current file and continue in a new one. A no-op on an empty file or an ended sink. */
|
|
8034
|
+
roll() {
|
|
8035
|
+
if (this._ended || this._bytes === 0) return;
|
|
8036
|
+
this._closeCurrent();
|
|
8037
|
+
this._open();
|
|
8038
|
+
}
|
|
8039
|
+
/** No more writes: emits `ended`, closes the current file (`file-closed`), then emits `close`. */
|
|
8040
|
+
end() {
|
|
8041
|
+
if (this._ended) return;
|
|
8042
|
+
this._ended = true;
|
|
8043
|
+
this.emit("ended");
|
|
8044
|
+
this._closeCurrent();
|
|
8045
|
+
void this._closing.then(() => {
|
|
8046
|
+
this.emit("finish");
|
|
8047
|
+
this.emit("close");
|
|
8048
|
+
});
|
|
8049
|
+
}
|
|
8050
|
+
_open() {
|
|
8051
|
+
++this._index;
|
|
8052
|
+
this._openedAt = Date.now();
|
|
8053
|
+
this._bytes = 0;
|
|
8054
|
+
this._path = this._options.path({ index: this._index, openedAt: this._openedAt });
|
|
8055
|
+
const stream = fs2.createWriteStream(this._path, { flags: "a" });
|
|
8056
|
+
stream.on("drain", () => this.emit("drain"));
|
|
8057
|
+
stream.on("error", (err) => this.emit("error", err));
|
|
8058
|
+
this._stream = stream;
|
|
8059
|
+
}
|
|
8060
|
+
_closeCurrent() {
|
|
8061
|
+
const stream = this._stream;
|
|
8062
|
+
const path = this._path;
|
|
8063
|
+
const index = this._index;
|
|
8064
|
+
const closed = new Promise((resolve) => {
|
|
8065
|
+
stream.once("close", () => resolve());
|
|
8066
|
+
stream.once("error", () => resolve());
|
|
8067
|
+
});
|
|
8068
|
+
this._closing = Promise.all([this._closing, closed]).then(() => {
|
|
8069
|
+
this.emit("file-closed", path, index);
|
|
8070
|
+
});
|
|
8071
|
+
stream.end();
|
|
8072
|
+
}
|
|
8073
|
+
};
|
|
8074
|
+
|
|
8075
|
+
// src/sinks/InMemorySink.ts
|
|
8076
|
+
import { EventEmitter as EventEmitter9 } from "events";
|
|
8077
|
+
var InMemorySink = class extends EventEmitter9 {
|
|
7985
8078
|
id;
|
|
7986
8079
|
samples;
|
|
7987
8080
|
_ended = false;
|
|
@@ -8044,6 +8137,7 @@ var RemoteTrackResolver = class {
|
|
|
8044
8137
|
observer.off("outbound-track-updated", onOutboundUpdated);
|
|
8045
8138
|
this._pendingInboundTracks.clear();
|
|
8046
8139
|
this._pendingOutboundTracks.clear();
|
|
8140
|
+
this._outboundTrackPublisherIds.clear();
|
|
8047
8141
|
});
|
|
8048
8142
|
observer.on("inbound-track-added", onInboundAdded);
|
|
8049
8143
|
observer.on("inbound-track-removed", onInboundRemoved);
|
|
@@ -8055,6 +8149,8 @@ var RemoteTrackResolver = class {
|
|
|
8055
8149
|
observedCall;
|
|
8056
8150
|
resolvers;
|
|
8057
8151
|
_publisherIdToOutboundTrack = /* @__PURE__ */ new Map();
|
|
8152
|
+
// The publisher id each outbound track was indexed under, so removal does not depend on its current attachments.
|
|
8153
|
+
_outboundTrackPublisherIds = /* @__PURE__ */ new Map();
|
|
8058
8154
|
_subscriberIdToInboundTrack = /* @__PURE__ */ new Map();
|
|
8059
8155
|
/**
|
|
8060
8156
|
* Tracks whose publisher id the strategy could not resolve **yet**.
|
|
@@ -8130,6 +8226,7 @@ var RemoteTrackResolver = class {
|
|
|
8130
8226
|
}
|
|
8131
8227
|
this._pendingOutboundTracks.delete(outboundTrack);
|
|
8132
8228
|
this._publisherIdToOutboundTrack.set(publisherId, outboundTrack);
|
|
8229
|
+
this._outboundTrackPublisherIds.set(outboundTrack, publisherId);
|
|
8133
8230
|
this.observedCall.unconsumedOutboundTracks.add(outboundTrack);
|
|
8134
8231
|
for (const observedClient of this.observedCall.observedClients.values()) {
|
|
8135
8232
|
for (const observedPeerConnection of observedClient.observedPeerConnections.values()) {
|
|
@@ -8144,7 +8241,8 @@ var RemoteTrackResolver = class {
|
|
|
8144
8241
|
}
|
|
8145
8242
|
_removeOutboundTrack(outboundTrack) {
|
|
8146
8243
|
this._pendingOutboundTracks.delete(outboundTrack);
|
|
8147
|
-
const publisherId = this.
|
|
8244
|
+
const publisherId = this._outboundTrackPublisherIds.get(outboundTrack);
|
|
8245
|
+
this._outboundTrackPublisherIds.delete(outboundTrack);
|
|
8148
8246
|
if (publisherId && this._publisherIdToOutboundTrack.get(publisherId) === outboundTrack) {
|
|
8149
8247
|
this._publisherIdToOutboundTrack.delete(publisherId);
|
|
8150
8248
|
}
|
|
@@ -8236,6 +8334,7 @@ export {
|
|
|
8236
8334
|
RTT_HISTOGRAM_NUMBER_OF_BUCKETS,
|
|
8237
8335
|
RemoteTrackResolver,
|
|
8238
8336
|
RemoteTrackResolverValidator,
|
|
8337
|
+
RollingJsonlFileSink,
|
|
8239
8338
|
SCORE_HISTOGRAM_BUCKET_WIDTH,
|
|
8240
8339
|
SCORE_HISTOGRAM_NUMBER_OF_BUCKETS,
|
|
8241
8340
|
SfuCongestionDetector,
|