GithubHelp home page GithubHelp logo

rtcstats's Introduction

rtcstats.js

Low-level logging on peerconnection API calls and periodic getStats calls for analytics/debugging purposes

Integration

Just one simple step: include rtcstats.js before any of your webrtc javascript.

<script src='/path/to/rtcstats.js'></script>

It will transparently modify the RTCPeerConnection objects and start sending data. If you need things like a client or conference identifier to be sent along, the recommended way is to use the legacy peerconnection constraints when constructing your RTCPeerConnection like this:

var pc = new RTCPeerConnection(yourConfiguration, {
  optional: [
    {rtcStatsClientId: "your client identifier"},
    {rtcStatsPeerId: "identifier for the current peer"},
    {rtcStatsConferenceId: "identifier for the conference, e.g. room name"}
  ]
})

If that integration is not possible there is a fallback integration which allows sending per-client information about the user id and conference id. This can be used by calling

trace('identity', null, {user: 'your client identifier',
    conference:'identifier for the conference, e.g. room name'});

Requiring as module

build

in the root directory of the project:

$npm i
...
$npm run dist

this will create the output in ./out/

require

const trace = require("rtcstats/trace-ws")("wss://rtcstats.appear.in"); // url-to-your-websocket-server
require("rtcstats")(
   trace,
   1000, // interval at which getStats will be polled.
   ['', 'webkit', 'moz'] // RTCPeerConnection prefixes to wrap.
);

When using ontop of adapter it is typically not necessary (and potentially harmful) to shim the webkit and moz prefixes in addition to the unprefixed version.

Importing the dumps

The dumps generated can be imported and visualized using this tool

rtcstats's People

Contributors

fippo avatar ggarber avatar janfellner avatar juandebravo avatar kapekost avatar swisspol avatar thepatrick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rtcstats's Issues

update tests/CI

currently the tests are still using an old adapter 4.x. However Chrome now requires disabling the sandbox which is not done in this super old release.

Need to migrate to newer adapter (karma) tests

rtcstats in nightwatch.js

Is it possible to implement rtcstats.js in an automated test using nightwatchs.js? I am trying to get the stats from a WebRTC conference. If so, how do I do it?

Add callback to inject own statistic properties to the statistics

To be able to add own properties to the statistics i would need a callback that is called after getStats before the statistics are handled.
With this approach i can inject own properties from the signalling layer e.g. how many simulcast layers are currently available or which layers have been chosen.

Current implementation i am using, but i am open to any approach offering the same:
https://github.com/JanFellner/rtcstats/tree/feature/enhanced-usage

Changes:
https://github.com/JanFellner/rtcstats/commit/2b4caf937f54b589a46f8e5c3f8191bfeee1a5f4

Uncaught Reference Error: module is not defined

I added the following line to my html:

<script src="rtcstats.js"></script>

However, I get the error "Uncaught Reference Error: module is not defined" in rtcstats.js, specifically this line:

module.exports = function(trace, getStatsInterval, prefixesToWrap) {

track gum with ids

I suspect we need a way to correlate GUM and the GUM callbacks -- some kind of id.

improve timestamp compression

so #83 fixed issues with stats that had old timestamps. But it means we can send a lot of these:
image
i.e. we repeat the timestamp a bit too often.
Would be good to optimize that away again. This might require doing something like setting the timestamp to 0 and then backfilling it from somewhere, e.g. the timestamp added to the getStats call

ip address privacy concerns

@ggarber mentioned there are some concerns exposing and storing ip addresses. I don't think that is a real issue since those addresses are already transmitted via the signaling server (minus any prflx ones) but... storing them might be an issue, especially long-term.

This needs to be removed in any

  • c= line in any SDP
  • a=rtcp line in any SDP
  • a=candidate line in any SDP
  • any onicecandidate / addIceCandidate event
  • getStats

compression of array and object values

currently rtcstats makes the assumption that values are simple types like string or number.
There are two notable exceptions to this:

  • trackIds which is an array
  • qualityLimitationDurations which is an object

For arrays, they should not be transmitted again if they're deeply equal
For objects they should only transmit values that have changes. Unclear how to deal with values that get removed

The following snippet solves the array part which seems like the more important one:

const s1 = {
  foo: {
    trackIds: [ 'RTCMediaStreamTrack_sender_3' ],
    qualityLimitationDurations: {other:0, cpu:0, bandwidth: 2.93, none:0.073},
  },
};

const s2 = {
  foo: {
    trackIds: [ 'RTCMediaStreamTrack_sender_3', 'RTCMediaStreamTrack_sender_4' ],
    qualityLimitationDurations: {other:0, cpu:0, bandwidth: 2.93, none:0.073},
  },
};

const s3 = {
  foo: {
    trackIds: [ 'RTCMediaStreamTrack_sender_3', 'RTCMediaStreamTrack_sender_4' ],
    qualityLimitationDurations: {other:0, cpu:0, bandwidth: 3.00, bogus:0.073},
  },
};

const delta = {
  decompress: function(baseStats, newStats) {
    const timestamp = newStats.timestamp
    delete newStats.timestamp;
    Object.keys(newStats).forEach(id => {
      if (!baseStats[id]) {
        if (newStats[id].timestamp === 0) {
          newStats[id].timestamp = timestamp;
        }
        baseStats[id] = newStats[id];
      } else {
        const report = newStats[id];
        if (report.timestamp === 0) {
            report.timestamp = timestamp;
        } else if (!report.timestamp) {
            report.timestamp = new Date(baseStats[id].timestamp).getTime();
        }
        Object.keys(report).forEach(name => {
          baseStats[id][name] = report[name];
        });
      }
    });
    return baseStats;
  },
  compress: function(baseStats, newStats) {
    Object.keys(newStats).forEach(id => {
      if (!baseStats[id]) {
        return;
      }
      const report = newStats[id];
      Object.keys(report).forEach(name => {
        if (report[name] === baseStats[id][name]) {
          delete newStats[id][name];
        } else if (Array.isArray(report[name])) {
          // Arrays get serialized if anything changed.
          if (JSON.stringify(report[name]) === JSON.stringify(baseStats[id][name])) {
            delete newStats[id][name];
          }
        }
        delete report.timestamp;
        if (Object.keys(report).length === 0) {
          delete newStats[id];
        }
      });
    });
    // TODO: moving the timestamp to the top-level is not compression but...
    newStats.timestamp = new Date();
    return newStats;
  }
};

const c1 = delta.compress({}, s1);
const c2 = delta.compress(c1, s2);
// Should be an array with two objects since this is an array.
console.log('should not compress Array with newly added members (result: array with two)', c2['foo'].trackIds);
//console.log('should compress objects with the same values (result: undefined)', c2['foo'].qualityLimitationDurations);

const c3 = delta.compress(c2, s3);
console.log('should compress Array with same members (result: undefined)', c3['foo'].trackIds);
//console.log('should compress objects with different values (result: undefined)', c3['foo'].qualityLimitationDurations);

const u1 = delta.decompress({}, c1);
const u2 = delta.decompress(u1, c2);
console.log('should decompress Array with newly added members (result: array with two)', u2['foo'].trackIds);
//console.log('should decompress objects with same values (result: object with four values)', u2['foo'].qualityLimitationDurations);
const u3 = delta.decompress(u2, c3);
console.log('should decompress Array with old members (result: array with two)', u3['foo'].trackIds);

by adding an Array.isArray check which does a naive full-json comparison.

add message compression

from #18: lets also compress this, either using lzstring or a using a custom name mapping. Most likely lzstring which adds ~4kb download is the best solution.

Clarify expected behavior in README

After reading the README, it's not clear to me where the stats will appear...in the browser console, I guessed. To test this, I did:

  1. Downloaded rtcstats.js
  2. Uploaded it to the same folder where my verto js lib files are
  3. Made this the first script execution in my test page: <script src="../js/rtcstats.js"></script>
  4. Made a test call and monitored the browser console

The call went fine (in Chrome72/incognito/Win10), but I didn't see anything new once the peer must have gotten to ice connection state "completed", nor after hangup.

I would expect that I could pass a callback, probably as a listener to iceconnectionstatechange, and that I could inspect the collected, periodic stats that way. If you would explain a bit what to expect, I'll submit a PR for the README to help clarify. Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.