← View all posts
August 6, 2018

isRemote in getStats() will disappear in Firefox 65

Contributed by Jan-Ivar Bruaroey,

Are you using getStats() for remote statistics in Firefox? Look for this warning today in Firefox Nightly (63, not 65):

⚠ Detected soon-to-break getStats() use! stat.isRemote goes away in Firefox 65, but won’t warn there!

TL;DR: If you see this warning in web console, read on to act now. Firefox 65 will move remote stats to "remote-outbound-rtp" and "remote-inbound-rtp", and isRemote will disappear, to comply with a change to the spec.

Firefox 63 and 64 will warn about this, but for technical reasons Firefox 65 will not be able to. This is because once the stats move in 65, there’s really no way to detect that you intended to look for remote stats the old way.

Here’s a an example of bad isRemote usage that triggers this warning in Firefox Nightly (open the web console to see the warning).

What is one to do? Prepare today! There’s already a safe, spec-supported way to access remote stats in Firefox that won’t break in Firefox 65: Use remoteId to cross-reference remote stats from local stats:

Use remoteId safely today

Access remote stats the way we’ve demonstrated in two blog posts last year, using remoteId:

      const stats = await pc.getStats();
      for (const stat of stats.values()) {
        if (stat.isRemote) continue;
        switch (stat.type) {
          case "outbound-rtp": {
            console.log("Sent " + stat.bytesSent);
            const remote = stats.get(stat.remoteId); // <-- Like this!
            if (remote) console.log("Other side " + remote.bytesReceived);
            break;
          }
          case "inbound-rtp": {
            console.log("Received " + stat.bytesReceived);
            const remote = stats.get(stat.remoteId); // <-- Like this!
            if (remote) console.log("Other side " + remote.bytesSent);
            break;
          }
       }

This code enumerates local stats, and finds the corresponding remote stat at the same time, using the remoteId cross-reference.This is just as fast as other ways of obtaining this information, as it merely cross-references into the same already-returned RTCStatsReport object.

Organizationally, this keeps related data together, and this approach will continue to work today, tomorrow in Firefox 65, and beyond. It should also work in Chrome once it supports remote stats in its spec API (it doesn’t today).

But…

Look carefully, and you’ll see we’re still using isRemote above in one place! Specifically:

      if (stat.isRemote) continue;

This is not a mistake. This is needed for compatibility, or we’d mistake remote stats for local stats in today’s browsers, where they’re listed under the same type. This will continue to work in Firefox 65 where isRemote will be undefined, because that works out to the same as false in that if-statement.

The warnings in Nightly are clever enough not to trip over this use. Instead, they trigger on any access of actual remote statistics, if it hasn’t seen use of .get(remoteId) first.

Don’t be like this:

The other way to read remote stats today is to check isRemote for true. This will break in Firefox 65:

      const stats = await pc.getStats();
      for (const stat of stats.values()) {
        switch (stat.type) {
          case "outbound-rtp": {
            if (stat.isRemote) {                           // always undefined!
              console.log("Other side " + stat.bytesSent); // never runs!
            } else {
              console.log("Sent " + stat.bytesSent);       // wrong!
            }
            break;
          }
          case "inbound-rtp": {
            if (stat.isRemote) {                               // always undefined!
              console.log("Other side " + stat.bytesReceived); // will never run!
            } else {
              console.log("Received " + stat.bytesReceived);   // wrong!
            }
            break;
          }
       }

In the future:

For completeness, we should mention that once Firefox 65 is out, you could also write the following, but it won’t work in older versions, obviously, because "remote-inbound-rtp" and "remote-outbound-rtp" won’t exist in those browsers:

      const stats = await pc.getStats();
      for (const stat of stats.values()) {
        switch (stat.type) {
          case "outbound-rtp": {
            console.log("Sent " + stat.bytesSent);
            break;
          }
          case "remote-inbound-rtp": {
            console.log("Other side " + stat.bytesReceived);
            break;
          }
          case "inbound-rtp": {
            console.log("Received " + stat.bytesReceived);
            break;
          }
          case "remote-outbound-rtp": {
            console.log("Other side " + stat.bytesSent);
            break;
          }
       }

In addition to not working in older browsers, this approach has other downsides: According to the spec, stats may appear in any order, which means this example might print the log statements in any order, and not grouped together logically. For these two reasons, we recommend you stick with the remoteId example. In the future, should you at some point no longer care about older versions, you can simply drop the following line from it:

      if (stat.isRemote) continue;

Working Good Example

Here’s the remoteId approach again in a working example. Hit the “Result” tab to see it in action:

If your stats code looks substantially different from what’s shown here, we highly recommend these previous blog posts on aligning with the spec on getStats(), and using await with WebRTC.

Remember,

remoteId good πŸ‘, isRemote bad πŸ‘Ž

Happy stats gathering!

 

PS: RTCIceCandidateStats

There’s also an isRemote member in RTCIceCandidateStats. It remains unaffected by all this.

 

Tags