callstats.js

The callstats.io's Javascript client library enables performance monitoring features in browser-based WebRTC endpoints. The communication with the callstats.io backend occurs over Secure HTTP (https://) and Secure WebSocket (wss://). The endpoint (the browser in this case) MUST support WebSockets. Additionally, the origin server MUST allow Cross-Origin Resource Sharing (CORS) and MAY need to serve its own pages over HTTPS to avoid mixed content warnings.

Everything in the callstats.js is scoped under the callstats namespace.

    var callstats = new callstats();

Versioning

callstats.js uses semantic versioning. The current version is: v1.0.0

    console.log("CallStats version: %o",callstats.version); 

API

callstats.initialize(): authenticates with the callstats.io backend to setup a trusted relationship with it. See integration section for details on when to call this API.

Parameters:

  • AppID: of type String. It is obtained from callstats.io backend; discussed in a later section.

  • AppSecret: of type String. It is obtained from callstats.io backend; discussed in a later section.

  • userID: of type String, maximum length 256 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

  • initCallback: providing a callback function is OPTIONAL, the callback asynchronously reports failure or success. See Callback and Error Handling section below.


callstats.AddNewFabric(): indicates that the WebRTC application intends to monitor the performance of the PeerConnection between the two endpoints (represented by the corresponding UserIDs). See integration section for details on when to call this API.

Parameters:

  • pcObject: pass the PeerConnection object created after invoking RTCPeerConnection().

  • remoteUserID: of type String, maximum length 256 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

  • fabricUsage: an Enumeration, with the following valid values video, audio, data, multiplex. When using a single PeerConnection for sending and receiving audio and video, application MUST use multiplex.

  • conferenceID: of type String, maximum length 512 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.

  • pcCallback: providing a callback function is OPTIONAL, the callback asynchronously reports failure or success. See Callback and Error Handling section below.


callstats.sendFabricEvent(): notifies the backend about events (e.g., 'Hold', 'Mute', etc.) on a PeerConnection. It is usually generated due to local user interaction at a PeerConnection.

Parameters:

  • pcObject: pass the PeerConnection object associated with the fabricEvent.

  • fabricEvent: an Enumeration, with valid values discussed in a later section.

  • conferenceID: of type String, maximum length 512 bytes. It is generated by the origin server and MUST NOT be null or empty; discussed in a later section.


Enumeration of fabricUsage

  • audio: describes an audio-only PeerConnection.

  • video: describes a video-only PeerConnection.

  • data: describes a PeerConnection with only DataChannels.

  • multiplex: describes a PeerConnection carrying at least two media types, typically Audio and Video, perhaps even DataChannels.

Currently monitoring DATA traffic is NOT SUPPORTED, because the browser does not yet implement any DataChannel statistics.


Enumeration of fabricEvent

  • fabricSetup: The PeerConnection is set up successfully and the endpoint is ready to send and receive media. Performance measurement is started.

  • fabricSetupFailed: The PeerConnection failed to set up communication between the two endpoints.

  • fabricHold: The PeerConnection is currently not sending and receiving any media, but the connection is still active.

  • fabricResume: The PeerConnection is resuming communication with the remote endpoint.

  • audioMute: The PeerConnection is currently not sending any Audio, but MAY be sending video.

  • audioUnmute: The PeerConnection is resuming Audio communication.

  • videoPause: The PeerConnection is currently not sending any Video, but MAY be sending audio.

  • videoResume: The PeerConnection is resuming Video communication.

  • fabricTerminated: The PeerConnection is destroyed and is no longer sending or receiving any media.


Callback and Error Handling

callstats.js uses a callback function to report different success and failure cases, they can occur during initialize() or sending measurements to the callstats.io backend. The callback takes the form of:

1     function callback(csError, csErrMsg) {
2       console.log("Status: errCode= " + csError + " errMsg= " + csErrMsg ); }
3     }

csError and csErrMsg are of type String. csErrMsg is a descriptive error returned by the callstats.io backend or the jQuery library.

csError Types

  • httpError: HTTP error, the csErrMsg string is reported by jQuery.ajax().

  • authError: Authentication failed, AppID or AppSecret is incorrect.

  • wsChannelFailure: Connection failed, could not connect to callstats.io over WebSockets.

  • csProtoError: the backend rejects the fabricEvent or the statistics because the callstats.js is sending malformed messages. This may happen due to a change in the metrics or formatting of the current statistics API implemented by the browser.

  • success: the backend has accepted the request and the endpoint is authenticated, or capable of sending measurement data.


Integration Steps

Preparing the Origin Server

The following steps need to be completed before integrating callstats.js into a WebRTC application.

callstats.js depends on other common libraries that SHOULD be included in the HEAD tag. No need to include them again if your web application already uses them.

  <script src="/js/jquery.min.js" />
  <script src="/socket.io/socket.io.js" />

Getting the AppID and AppSecret

These are generated by callstats.io backend when registering a new WebRTC application.

Generating the userID

The userID is expected to be unique, and the max length is 256 bytes. It is used by the callstats.io backend to distinguish between different endpoints. The userIDs generated by the origin server and therefore the origin server decides if these identifiers are ephemeral or actual usernames. Typically, if the same user joins the conference via multiple means (devices or browsers) at the same time, the origin server MAY use the same userID. If the userID changes, the app MUST call initialize() again.

The callstats.io backend treats userIDs as opaque identifiers, the origin server MAY choose to pass the same identifiers as it is using or send a SHA1 hash of the username@domain instead (where the username and domain are the ones used by the origin server).

Reusing the userID across sessions facilitates the callstats.io backend to measure consistency of the endpoint across sessions and additionally helps the the WebRTC application developer identify under-performing or misbehaving devices.

Generating the conferenceID

The conferenceID is a unique call identifier to associate all userIDs in a conference. Therefore, all participants in a common call MUST use the same conferenceID. It is also generated by the origin server and MUST be temporally unique (i.e., for the duration of the call), the origin server MAY reuse the conferenceID identifier again for separate conferences at a later time, after the previous call using it has ended. The maximum length of the conferenceID is 512 bytes.

Like userIDs, the callstats.io backend treats conferenceIDs as opaque identifiers, the origin server MAY use the same identifier as the one generated by the conference bridge, or use the URL of the page where the WebRTC call is taking place (e.g., www.example.com/username), concatenate current timestamp with a random number, or pass a SHA1 hash of one of the above schemes.

The origin server MAY reuse the userID within the same conference call, i.e., two or more endpoints report using the same userID and conferenceID. While this is NOT RECOMMENDED, the callstats.io will still attempt to distinguish these userIDs as distinct entities.

Authentication

callstats.io offers two authentication methods:

  • Basic over HTTPS (requires only client implementation)
  • OAuth (requires changes in both the client and origin server).

Basic Authentication over HTTPS

The application requires an AppID and AppSecret to authenticate with the callstats.io backend. The origin server is expected to pass the userID for each endpoint in a WebRTC call. The callstats.js internally implements a 4-way handshake, comprising of the following steps request-challenge- response-success/failure. If successful, the callstats.js generates a token valid for 2 hours. The token is subsequently used by the callstats.js to send event and measurement data to the callstats callstats.io.

OAuth

Instead of relying only on the endpoint for authentication, the callstats.io also implements OAuth, which requires the origin server to handle the challenge-response step of the authentication setup instead of the endpoint.

Details TBD.


Integrating with your SDK

Step 1: Include JS

Add the callstats.js in the HEAD tag. Currently, callstats.js depends on async.js and sha.js, they MUST be included as well.

1     <script src="https://dashboard.callstats.io/static/js/sha.js"> </script>
2     <script src="https://dashboard.callstats.io/static/js/async.js"> </script>
3     <script src="https://dashboard.callstats.io/api/callstats.js"> </script>

Update: A minimized version will be released shortly.

Step 2: Initialize()

After the user is authenticated with the origin server (or when the page loads), call initialize() with appropriate parameters (see API section). Check the callback for errors. If the authentication succeeds, callstats.js will receive an appropriate authentication token to make subsequent API calls.

 1     var callstats = new callstats();
 2     var AppID = "YOUR APPLICATION ID";
 3     var AppSecret = "YOUR APPLICATION SECRET";
 4 
 5     function initCallback (err, msg) {
 6       console.log("Initializing Status: err="+err+" msg="+msg);
 7     }
 8 
 9     //userID is generated or given by the origin server
10     callstats.initialize(AppID, AppSecret, userID, initCallback);

Step 3: AddNewFabric()

When creating a PeerConnection, call callstats.AddNewFabric() with appropriate parameters (see API section). It is important to make the request only after the PeerConnection is created. The PeerConnection object MUST NOT be "undefined" because callstats.js uses getStats() to query the metrics from the browser internals. The earliest an application is able to call AddNewFabric() is when it receives the onnegotiationneeded event is fired by the WebRTC API.

 1     var pc_config = {"iceServers": [{url: "stun:stun.example.org:3478"}]};
 2     var pc = new RTCPeerConnection(pc_config);
 3 
 4     function pcCallback (err, msg) {
 5       console.log("Monitoring status: "+ err + " msg: " + msg);
 6     };
 7 
 8     //remote_user_id is the recipient's userID
 9     //conferenceID is generated or provided by the origin server (webrtc service)
10 
11     // let the "negotiationneeded" event trigger offer generation
12     pc.onnegotiationneeded = function () {
13       // pc is created, tell the callstats.js about it
14       callstats.addNewFabric(pc, remote_user_id, conferenceID, pcCallback);
15 
16       // pick a fabricUsage enumeration, if sending audio and video use multiplex
17       var usage = callstats.fabricUsage.multiplex;
18       callstats.addNewFabric(pc, receiver, usage, confID, pcCallback);
19 
20       // create offer
21       pc.createOffer(localDescCreated, logError);
22     }

It also uses the event as the initial timestamp to calculate the establishment time. Subsequently, when a fabricSetupFailed or fabricSetup event is fired, the difference between the timestamps gives the establishment time.

In any WebRTC endpoint, where multiple PeerConnections are created between each participant (e.g., audio and video sent over different PeerConnections or a mesh call), the addNewFabric() MUST be called for each PeerConnection.

Step 4: Events

Send the appropriate fabricEvent via sendFabricEvent().

  • send fabricSetup after onaddstream event is fired by the WebRTC API and the endpoint starts to render media. callstats.js expects both local and remote endpoints to generate this event. After this event is fired, the callstats.js begins performance monitoring and sending data to the callstats.io backend.

  • send fabricFailed when a call fails to connect to the remote peer or to the conferencing server. For example, failing to traverse a NAT or middlebox (ICE failure). This event MUST be reported by a local endpoint when the call fails without engaging the remote endpoint. In cases where the call fails after signaling to the remote endpoint succeeds, each endpoint MUST report the event independently.

  • send fabricTerminated when an endpoint or participant disconnects from the conference, it notifies the callstats.js to stop monitoring the local PeerConnection. Depending on the implementation of the Hangup() method in WebRTC (may have to rely on signaling), the remote endpoint sends a fabricTerminated event before destroying its local PeerConnection object. The callstats.io backend monitors each PeerConnection in real-time, but generates summary statistics when the participant leaves. The statistics are aggregated for conference when all participants leave. If no fabricTerminated event is received, the callstats.io backend will summarize and aggregate the statistics 120 seconds after the last measurement for a conference is received.

Integration Progress

After creating an AppID, the https://dashboard.callstats.io/newapp helps you integrate callstats.js into your web application. It reports if any of the APIs have been invoked correctly.


Dashboard

The dashboard is a work in progress, more details to come.


Known Issues


Change Log

March 02, 2014: v1.1.0

  • Aligned the protocol and encoding to the callstats.io backend

January 16, 2014: v1.0.0

  • First Public Version.

  • Added initialize(), AddNewFabric(), sendFabricEvent() API.

  • Added fabricUsage and fabricEvent enumerations.

  • Added error handling.

  • Added definitions for us erID and conferenceID variables.

  • Added Integration Steps.

  • Added explicit reference to SHA.js. [Jan 30]

  • Added max length for userID (256 bytes) and conferenceID (512 bytes). [Jan 31]

  • Clarified definitions of fabricEvents. [Feb 03]


Support

Markdown friendly version is available on our Github. If you find any errors or bugs, post the issues directly on Github.

As the WebRTC matures more fabricEvents will be added. In the meantime, if you have comments or have new feature requests, join the discussion on the mailing list or drop us an email.