npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vonage/video-realtime-stats

v0.1.3

Published

Library to add real-time stats to your Vonage Video application

Downloads

53

Readme

Vonage Video API - Real Time Stats

This library provides a wrapper built on top of getRtcStatsReport API. The library exposes some methods and fires some events upon high packet loss or when the resolution is limited. For now, it only provides data on the publisher, but the subscribers may follow in the future.

Limitations/Known issues

  • The field qualityLimitationReason (https://developer.mozilla.org/en-US/docs/Web/API/RTCOutboundRtpStreamStats/qualityLimitationReason) does not exist on Firefox. This means that the qualityLimited event won't fire up in Firefox.

  • If you try to publish 1280X720 resolution and there are no users subscribing to your stream, the Vonage Media Server will intentionally limit the quality that you can send to avoid a waste of resources. This would trigger the qualityLimited event immediately. You can consider setting the stats.on('qualityLimited', handler) event listener only when there are more than 2 connections in the call or do a subscribers check on the callback function.

stats.on('qualityLimited', ()=> if (subscribers > 0) updateUI)

Prerequisites

Installation

NPM

You can install directly from npm.

npm install

Using this method, you can import vonage-real-time-stats like so:

import * as VideoStats from '@vonage/video-realtime-stats';

Script tag

You can also copy vonage-real-time-stats.js from the dist/build folder and include it directly in your web app using a <script> tag.

<script src="https://my-server-path/vonage-real-time-stats.js"></script>

Using this method, vonage-real-time-stats.js will set a browser global:

const VideoNetworkQualityStats = OT.RealTimeStats;

Build the library locally

You can build the library locally following these steps:

  1. npm install
  2. npm run build-umd
  3. cd sample-app and npm install. The app server will start on port 3000

VideoNetworkQualityStats

The VideoNetworkQualityStats initialises the library. The constructor has the following options:

| Option | Type | Required | Description | | ------------------------ | ------ | -------- | ----------------------------------------------------------------------------- | | intervalStats | Number | Yes | The interval at which get stats will be called in milleseconds (default 5000) | | VideoPacketLossThreshold | Number | Yes | The threshold value for video packet loss in percentage (default 5%) |

Example:

const stats = new VideoNetworkQualityStats({
  intervalStats: 3000,
  VideoPacketLossThreshold: 5,
});

Methods

setPublisher: This method sets the publisher

stats.setPublisher(publisher);

startStats: This method starts the stats interval

stats
  .startStats()
  .then(() => console.log('stats started'))
  .catch((e) => console.log(e));

stopStats: This method stops the stats interval

stats.stopStats();

getCipher: This method returns the srtp cipher used by the publisher stream

stats.getCipher().then((srtpCipher) => console.log(srtpCipher));

getMediaTransportType: This method returns the connection type (TURN-tls, TURN-tcp, TURN-upd, UDP)

stats
  .getMediaTransportType()
  .then((connectionType) => console.log(connectionType));

getSimulcastLayers: This method returns the simulcast layers used by the publisher. Simulcast is a publisher property that, in supported endpoints, allows the publisher to send several quality layers so that the media server can decide which one to forward to every subscriber depending on their network conditions. Depending on the resolution that you set when you initialise the publisher and your network conditions, you can see up to 3 different quality layers, containing the fps, width and height qualityLimitationReason, and id and an accumulator for the bytesSent. If the endpoint is non-simulcast capable or the API key does not have simulcast enabled, the publisher will only send one quality layer. This method will therefore return one single layer.

const simulcastLayers = stats.getSimulcastLayers();
console.log(simulcastLayers);

Events

Events in stats

qualityLimited: This event fires when the resolution of the publisher is limited due to bandwidth or CPU.The event contains the reason, the streamId and the current resolution of the publisher

stats.on('qualityLimited', (event) => {
  //console.log(`The quality of stream ${event.streamId} is limited due to ${event.reason}. Your current resolution is ${event.currentResolution}`)
  //Update user interface letting the user know that the resolution they are sending is limited
});

qualityLimitedStopped: This event fires when the resolution of the publisher is no longer limited due to bandwidth or CPU.

stats.on('qualityLimitedStopped', (event) => {
  //console.log(`The quality of stream ${event.streamId} is no longer limited due to ${event.reason}.
  //Update user interface letting the user know that the resolution they are sending is no longer limited
});

highPacketLoss: This event fires when the video packet loss reaches the threshold configured when initialising the stats object.

stats.on('highPacketLoss', (event) => {
  //console.log(`Packet loss over ${event.packetLossThreshold}% detected in stream ${event.streamId}`).
  //Update user interface letting the user know that they are having packet loss
});

highPacketLossStopped: This event fires when there was packet loss and now the packet loss value does not reach the threshold

stats.on('highPacketLossStopped', (event) => {
  //console.log(`Packet loss is now below ${event.packetLossThreshold}%  in stream ${event.streamId}`).
  //Update user interface letting the user know that they are no longer having packet loss
});

Example

const { VideoNetworkQualityStats } = OT.RealTimeStats;

const stats = new VideoNetworkQualityStats({
  intervalStats: 3000,
  VideoPacketLossThreshold: 5,
});

async function publishToSession() {
  // Create the publisher and publish into the session
  let publisher = OT.initPublisher(
    'publisher',
    {
      width: 640,
      height: 480,
      publishAudio: false,
      publishVideo: true,
      insertMode: 'append',
    },
    (err) => {
      if (err) console.error('Error publishing:', err);
      else {
        console.log('Publisher Created');
      }
    }
  );
  const session = OT.initSession(apikey, sessionId);
  session.on('streamCreated', (stream) => {
    session.subscribe(stream, (err) => {
      if (err) console.error('Error while subscribing', err);
      else console.log('Subscribed to ', stream);
    });
  });

  session.connect(token, (err) => {
    if (err) {
      console.error('Error while connecting to the session falling', err);
      return;
    }
    console.log('Session Connected');

    session.publish(publisher, (errPublisher) => {
      if (errPublisher)
        console.error('Error while publishing into the session', errPublisher);
      else {
        stats.setPublisher(publisher);
        stats
          .startStats()
          .then(() => {
            stats.on('qualityLimited', (event) => {
              //Update user interface
              openToast(
                'quality',
                'The quality of your video is limited',
                'show'
              );
            });
            stats.on('qualityLimitedStopped', (event) => {
              // Update user interface
              openToast(
                'quality',
                'The quality of your video is limited',
                'hide'
              );
              console.log(event);
            });
            stats.on('highPacketLoss', (event) => {
              //Update user interface
              openToast('packetLoss', 'You may face quality issues', 'show');
            });
            stats.on('highPacketLossStopped', (event) => {
              //Update user interface
              openToast('packetLoss', 'You may face quality issues', 'hide');
            });

            stats.getCipher().then((srtpCipher) => console.log(srtpCipher));
            stats
              .getConnectionType()
              .then((connectionType) => console.log(connectionType));
          })
          .catch((e) => console.log(e));
      }
    });
  });
}

publishToSession();