sfu-monitor-js

The documentation is created for sfu-monitor-js version 2.x.y

Install

npm i @observertc/sfu-monitor-js

Source code

https://github.com/ObserveRTC/sfu-monitor-js

Top-level components

// Using ES6 import.
import * as ObserveRTC from '@observertc/sfu-monitor-js';

// Using CommonJS.
const ObserveRTC = require("@observertc/sfu-monitor-js");

// Or using destructuring assignment:
import {
  /**
   * An interface for the SfuMonitor.
   */
  SfuMonitor, 
  /**
   * Type for SfuMonitorConfig. 
   */
  SfuMonitorConfig,
  /**
   * interface for SfuMonitor events and emitted data types 
   */
  SfuMonitorEventsMap,

  /**
   * interface to define an auxilarity collector and SfuMonitor can use to collect stats
   */
  AuxCollector,

  /**
   * interface for a collector created after mediasoup is added to collect stats from
   */
  MediasoupCollector,

  /**
   * Additional types are imported from the `@observertc/sample-schemas-js` package
   */
  Samples,
  SfuSample,
  SfuTransport,
  SfuInboundRtpPad,
  SfuOutboundRtpPad,
  SfuSctpChannel,
  SfuExtensionStats,
  CustomSfuEvent,
  /**
   * interface for entries SfuMonitor storage provide
   */
  SfuTransportEntry,
  SfuInboundRtpPadEntry,
  SfuOutboundRtpPadEntry,
  SfuSctpChannelEntry,
} from '@observertc/client-monitor-js';

createSfuMonitor

Creates a new SfuMonitor instance with the specified configuration.

import * as ObserveRTC from '@observertc/sfu-monitor-js';

// quick start to create a monitor and log the collected stats
const monitor = ObserveRTC.createSfuMonitor({
  collectingPeriodInMs: 2000,
  samplingPeriodInMs: 4000,
});

monitor.on('sample-created', ({ sfuSample }) => {
  console.log('The created sample', sfuSample);
});
import * as ObserveRTC from '@observertc/sfu-monitor-js';

// configuration for the client-monitor
const config: ObserveRTC.SfuMonitorConfig = {
  /**
  * The identifier of the SFU.
  *
  * DEFAULT: a generated unique value
  */
  sfuId: 'my-sfu-id',

  /**
  * Sets the default logging level for sfu-monitor-js
  * 
  * DEFAULT: warn
  */
  logLevel: LogLevel,

  /**
  * Sets the maximum number of listeners for event emitters
  */
  maxListeners: 1000,
  
  /**
  * Set the ticking time of the timer invokes processes for collecting, sampling, and sending.
  * 
  * DEFAULT: 1000
  */
  tickingTimeInMs: 1000,

  /**
  * By setting it, the observer calls the added statsCollectors periodically
  * and pulls the stats.
  *
  * DEFAULT: undefined
  */
  collectingPeriodInMs: 1000,
  /**
  * By setting it, the observer make samples periodically.
  *
  * DEFAULT: undefined
  */
  samplingPeriodInMs: 1000,

  /**
  * By setting it, the observer sends the samples periodically.
  *
  * DEFAULT: undefined
  */
  sendingPeriodInMs: 1000,

  /**
  * Limits the number of stats polled at once from the collectors. 
  * 
  * DEFAULT: 50
  */
  pollingBatchSize: 50,

  /**
  * Pacing time between polling batches of stats
  * 
  * DEFAULT: undefined
  */
  pollingBatchPaceTimeInMs: 50,

  /**
  * Flag indicating if the monitor creates sfu events.
  * If true, events happening on the collected sources create sfu events such as SFU_TRANSPORT_OPENED, SFU_TRANSPORT_CLOSED.
  * 
  * If this flag is false, the application is responsible for adding sfu events by calling the appropriate SfuMonitor method for the corresponding event.
  * 
  * DEFAULT: false
  */
  createSfuEvents: true,

  /**
  * Configuration for the samples accumulator to balance the transfer the size of the Samples 
  * prepared to be sent to the server
  * 
  */
  accumulator: {
    /**
     * Sets the maximum number of client sample allowed to be in one Sample
     * 
     * DEFAULT: 100
     */
    maxClientSamples: 100,

    /**
     * Sets the maximum number of Samples the accumulator can hold
     * 
     * DEFAULT: 10
     */
    maxSamples: 10,

    /**
     * Forward a Sample to the server even if it is empty
     * 
     * DEFAULT: false
     */
    forwardIfEmpty: false
  }
};

const monitor = ObserveRTC.createSfuMonitor(config);

Integrations

Mediasoup

You can listen all created workers all routers, transports, etc. by adding mediasoup to the collector

import * as mediasoup from 'mediasoup';

const sfuMonitor = createSfuMonitor({
  logLevel: 'info',
  collectingPeriodInMs: 5000,
  samplingPeriodInMs: 15000,
});

const mediasoupCollector = sfuMonitor.createMediasoupCollector({
  mediasoup,
  pollConsumerStats: (consumerId: string) => true,
  pollDataConsumerStats: (dataConsumerId: string) => true,
  pollProducerStats: (producerId: string) => true,
  pollDataProducerStats: (dataProducerId: string) => true,
  pollWebRtcTransportStats: (transportId: string) => true,
});

Or you can add specific object to listen for

import * as mediasoup from 'mediasoup';

const sfuMonitor = createSfuMonitor({
  logLevel: 'info',
  collectingPeriodInMs: 5000,
  samplingPeriodInMs: 15000,
});

const mediasoupCollector = sfuMonitor.createMediasoupCollector({
  pollConsumerStats: (consumerId: string) => true,
});

const transport = // .. created transport from a router
const consumer = // created consumer from a transport

mediasoupCollector.addConsumer(consumer, transportId);

SfuMonitor

SfuMonitor is responsible for monitoring and collecting SFU-related data.

Events

SfuMonitor emitted stats-collected, sample-created, send events.

stats-collected

Emitted event after each collection period or if the monitor.collect() method is called.

const subscription = () => {
  console.log('The follosing stats are collected:');
};
monitor.on('stats-collected', subscription);
monitor.once('stats-collected', subscription);
monitor.off('stats-collected', subscription);

sample-created

Emitted event after each sampling period or if the monitor.sample() method is called.

const subscription = clientSample => {
  console.log('The ClientSample is created', clientSample);
};
monitor.on('sample-created', subscription);
monitor.once('sample-created', subscription);
monitor.off('sample-created', subscription);

send

Emitted event after each sending period or if the monitor.send() method is called.

const subscription = samples =>  {
  console.log('Samples are ready for sending', samples);
};
monitor.on('send', subscription);
monitor.once('send', subscription);
monitor.off('send', subscription);

Properties

  • config: The assigned configuration for the SfuMonitor upon creation.
  • sfuId: Gets the SFU identifier.
  • metrics: Access to the montior’s self metrics (last collection time, etc.).
  • storage: Access to the collected stats.
  • closed: Flag indicating whether the monitor is closed or not.
const config = monitor.config;
console.log(
  'The assigned configuration for the SfuMonitor upon creation.',
  config
);

const sfuId = monitor.sfuId;
console.log(
  'the SFU identifier.',
  config
);

const metrics = monitor.metrics;
console.log(
  "Access to the montior's self metrics (last collection time, etc.):",
  metrics
);

const storage = monitor.storage;
console.log('Access to the collected stats:', storage);

const closed = monitor.closed;
console.log('Flag indicating whether the monitor is closed or not:', closed);

createAuxCollector

Creates an auxiliary collector the sfu monitor can collect stats from

const collector = monitor.createAuxCollector();

const transportId = ""
collector.addTransportStatsSupplier("myUniqueGeneratedTransportId", async () => {
    const stats: SfuTransport = {

    };
    return stats;
});

collector.addInboundRtpPadStatsSupplier("padId", ...);
collector.addOutboundRtpPadStatsSupplier("padId", ...);
collector.addSctpStreamStatsSupplier("channelId", ...);

createMediasoupCollector

Creates a mediasoup collector with the specified configuration.

addExtensionStats

Adds an arbitrary stats object that will be sent to the backend observer.

monitor.addExtensionStats({ name: 'customStats', value: 'example' });

addTransportOpenedEvent

Adds a transport opened event to the SFU event list.

monitor.addTransportOpenedEvent(
  transportId, // The identifier of the opened transport.
  timestamp // Optional timestamp for the event. If not provided, the current date and time will be used.
);

addTransportClosedEvent

Adds a transport closed event to the SFU event list.

monitor.addTransportClosedEvent(
  transportId, // The identifier of the closed transport.
  timestamp // Optional timestamp for the event. If not provided, the current date and time will be used.
)

addRtpStreamAdded

Adds an RTP stream added event to the SFU event list.

monitor.addRtpStreamAdded(
  transportId, // The identifier of the transport associated with the RTP stream.
  rtpPadId, // The identifier of the RTP pad.
  sfuStreamId, // The identifier of the SFU stream.
  sfuSinkId, // Optional identifier of the SFU sink.
  timestamp // Optional timestamp for the event. If not provided, the current date and time will be used.
);

addRtpStreamRemoved

Adds an RTP stream removed event to the SFU event list.

monitor.addRtpStreamRemoved(
  transportId, // The identifier of the transport associated with the RTP stream.
  rtpPadId, // The identifier of the RTP pad.
  sfuStreamId, // The identifier of the SFU stream.
  sfuSinkId, // Optional identifier of the SFU sink.
  timestamp // Optional timestamp for the event. If not provided, the current date and time will be used.
)

setMarker

Marks all of the created samples with a given string.

await monitor.setMarker("experimental-stats");

collect

Collects stats.

await monitor.collect();

sample

Creates a sfu sample from the collected stats.

monitor.sample();

send

Sends the samples.

monitor.send();

close

Closes the monitor and all its used resources.

monitor.close();

Storage

Sfu Monitor collects measurements about the following components:

  • Transport: Represent a network transport connection between an SFU and an external endpoint
  • Inbound RTP Pad: Represents an ingress point for RTP sessions to the SFU.
  • Outbound RTP Pad: Represents an eggress point for RTP sessions from the SFU.
  • SCTP Channel: Represent an SCTP session

transports

Iterable iterator to list all collected transports.

const iterator = statsReader.transports();

getTransportEntry

Gets the monitored object based on identifier.

const transportEntry = statsReader.getTransportEntry(transportId);

inboundRtpPads

Iterable iterator to list all collected inbound RTP pads.

const iterator = statsReader.inboundRtpPads();

getInboundRtpPad

Iterable iterator to list all collected inbound RTP pads.

const inboundRtpPad = statsReader.getInboundRtpPad(rtpPadId);

outboundRtpPads

Iterable iterator to list all collected outbound RTP pads.

const inboundRtpPad = statsReader.getInboundRtpPad(rtpPadId);

getOutboundRtpPad

Gets the monitored object based on identifier.

const outboundRtpPad = statsReader.getOutboundRtpPad(rtpPadId);

sctpChannels

Iterable iterator to list all collected SCTP channels.

const iterator = statsReader.sctpChannels();

getSctpChannel

Gets the monitored object based on identifier.

const sctpChannel = statsReader.getOutboundRtpPad(sctpChannelId);

AuxCollector

Interface for auxiliary collectors.

addTransportStatsSupplier

Adds a transport stats supplier for a given transport ID.

auxCollector.addTransportStatsSupplier(transportId, supplier);

removeTransportStatsSupplier

Removes a transport stats supplier for a given transport ID.

auxCollector.removeTransportStatsSupplier(transportId);

addInboundRtpPadStatsSupplier

Adds an inbound RTP pad stats supplier for a given inbound RTP pad ID.

auxCollector.addInboundRtpPadStatsSupplier(inboundRtpPadId, supplier);

removeInboundRtpPadStatsSupplier

Removes an inbound RTP pad stats supplier for a given inbound RTP pad ID.

auxCollector.removeInboundRtpPadStatsSupplier(inboundRtpPadId);

addOutboundRtpPadStatsSupplier

Adds an outbound RTP pad stats supplier for a given outbound RTP pad ID.

auxCollector.addOutboundRtpPadStatsSupplier(outboundRtpPadId, supplier);

removeOutboundRtpPadStatsSupplier

Removes an outbound RTP pad stats supplier for a given outbound RTP pad ID.

auxCollector.removeInboundRtpPadStatsSupplier(outboundRtpPadId);

addSctpStreamStatsSupplier

Adds an SCTP stream stats supplier for a given SCTP stream ID.

auxCollector.addSctpStreamStatsSupplier(sctpChannelId, supplier);

removeSctpStreamStatsSupplier

auxCollector.removeSctpStreamStatsSupplier(sctpChannelId);

MediasoupCollector

Interface for Mediasoup collectors.

addWorker

Adds a Mediasoup worker surrogate.

mediasoupCollector.addWorker(worker);

addRouter

Adds a Mediasoup router surrogate.

mediasoupCollector.addRouter(worker);

addTransport

Adds a Mediasoup transport surrogate.

mediasoupCollector.addTransport(worker, internal);

addProducer

Adds a Mediasoup producer surrogate.

mediasoupCollector.addProducer(producer, transportId, internal);

addConsumer

Adds a Mediasoup consumer surrogate.

mediasoupCollector.addConsumer(consumer, transportId, internal);

addDataProducer

Adds a Mediasoup data producer surrogate.

mediasoupCollector.addDataProducer(dataProducer, transportId, internal);

addDataConsumer

Adds a Mediasoup data consumer surrogate.

mediasoupCollector.addDataConsumer(dataConsumer, transportId, internal);

MediasoupCollectorConfig

Configuration options for the MediasoupCollector.

const config: MediasoupCollectorConfig = {
  /**
    * The top level mediasoup object to observe events and monitor.
    */
  mediasoup?: MediasoupSurrogate;

  /**
    * Function to indicate if we want to poll the WebRTC transport stats.
    * Default: false
    */
  pollWebRtcTransportStats?: (transportId: string) => boolean;

  /**
    * Function to indicate if we want to poll the plain RTP transport stats.
    * Default: false
    */
  pollPlainRtpTransportStats?: (transportId: string) => boolean;

  /**
    * Function to indicate if we want to poll the pipe transport stats.
    * Default: false
    */
  pollPipeTransportStats?: (transportId: string) => boolean;

  /**
    * Function to indicate if we want to poll the direct transport stats.
    * Default: false
    */
  pollDirectTransportStats?: (transportId: string) => boolean;

  /**
    * Function to indicate if we want to poll the producer stats.
    * Default: false
    */
  pollProducerStats?: (producerId: string) => boolean;

  /**
    * Function to indicate if we want to poll the consumer stats.
    * Default: false
    */
  pollConsumerStats?: (consumerId: string) => boolean;

  /**
    * Function to indicate if we want to poll the dataProducer stats.
    * Default: false
    */
  pollDataProducerStats?: (dataProducerId: string) => boolean;

  /**
    * Function to indicate if we want to poll the data consumer stats.
    * Default: false
    */
  pollDataConsumerStats?: (dataConsumerId: string) => boolean;
}

Edit this page on GitHub