Skip to content

Commit

Permalink
3.11.0 (#34)
Browse files Browse the repository at this point in the history
## 3.11.0

* Added `durationOfCollectingStatsInMs` to the `stats-collected` event.
* Set the default sensitivity for `CongestionDetector` to `medium`.
* Changed the default value for `fractionalCorrectionAlertOnThreshold` to 0.3 in `AudioDesyncDetector`.
* Changed the default value for `fractionalCorrectionAlertOffThreshold` to 0.15 in `AudioDesyncDetector`.
* Added `FpsVolatilityModule` to the CPU Performance Detector.
* Added `StatsCollectingSkewModule` to the CPU Performance Detector.
* Made Mediasoup stats collector compatible with version 3.7.16.
* Renamed `Mediasoup[*]Surrogate` interfaces to `MediasoupStatsCollector[*]Interface`.
* Exposed the `MediasoupStatsCollectorDeviceInterface` interface.
* Fixed `ewmaRttInS` calculation in `PeerConnectionStatsCollector`.
* Added `LayersChangedDetector` for experimental purposes.
* Added `pcConnectionState` to the `PEER_CONNECTION_STATE_CHANGED` event.
* Added `fpsVolatility` as a property to `inboundRtpEntry`.
  • Loading branch information
balazskreith authored Aug 25, 2024
1 parent 02a931b commit 5c9529b
Show file tree
Hide file tree
Showing 17 changed files with 1,577 additions and 1,204 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ on:
push:
branches:
- master
- develop
pull_request:
branches:
- master
- develop

jobs:
publish:
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@observertc/client-monitor-js",
"version": "3.10.2",
"version": "3.11.0",
"description": "ObserveRTC Client Integration Javascript Library",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down Expand Up @@ -39,6 +39,7 @@
"@types/jest": "^29.5.3",
"@types/ua-parser-js": "^0.7.39",
"@types/uuid": "^8.3.4",
"mediasoup-client": "^3.7.16",
"@typescript-eslint/eslint-plugin": "^5.38.0",
"@typescript-eslint/parser": "^5.38.0",
"bufferutil": "^4.0.6",
Expand Down
35 changes: 28 additions & 7 deletions src/ClientMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export interface ClientMonitorEvents {
lastSample?: ClientSample,
},
'stats-collected': {
durationOfCollectingStatsInMs: number,
elapsedSinceLastCollectedInMs: number,
collectedStats: CollectedStats,
},
Expand Down Expand Up @@ -276,6 +277,7 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {

public async collect(): Promise<CollectedStats> {
if (this._closed) throw new Error('ClientMonitor is closed');
const started = Date.now();
const wasUsingTURN = this.peerConnections.some(pc => pc.usingTURN);
const collectedStats = await this.collectors.collect();
this.storage.update(collectedStats);
Expand All @@ -284,6 +286,7 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {
this.emit('stats-collected', {
collectedStats,
elapsedSinceLastCollectedInMs: timestamp - this._lastCollectedAt,
durationOfCollectingStatsInMs: timestamp - started,
});

this._lastCollectedAt = timestamp;
Expand Down Expand Up @@ -484,7 +487,7 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {
createIssueOnDetection,
...detectorConfig
} = options ?? {
sensitivity: 'high',
sensitivity: 'medium',
};

if (existingDetector) {
Expand Down Expand Up @@ -554,8 +557,8 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {
}

const detector = new AudioDesyncDetector({
fractionalCorrectionAlertOnThreshold: config?.fractionalCorrectionAlertOnThreshold ?? 0.1,
fractionalCorrectionAlertOffThreshold: config?.fractionalCorrectionAlertOffThreshold ?? 0.05,
fractionalCorrectionAlertOnThreshold: config?.fractionalCorrectionAlertOnThreshold ?? 0.3,
fractionalCorrectionAlertOffThreshold: config?.fractionalCorrectionAlertOffThreshold ?? 0.15,
});
const onUpdate = () => detector.update(this.storage.inboundRtps());
const {
Expand Down Expand Up @@ -676,8 +679,17 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {
existingDetector.close();
}

const detector = new CpuPerformanceDetector(config ?? {});
const onUpdate = () => detector.update(this.storage.peerConnections());
const detector = new CpuPerformanceDetector(config ?? {
fpsVolatilityThresholds: {
lowWatermark: 0.08,
highWatermark: 0.15,
},
durationOfCollectingStatsThreshold: this._config.collectingPeriodInMs ? {
lowWatermark: this._config.collectingPeriodInMs * 0.5,
highWatermark: this._config.collectingPeriodInMs,
} : undefined,
});
const onUpdate = ({ durationOfCollectingStatsInMs }: { durationOfCollectingStatsInMs: number}) => detector.update(this.storage.peerConnections(), durationOfCollectingStatsInMs);
const {
createIssueOnDetection,
} = config ?? {};
Expand Down Expand Up @@ -705,6 +717,7 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {
detector.off('statechanged', onStateChanged);
this._detectors.delete(CpuPerformanceDetector.name);
});

this.on('stats-collected', onUpdate);
detector.on('statechanged', onStateChanged);

Expand Down Expand Up @@ -1070,8 +1083,8 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {

if (settings.audioDesync) {
this.createAudioDesyncDetector({
fractionalCorrectionAlertOffThreshold: 0.05,
fractionalCorrectionAlertOnThreshold: 0.1,
fractionalCorrectionAlertOffThreshold: 0.15,
fractionalCorrectionAlertOnThreshold: 0.3,
createIssueOnDetection: getCreateIssueOnDetection('audioDesync'),
});
}
Expand All @@ -1084,6 +1097,14 @@ export class ClientMonitor extends TypedEventEmitter<ClientMonitorEvents> {

if (settings.cpuLimitation) {
this.createCpuPerformanceIssueDetector({
fpsVolatilityThresholds: {
lowWatermark: 0.08,
highWatermark: 0.15,
},
durationOfCollectingStatsThreshold: this._config.collectingPeriodInMs ? {
lowWatermark: this._config.collectingPeriodInMs * 0.5,
highWatermark: this._config.collectingPeriodInMs,
} : undefined,
createIssueOnDetection: getCreateIssueOnDetection('cpuLimitation'),
});
}
Expand Down
6 changes: 3 additions & 3 deletions src/Collectors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createPeerConnectionCollector } from "./collectors/PeerConnectionStatsCollector";
import { createLogger } from "./utils/logger";
import { v4 as uuid } from "uuid";
import { MediaosupDeviceSurrogate } from "./collectors/MediasoupSurrogates";
import { MediasoupStatsCollectorDeviceInterface } from "./collectors/MediasoupSurrogates";
import { StatsMap, collectStatsValuesFromRtcStatsReport, createStatsMap } from "./utils/Stats";
import { createProcessor } from "./utils/Processor";
import { TypedEventEmitter } from "./utils/TypedEmitter";
Expand Down Expand Up @@ -152,10 +152,10 @@ export function createCollectors(config: {
return statsCollector;
}

function addMediasoupDevice(device: MediaosupDeviceSurrogate, collectorId?: string) {
function addMediasoupDevice(device: MediasoupStatsCollectorDeviceInterface, collectorId?: string) {
logger.trace(`addMediasoupDevice(): mediasoupDevice: `, device);
const statsCollector = createMediasoupStatsCollector({
device,
device: device as MediasoupStatsCollectorDeviceInterface,
collectorId,

storage,
Expand Down
3 changes: 3 additions & 0 deletions src/Sampler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export class Sampler {
const outboundRtpStats = outboundRtp.stats;
const remoteInboundRtpStats = outboundRtp.getRemoteInboundRtp()?.stats;
const mediaSourceStats = outboundRtp.getMediaSource()?.stats;

if (outboundRtp.stats.kind === "audio") {
if (!outboundAudioTracks) outboundAudioTracks = [];
const outboundAudioTrack: OutboundAudioTrack = {
Expand Down Expand Up @@ -463,6 +464,7 @@ export class Sampler {
clockRate: stats.clockRate,
channels: stats.channels,
sdpFmtpLine: stats.sdpFmtpLine,

});
}

Expand Down Expand Up @@ -540,6 +542,7 @@ export class Sampler {
iceServers.push(stats.url);
}
}

clientSample.inboundAudioTracks = inboundAudioTracks;
clientSample.inboundVideoTracks = inboundVideoTracks;
clientSample.outboundAudioTracks = outboundAudioTracks;
Expand Down
31 changes: 17 additions & 14 deletions src/collectors/MediasoupStatsCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
createPeerConnectionStateChangedEvent
} from "../utils/callEvents";
import {
MediaosupDeviceSurrogate,
MediasoupConsumerSurrogate,
MediasoupDataConsumerSurrogate,
MediasoupDataProducerSurrogate,
MediasoupProducerSurrogate,
MediasoupTransportSurrogate
MediasoupStatsCollectorDeviceInterface,
MediasoupStatsCollectorConsumerInterface,
MediasoupStatsCollectorDataConsumerInterface,
MediasoupStatsCollectorDataProducerInterface,
MediasoupStatsCollectorProducerInterface,
MediasoupStatsCollectorTransportInterface
} from "./MediasoupSurrogates";
import { StatsProvider, createStatsProvider } from "./StatsProvider";
import { createLogger } from "../utils/logger";
Expand All @@ -22,7 +22,7 @@ const logger = createLogger("MediasoupStatsCollector");

export type MediasoupStatsCollectorConfig = {
collectorId?: string,
device: MediaosupDeviceSurrogate,
device: MediasoupStatsCollectorDeviceInterface,
storage: StatsStorage
emitCallEvent: ((event: CustomCallEvent) => void);
addStatsProvider: ((statsProvider: StatsProvider) => void);
Expand All @@ -41,11 +41,11 @@ export function createMediasoupStatsCollector(config: MediasoupStatsCollectorCon
removeStatsProvider,
} = config;

const transports = new Map<string, MediasoupTransportSurrogate>();
const transports = new Map<string, MediasoupStatsCollectorTransportInterface>();
const addedOutboundTrackIds = new Set<string>();
// const producers = new Map<string, MediasoupProducerSurrogate>();
// const consumers = new Map<string, MediasoupConsumerSurrogate>();
const pendingProducerBindings = new Map<string, { producer: MediasoupProducerSurrogate, peerConnectionId: string }>();
const pendingProducerBindings = new Map<string, { producer: MediasoupStatsCollectorProducerInterface, peerConnectionId: string }>();
const getLastSndTransport = () => {
const sndTransports = Array.from(transports.values()).filter(transport => transport.direction === 'send');
return sndTransports.length < 1 ? undefined : sndTransports[sndTransports.length - 1];
Expand Down Expand Up @@ -91,7 +91,7 @@ export function createMediasoupStatsCollector(config: MediasoupStatsCollectorCon
}

function createAddProducerListener(peerConnectionId: string) {
return (producer: MediasoupProducerSurrogate) => {
return (producer: MediasoupStatsCollectorProducerInterface) => {
const eventBase = {
peerConnectionId,
mediaTrackId: producer.track?.id,
Expand Down Expand Up @@ -151,7 +151,7 @@ export function createMediasoupStatsCollector(config: MediasoupStatsCollectorCon
}

function createAddConsumerListener(peerConnectionId: string) {
return (consumer: MediasoupConsumerSurrogate) => {
return (consumer: MediasoupStatsCollectorConsumerInterface) => {
const eventBase = {
peerConnectionId,
mediaTrackId: consumer.track.id,
Expand Down Expand Up @@ -204,7 +204,7 @@ export function createMediasoupStatsCollector(config: MediasoupStatsCollectorCon
}

function createAddDataProducerListener(peerConnectionId: string) {
return (dataProducer: MediasoupDataProducerSurrogate) => {
return (dataProducer: MediasoupStatsCollectorDataProducerInterface) => {
const eventBase = {
peerConnectionId,
attachments: JSON.stringify({
Expand All @@ -226,7 +226,7 @@ export function createMediasoupStatsCollector(config: MediasoupStatsCollectorCon
}

function createAddDataConsumerListener(peerConnectionId: string) {
return (dataConsumer: MediasoupDataConsumerSurrogate) => {
return (dataConsumer: MediasoupStatsCollectorDataConsumerInterface) => {
const eventBase = {
peerConnectionId,
attachments: JSON.stringify({
Expand All @@ -249,7 +249,7 @@ export function createMediasoupStatsCollector(config: MediasoupStatsCollectorCon
}


function addTransport(transport: MediasoupTransportSurrogate, timestamp?: number) {
function addTransport(transport: MediasoupStatsCollectorTransportInterface, timestamp?: number) {
const eventBase = {
peerConnectionId: transport.id,
attachments: JSON.stringify({
Expand Down Expand Up @@ -360,6 +360,9 @@ export function createMediasoupStatsCollector(config: MediasoupStatsCollectorCon
get id() {
return collectorId;
},
get transports(): ReadonlyMap<string, MediasoupStatsCollectorTransportInterface> {
return transports;
},
close,
addTransport,
addOutboundTrack,
Expand Down
Loading

0 comments on commit 5c9529b

Please sign in to comment.