W3C home > Mailing lists > Public > public-webrtc@w3.org > January 2013

Integration of Stats API v2

From: Adam Bergkvist <adam.bergkvist@ericsson.com>
Date: Wed, 23 Jan 2013 11:44:19 +0100
Message-ID: <50FFBF03.50509@ericsson.com>
To: "public-webrtc@w3.org" <public-webrtc@w3.org>
Hi

I'm currently working on putting version 2 of the stats into the spec as 
decided on the last telco. Overall I think this works, but always 
getting objects by id makes the code more complicated. There are 
situations where ids are needed (e.g., to correlate stats objects 
between getStats() calls), but I think we should get objects directly 
when possible.

Some comments:

The current approach to gathering stats is to gather all possible kinds 
of stats for a chosen selector and then, after you get the report and 
the stats objects, pick the interesting parts. (I know that Ekr 
commented this on the last telco.)

I propose we do the filtering at getStats()-time instead of after the 
report is created. The result would be more conservative stats gathering 
and smaller reports.

void getStats (MediaStreamTrack? selector,
                RTCStatsCategory[]? categories,
                RTCStatsCallback successCallback,
                RTCPeerConnectionErrorCallback failureCallback);

// names taken from the stats dictionaries in the proposal
enum RTCStatsCategory {
     "rtp-stream",
     "outgoing-rtp-stream",
     "incoming-rtp-stream",
     "incoming-local-rtp-stream",
     "rtp-session",
     "candidate",
     "candidate-pair"
     // ...
};


The same enum would also be reused as argument values the objects() method.

 > interface RTCStatsReport {
 >   sequence<DOMString> objects(DOMString type?);
 >   RTCStatsObject get(DOMString id);
 > }

 > interface RTCStatsObject {
 >    ...
 >    readonly DOMString id;
 >    ...
 > };

It's not obvious what the objects() method returns; the name suggests 
stat objcets but the return value is a sequence of DOMStrings. From the 
example it seems like it returns ids. This seems a bit complicated. Why 
not let it return a sequence of RTCStatObjects (of a certain type) 
directly as the name implies instead of requiring detour with ids and get().

var statsObjects = report.objects("rtp-stream");

A corresponding stats object from a later report (for the first object) 
would then be retrieved with:

secondReport.get(statsObjects[0].id);

So from what I understand, the id links stats objects that correspond to 
the same selector sub-component for a specific stats category between 
reports. For example, sub component=SSRC when selector=MediaStreamTrack 
and category=rtp-stream. This makes sense since it isn't practical to 
use indexes if the number of stats objects differs between the first and 
the second report.

Could we have a name that emphasizes the difference between this id and 
ids on MediaStream and MediaStreamTrack? I.e. that two objects with the 
same id aren't the same object, instedad they are results of reporting 
stats from the same underlying component. E.g. sourceId, componentId, 
providerId or something.

 > In order to have a well known syntax for RTCStats objects, we use
 > Dictionary declarations. This does NOT mean that an RTCStatsObject is
 > or contains a dictionary; due to implementation issues, we still have
 > only the names() and getValue functions as interfaces to the
 > RTCStatsObject.

I'm not sure it's good idea to take a syntax that is well defined is 
this context and say that it means something else. I think the described 
dictionaries looks good and it would be more straight forward to use 
them as dictionaries (and update implementations to support this). 
RTCStatsObject could also be a dictionary since the two methods would 
become redundant (names() is replaced by property enumeration and 
getValue() by direct property access). This would also flatten each 
level of the stats structure a bit and make it easier to use.

dictionary RTCStatsObject {
     readonly attribute long timestamp;
     readonly DOMString type;
     readonly DOMString id;
};

dictionary RTPStream : RTCStatsObject {
     int ssrc;
     int? maxBandwidth; // as specified by user, if present
     ...
}
...

 > dictionary RTPStream {
 >     ...
 >     StatsObjectID? otherEndStats; // Reference to the stats signalled
 >                                   // from our partner.
 >     ...
 > }

What's the reason for having an id here and not referencing the 
otherEndStats directly? Can these stats be found via the object() method 
as well?

 > interface RTCStatsObject {
 >     readonly attribute long timestamp;
 >     ...

We should use DOMTimeStamp here as defined by WebIDL [1].

============================================================

The changes proposed above would make the API a bit easier to use by 
working directly with objcets and with less "get by id" operations.

(new example)
pc.getStats(selector, ["rtp-stream"], ...);

// proccess stats
var objects = secondReport.objects();
for (i = 0; i < objects.length; i++) {
     second = objects[i];
     // get the corresponding stats object from the first report
     first = firstReport.get(second.id);

     if (first && first.remote) {
         var packetsSent = first.packetsSsent - second.packetsSent;
         var packetsReceived = first.remote.packetsReceived -
                 second.remote.packetsReceived;

         // if fractionLost is > 0.3, we have probably found the culprit
         var fractionLost = (packetsSent - packetsReceived) /
                 packetsSent;
     }
}

------------------------------------------------------------

(existing example)
pc.getStats(selector, ...);

// proccess stats
var ssrcIds = now.objects("RTPStream");
for (i = 0; i < ssrcIds.length; i++) {
     var ssrcStatsId = ssrcIds[i];
     nowState = now.get(ssrcStatsId);
     prevState = baseline.get(ssrcStatsId);
     remoteStatsId = nowstate.get("otherEndStats");
     remoteNowState = now.get(remoteStatsId);
     remotePrevState = baseline.get(remoteStatsId);

     if (prevstate && remotePrevState) {
         var packetsSent = nowstate.get(packetsSent)
                 - prevstate.get(packetsSent);
         var packetsReceived = remoteNowState.get(packetsReceived)
                 - remotePrevState.get(packetsReceived);

         // if fractionLost is > 0.3, we have probably found the culprit
         var fractionLost = (packetsSent - packetsReceived) /
                 packetsSent;
     }
}


/Adam

[1] http://dev.w3.org/2006/webapi/WebIDL/#common-DOMTimeStamp
Received on Wednesday, 23 January 2013 10:44:43 UTC

This archive was generated by hypermail 2.3.1 : Monday, 23 October 2017 15:19:32 UTC