Search code examples
webrtc

How Chromium WebRTC determines qualityLimitationReason?


In WebRTC stats for RTCOutboundRtpStreamStats, we have the metric qualityLimitationReason.

This metric indicates the reason for degradation in stream quality, and can be one of: "none", "bandwidth", "cpu", "other".

This is useful if we want to understand which resource our app is over-using.

What is the logic the Chromium WebRTC applies to calculate the reason?


Solution

  • As stated in the spec the qualityLimitationReason reports the "most limiting factor" (and if multiple factors exist an order of priority is defined):

    The implementation reports the most limiting factor. If the implementation is not able to determine the most limiting factor because multiple may exist, the reasons MUST be reported in the following order of priority: "bandwidth", "cpu", "other".

    Additionally the spec includes the note:

    The consumption of CPU and bandwidth resources is interdependent and difficult to estimate, making it hard to determine what the "most limiting factor" is. The priority order promoted here is based on the heuristic that "bandwidth" is generally more varying and thus a more likely and more useful signal than "cpu".


    The qualityLimitationReason value is set in the WebRTC Native Code package here:

      bool is_cpu_limited = cpu_counts.resolution_adaptations > 0 ||
                            cpu_counts.num_framerate_reductions > 0;
      bool is_bandwidth_limited = quality_counts.resolution_adaptations > 0 ||
                                  quality_counts.num_framerate_reductions > 0 ||
                                  bw_limited_layers_ || internal_encoder_scaler_;
      if (is_bandwidth_limited) {
        // We may be both CPU limited and bandwidth limited at the same time but
        // there is no way to express this in standardized stats. Heuristically,
        // bandwidth is more likely to be a limiting factor than CPU, and more
        // likely to vary over time, so only when we aren't bandwidth limited do we
        // want to know about our CPU being the bottleneck.
        quality_limitation_reason_tracker_.SetReason(
            QualityLimitationReason::kBandwidth);
      } else if (is_cpu_limited) {
        quality_limitation_reason_tracker_.SetReason(QualityLimitationReason::kCpu);
      } else {
        quality_limitation_reason_tracker_.SetReason(
            QualityLimitationReason::kNone);
      }
    

    As can be seen above, if either of the counters resolution_adaptations or num_framerate_reductions are greater than zero then the stream is considered to be limited - either by CPU (cpu) or bandwidth (bandwidth).

    The respective counter is incremented whenever the resolution is decreased or the framerate is decreased, and vice-versa (decremented) if the resolution/framerate is increased.

    These adaptions are triggered OnResourceUsageStateMeasured(). The ResourceUsageState states if resource overuse or underuse is observed.

    This event can be triggered for a number of different reasons such as thermal constraints (see here) or frame underuse/overuse (see here).

    The above adaption counters (resolution and framerate) are considered to be CPU adaptions, however if either quality scaler resource or bandwidth scaler resource are started then these are also considered to be bandwidth related (see here). Because "bandwidth" is higher priority this will mean the reason will be listed as "bandwidth" in this case.

    For more information on what these scalers do see the QualityScaler and BandwidthQualityScaler class descriptions.

    Additionally if either bw_limited_layers_ or internal_encoder_scaler_ are set then the reason is considered to be "bandwidth" too.

    Otherwise, the reason is set to "none".


    To summarise, in the WebRTC Native Code package, the qualityLimitationReason can be set to one of the following values:

    • bandwidth:
      • This is set if ANY of following are true:
        • Either the quality scaler or bandwidth scaler is started AND either the resolution or framerate has been reduced due to resource overuse
        • Layers were disabled due to low available bandwidth
        • The internal encoder has scaled the result
    • cpu:
      • This is set if both of following are true:
        • "bandwidth" is not considered the reason
        • Either the resolution or framerate has been reduced due to resource overuse
    • none:
      • This is set if none of the above reasons have been observed

    The underlying reason(s) for for the limitation could be down a number factors such as thermal limits, bandwidth constraints, CPU usage or internal encoder scaling.