Populate qualityLimitationDurations stats for outbound RTP streams

Spec: https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-qualitylimitationdurations
Tested in chromium using wpt/webrtc-stats.

Bug: webrtc:10686
Change-Id: I05ac344e6caa7a663675de4c06ccfd17e1efb6ee
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219300
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34179}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index 60ff8c2..fe6d658 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -13,6 +13,7 @@
 
 #include <stdint.h>
 
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -542,10 +543,8 @@
   // implement it for audio as well.
   RTCStatsMember<double> total_packet_send_delay;
   // Enum type RTCQualityLimitationReason
-  // TODO(https://crbug.com/webrtc/10686): Also expose
-  // qualityLimitationDurations. Requires RTCStatsMember support for
-  // "record<DOMString, double>", see https://crbug.com/webrtc/10685.
   RTCStatsMember<std::string> quality_limitation_reason;
+  RTCStatsMember<std::map<std::string, double>> quality_limitation_durations;
   // https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-qualitylimitationresolutionchanges
   RTCStatsMember<uint32_t> quality_limitation_resolution_changes;
   // https://henbos.github.io/webrtc-provisional-stats/#dom-rtcoutboundrtpstreamstats-contenttype
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index f3a94b0..d7b7ba7 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -265,6 +265,17 @@
   RTC_CHECK_NOTREACHED();
 }
 
+std::map<std::string, double>
+QualityLimitationDurationToRTCQualityLimitationDuration(
+    std::map<webrtc::QualityLimitationReason, int64_t> durations_ms) {
+  std::map<std::string, double> result;
+  for (const auto& elem : durations_ms) {
+    result[QualityLimitationReasonToRTCQualityLimitationReason(elem.first)] =
+        elem.second;
+  }
+  return result;
+}
+
 double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
   RTC_DCHECK_GE(audio_level, 0);
   RTC_DCHECK_LE(audio_level, 32767);
@@ -568,6 +579,9 @@
   outbound_video->quality_limitation_reason =
       QualityLimitationReasonToRTCQualityLimitationReason(
           video_sender_info.quality_limitation_reason);
+  outbound_video->quality_limitation_durations =
+      QualityLimitationDurationToRTCQualityLimitationDuration(
+          video_sender_info.quality_limitation_durations_ms);
   outbound_video->quality_limitation_resolution_changes =
       video_sender_info.quality_limitation_resolution_changes;
   // TODO(https://crbug.com/webrtc/10529): When info's |content_info| is
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index def98d4..92f7377 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -2199,6 +2199,8 @@
   video_media_info.senders[0].total_packet_send_delay_ms = 10000;
   video_media_info.senders[0].quality_limitation_reason =
       QualityLimitationReason::kBandwidth;
+  video_media_info.senders[0].quality_limitation_durations_ms
+      [webrtc::QualityLimitationReason::kBandwidth] = 300;
   video_media_info.senders[0].quality_limitation_resolution_changes = 56u;
   video_media_info.senders[0].qp_sum = absl::nullopt;
   video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
@@ -2254,6 +2256,9 @@
   expected_video.total_encoded_bytes_target = 1234;
   expected_video.total_packet_send_delay = 10.0;
   expected_video.quality_limitation_reason = "bandwidth";
+  expected_video.quality_limitation_durations = std::map<std::string, double>{
+      std::pair<std::string, double>{"bandwidth", 300.0},
+  };
   expected_video.quality_limitation_resolution_changes = 56u;
   expected_video.frame_width = 200u;
   expected_video.frame_height = 100u;
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index d92e7ff..032cbe9 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -973,6 +973,8 @@
       verifier.TestMemberIsNonNegative<double>(
           outbound_stream.total_packet_send_delay);
       verifier.TestMemberIsDefined(outbound_stream.quality_limitation_reason);
+      verifier.TestMemberIsDefined(
+          outbound_stream.quality_limitation_durations);
       verifier.TestMemberIsNonNegative<uint32_t>(
           outbound_stream.quality_limitation_resolution_changes);
       // The integration test is not set up to test screen share; don't require
@@ -1006,6 +1008,8 @@
       verifier.TestMemberIsUndefined(outbound_stream.total_packet_send_delay);
       verifier.TestMemberIsUndefined(outbound_stream.quality_limitation_reason);
       verifier.TestMemberIsUndefined(
+          outbound_stream.quality_limitation_durations);
+      verifier.TestMemberIsUndefined(
           outbound_stream.quality_limitation_resolution_changes);
       verifier.TestMemberIsUndefined(outbound_stream.content_type);
       // TODO(hbos): Implement for audio as well.
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index dcd2aeb..0db833c 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -811,6 +811,7 @@
     &huge_frames_sent,
     &total_packet_send_delay,
     &quality_limitation_reason,
+    &quality_limitation_durations,
     &quality_limitation_resolution_changes,
     &content_type,
     &encoder_implementation,
@@ -847,6 +848,7 @@
       huge_frames_sent("hugeFramesSent"),
       total_packet_send_delay("totalPacketSendDelay"),
       quality_limitation_reason("qualityLimitationReason"),
+      quality_limitation_durations("qualityLimitationDurations"),
       quality_limitation_resolution_changes(
           "qualityLimitationResolutionChanges"),
       content_type("contentType"),
@@ -879,6 +881,7 @@
       huge_frames_sent(other.huge_frames_sent),
       total_packet_send_delay(other.total_packet_send_delay),
       quality_limitation_reason(other.quality_limitation_reason),
+      quality_limitation_durations(other.quality_limitation_durations),
       quality_limitation_resolution_changes(
           other.quality_limitation_resolution_changes),
       content_type(other.content_type),