Home | History | Annotate | Download | only in media
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/media/webrtc_browsertest_perf.h"
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "base/values.h"
      9 #include "chrome/test/base/in_process_browser_test.h"
     10 #include "testing/perf/perf_test.h"
     11 
     12 static std::string Statistic(const std::string& statistic,
     13                              const std::string& bucket) {
     14   // A ssrc stats key will be on the form stats.<bucket>-<key>.values.
     15   // This will give a json "path" which will dig into the time series for the
     16   // specified statistic. Buckets can be for instance ssrc_1212344, bweforvideo,
     17   // and will each contain a bunch of statistics relevant to their nature.
     18   // Each peer connection has a number of such buckets.
     19   return base::StringPrintf("stats.%s-%s.values", bucket.c_str(),
     20                             statistic.c_str());
     21 }
     22 
     23 static bool MaybePrintResultsForAudioReceive(
     24     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
     25   std::string value;
     26   if (!pc_dict.GetString(Statistic("audioOutputLevel", ssrc), &value)) {
     27     // Not an audio receive stream.
     28     return false;
     29   }
     30 
     31   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesReceived", ssrc), &value));
     32   perf_test::PrintResult(
     33       "audio_bytes", "", "bytes_recv", value, "bytes", false);
     34   EXPECT_TRUE(pc_dict.GetString(Statistic("packetsLost", ssrc), &value));
     35   perf_test::PrintResult(
     36       "audio_misc", "", "packets_lost", value, "", false);
     37 
     38   return true;
     39 }
     40 
     41 static bool MaybePrintResultsForAudioSend(
     42     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
     43   std::string value;
     44   if (!pc_dict.GetString(Statistic("audioInputLevel", ssrc), &value)) {
     45     // Not an audio send stream.
     46     return false;
     47   }
     48 
     49   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesSent", ssrc), &value));
     50   perf_test::PrintResult(
     51       "audio_bytes", "", "bytes_sent", value, "bytes", false);
     52   EXPECT_TRUE(pc_dict.GetString(Statistic("googJitterReceived", ssrc), &value));
     53   perf_test::PrintResult(
     54       "audio_tx", "", "goog_jitter_recv", value, "ms", false);
     55   EXPECT_TRUE(pc_dict.GetString(Statistic("googRtt", ssrc), &value));
     56   perf_test::PrintResult(
     57       "audio_tx", "", "goog_rtt", value, "ms", false);
     58   return true;
     59 }
     60 
     61 static bool MaybePrintResultsForVideoSend(
     62     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
     63   std::string value;
     64   if (!pc_dict.GetString(Statistic("googFrameRateSent", ssrc), &value)) {
     65     // Not a video send stream.
     66     return false;
     67   }
     68 
     69   // Graph these by unit: the dashboard expects all stats in one graph to have
     70   // the same unit (e.g. ms, fps, etc). Most graphs, like video_fps, will also
     71   // be populated by the counterparts on the video receiving side.
     72   perf_test::PrintResult(
     73       "video_fps", "", "goog_frame_rate_sent", value, "fps", false);
     74   EXPECT_TRUE(pc_dict.GetString(Statistic("googFrameRateInput", ssrc), &value));
     75   perf_test::PrintResult(
     76       "video_fps", "", "goog_frame_rate_input", value, "fps", false);
     77 
     78   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesSent", ssrc), &value));
     79   perf_test::PrintResult(
     80       "video_total_bytes", "", "bytes_sent", value, "bytes", false);
     81 
     82   EXPECT_TRUE(pc_dict.GetString(Statistic("googFirsReceived", ssrc), &value));
     83   perf_test::PrintResult(
     84       "video_misc", "", "goog_firs_recv", value, "", false);
     85   EXPECT_TRUE(pc_dict.GetString(Statistic("googNacksReceived", ssrc), &value));
     86   perf_test::PrintResult(
     87       "video_misc", "", "goog_nacks_recv", value, "", false);
     88 
     89   EXPECT_TRUE(pc_dict.GetString(Statistic("googFrameWidthSent", ssrc), &value));
     90   perf_test::PrintResult(
     91       "video_resolution", "", "goog_frame_width_sent", value, "pixels", false);
     92   EXPECT_TRUE(
     93       pc_dict.GetString(Statistic("googFrameHeightSent", ssrc), &value));
     94   perf_test::PrintResult(
     95       "video_resolution", "", "goog_frame_height_sent", value, "pixels", false);
     96 
     97   EXPECT_TRUE(pc_dict.GetString(
     98       Statistic("googCaptureJitterMs", ssrc), &value));
     99   perf_test::PrintResult(
    100       "video_tx", "", "goog_capture_jitter_ms", value, "ms", false);
    101   EXPECT_TRUE(pc_dict.GetString(
    102       Statistic("googCaptureQueueDelayMsPerS", ssrc), &value));
    103   perf_test::PrintResult(
    104       "video_tx", "", "goog_capture_queue_delay_ms_per_s",
    105        value, "ms/s", false);
    106   EXPECT_TRUE(pc_dict.GetString(Statistic("googAvgEncodeMs", ssrc), &value));
    107   perf_test::PrintResult(
    108       "video_tx", "", "goog_avg_encode_ms", value, "ms", false);
    109   EXPECT_TRUE(pc_dict.GetString(Statistic("googRtt", ssrc), &value));
    110   perf_test::PrintResult("video_tx", "", "goog_rtt", value, "ms", false);
    111 
    112   EXPECT_TRUE(pc_dict.GetString(
    113       Statistic("googEncodeUsagePercent", ssrc), &value));
    114   perf_test::PrintResult(
    115       "video_cpu_usage", "", "goog_encode_usage_percent", value, "%", false);
    116   return true;
    117 }
    118 
    119 static bool MaybePrintResultsForVideoReceive(
    120     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
    121   std::string value;
    122   if (!pc_dict.GetString(Statistic("googFrameRateReceived", ssrc), &value)) {
    123     // Not a video receive stream.
    124     return false;
    125   }
    126 
    127   perf_test::PrintResult(
    128       "video_fps", "", "goog_frame_rate_recv", value, "fps", false);
    129   EXPECT_TRUE(
    130       pc_dict.GetString(Statistic("googFrameRateOutput", ssrc), &value));
    131   perf_test::PrintResult(
    132       "video_fps", "", "goog_frame_rate_output", value, "fps", false);
    133 
    134   EXPECT_TRUE(pc_dict.GetString(Statistic("packetsLost", ssrc), &value));
    135   perf_test::PrintResult("video_misc", "", "packets_lost", value, "", false);
    136 
    137   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesReceived", ssrc), &value));
    138   perf_test::PrintResult(
    139       "video_total_bytes", "", "bytes_recv", value, "bytes", false);
    140 
    141   EXPECT_TRUE(
    142       pc_dict.GetString(Statistic("googFrameWidthReceived", ssrc), &value));
    143   perf_test::PrintResult(
    144       "video_resolution", "", "goog_frame_width_recv", value, "pixels", false);
    145   EXPECT_TRUE(
    146       pc_dict.GetString(Statistic("googFrameHeightReceived", ssrc), &value));
    147   perf_test::PrintResult(
    148       "video_resolution", "", "goog_frame_height_recv", value, "pixels", false);
    149 
    150   EXPECT_TRUE(pc_dict.GetString(Statistic("googCurrentDelayMs", ssrc), &value));
    151   perf_test::PrintResult(
    152       "video_rx", "", "goog_current_delay_ms", value, "ms", false);
    153   EXPECT_TRUE(pc_dict.GetString(Statistic("googTargetDelayMs", ssrc), &value));
    154   perf_test::PrintResult(
    155       "video_rx", "", "goog_target_delay_ms", value, "ms", false);
    156   EXPECT_TRUE(pc_dict.GetString(Statistic("googDecodeMs", ssrc), &value));
    157   perf_test::PrintResult("video_rx", "", "goog_decode_ms", value, "ms", false);
    158   EXPECT_TRUE(pc_dict.GetString(Statistic("googMaxDecodeMs", ssrc), &value));
    159   perf_test::PrintResult(
    160       "video_rx", "", "goog_max_decode_ms", value, "ms", false);
    161   EXPECT_TRUE(pc_dict.GetString(Statistic("googJitterBufferMs", ssrc), &value));
    162   perf_test::PrintResult(
    163       "video_rx", "", "goog_jitter_buffer_ms", value, "ms", false);
    164   EXPECT_TRUE(pc_dict.GetString(Statistic("googRenderDelayMs", ssrc), &value));
    165   perf_test::PrintResult(
    166       "video_rx", "", "goog_render_delay_ms", value, "ms", false);
    167 
    168   return true;
    169 }
    170 
    171 static std::string ExtractSsrcIdentifier(const std::string& key) {
    172   // Example key: ssrc_1234-someStatName. Grab the part before the dash.
    173   size_t key_start_pos = 0;
    174   size_t key_end_pos = key.find("-");
    175   CHECK(key_end_pos != std::string::npos) << "Could not parse key " << key;
    176   return key.substr(key_start_pos, key_end_pos - key_start_pos);
    177 }
    178 
    179 // Returns the set of unique ssrc identifiers in the call (e.g. ssrc_1234,
    180 // ssrc_12356, etc). |stats_dict| is the .stats dict from one peer connection.
    181 static std::set<std::string> FindAllSsrcIdentifiers(
    182     const base::DictionaryValue& stats_dict) {
    183   std::set<std::string> result;
    184   base::DictionaryValue::Iterator stats_iterator(stats_dict);
    185 
    186   while (!stats_iterator.IsAtEnd()) {
    187     if (stats_iterator.key().find("ssrc_") != std::string::npos)
    188       result.insert(ExtractSsrcIdentifier(stats_iterator.key()));
    189     stats_iterator.Advance();
    190   }
    191   return result;
    192 }
    193 
    194 namespace test {
    195 
    196 void PrintBweForVideoMetrics(const base::DictionaryValue& pc_dict) {
    197   const std::string kBweStatsKey = "bweforvideo";
    198   std::string value;
    199   ASSERT_TRUE(pc_dict.GetString(
    200       Statistic("googAvailableSendBandwidth", kBweStatsKey), &value));
    201   perf_test::PrintResult(
    202       "bwe_stats", "", "available_send_bw", value, "bit/s", false);
    203   ASSERT_TRUE(pc_dict.GetString(
    204       Statistic("googAvailableReceiveBandwidth", kBweStatsKey), &value));
    205   perf_test::PrintResult(
    206       "bwe_stats", "", "available_recv_bw", value, "bit/s", false);
    207   ASSERT_TRUE(pc_dict.GetString(
    208       Statistic("googTargetEncBitrate", kBweStatsKey), &value));
    209   perf_test::PrintResult(
    210       "bwe_stats", "", "target_enc_bitrate", value, "bit/s", false);
    211   ASSERT_TRUE(pc_dict.GetString(
    212       Statistic("googActualEncBitrate", kBweStatsKey), &value));
    213   perf_test::PrintResult(
    214       "bwe_stats", "", "actual_enc_bitrate", value, "bit/s", false);
    215   ASSERT_TRUE(pc_dict.GetString(
    216       Statistic("googTransmitBitrate", kBweStatsKey), &value));
    217   perf_test::PrintResult(
    218       "bwe_stats", "", "transmit_bitrate", value, "bit/s",false);
    219 }
    220 
    221 void PrintMetricsForAllStreams(const base::DictionaryValue& pc_dict) {
    222   const base::DictionaryValue* stats_dict;
    223   ASSERT_TRUE(pc_dict.GetDictionary("stats", &stats_dict));
    224   std::set<std::string> ssrc_identifiers = FindAllSsrcIdentifiers(*stats_dict);
    225 
    226   std::set<std::string>::const_iterator ssrc_iterator =
    227       ssrc_identifiers.begin();
    228   for (; ssrc_iterator != ssrc_identifiers.end(); ++ssrc_iterator) {
    229     // Figure out which stream type this ssrc represents and print all the
    230     // interesting metrics for it.
    231     const std::string& ssrc = *ssrc_iterator;
    232     bool did_recognize_stream_type =
    233         MaybePrintResultsForAudioReceive(ssrc, pc_dict) ||
    234         MaybePrintResultsForAudioSend(ssrc, pc_dict) ||
    235         MaybePrintResultsForVideoReceive(ssrc, pc_dict) ||
    236         MaybePrintResultsForVideoSend(ssrc, pc_dict);
    237     ASSERT_TRUE(did_recognize_stream_type) << "Failed to figure out which "
    238                                               "kind of stream SSRC " << ssrc
    239                                            << " is. ";
    240   }
    241 }
    242 
    243 }  // namespace test
    244