Home | History | Annotate | Download | only in webrtc
      1 /*
      2  * libjingle
      3  * Copyright 2012, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/app/webrtc/statscollector.h"
     29 
     30 #include <utility>
     31 #include <vector>
     32 
     33 #include "talk/session/media/channel.h"
     34 #include "webrtc/base/base64.h"
     35 #include "webrtc/base/scoped_ptr.h"
     36 #include "webrtc/base/timing.h"
     37 
     38 namespace webrtc {
     39 
     40 // The items below are in alphabetical order.
     41 const char StatsReport::kStatsValueNameActiveConnection[] =
     42     "googActiveConnection";
     43 const char StatsReport::kStatsValueNameActualEncBitrate[] =
     44     "googActualEncBitrate";
     45 const char StatsReport::kStatsValueNameAudioOutputLevel[] = "audioOutputLevel";
     46 const char StatsReport::kStatsValueNameAudioInputLevel[] = "audioInputLevel";
     47 const char StatsReport::kStatsValueNameAvailableReceiveBandwidth[] =
     48     "googAvailableReceiveBandwidth";
     49 const char StatsReport::kStatsValueNameAvailableSendBandwidth[] =
     50     "googAvailableSendBandwidth";
     51 const char StatsReport::kStatsValueNameAvgEncodeMs[] = "googAvgEncodeMs";
     52 const char StatsReport::kStatsValueNameBucketDelay[] = "googBucketDelay";
     53 const char StatsReport::kStatsValueNameBytesReceived[] = "bytesReceived";
     54 const char StatsReport::kStatsValueNameBytesSent[] = "bytesSent";
     55 const char StatsReport::kStatsValueNameBandwidthLimitedResolution[] =
     56     "googBandwidthLimitedResolution";
     57 const char StatsReport::kStatsValueNameCaptureJitterMs[] =
     58     "googCaptureJitterMs";
     59 const char StatsReport::kStatsValueNameCaptureQueueDelayMsPerS[] =
     60     "googCaptureQueueDelayMsPerS";
     61 const char StatsReport::kStatsValueNameChannelId[] = "googChannelId";
     62 const char StatsReport::kStatsValueNameCodecName[] = "googCodecName";
     63 const char StatsReport::kStatsValueNameComponent[] = "googComponent";
     64 const char StatsReport::kStatsValueNameContentName[] = "googContentName";
     65 const char StatsReport::kStatsValueNameCpuLimitedResolution[] =
     66     "googCpuLimitedResolution";
     67 const char StatsReport::kStatsValueNameDecodingCTSG[] =
     68     "googDecodingCTSG";
     69 const char StatsReport::kStatsValueNameDecodingCTN[] =
     70     "googDecodingCTN";
     71 const char StatsReport::kStatsValueNameDecodingNormal[] =
     72     "googDecodingNormal";
     73 const char StatsReport::kStatsValueNameDecodingPLC[] =
     74     "googDecodingPLC";
     75 const char StatsReport::kStatsValueNameDecodingCNG[] =
     76     "googDecodingCNG";
     77 const char StatsReport::kStatsValueNameDecodingPLCCNG[] =
     78     "googDecodingPLCCNG";
     79 const char StatsReport::kStatsValueNameDer[] = "googDerBase64";
     80 // Echo metrics from the audio processing module.
     81 const char StatsReport::kStatsValueNameEchoCancellationQualityMin[] =
     82     "googEchoCancellationQualityMin";
     83 const char StatsReport::kStatsValueNameEchoDelayMedian[] =
     84     "googEchoCancellationEchoDelayMedian";
     85 const char StatsReport::kStatsValueNameEchoDelayStdDev[] =
     86     "googEchoCancellationEchoDelayStdDev";
     87 const char StatsReport::kStatsValueNameEchoReturnLoss[] =
     88     "googEchoCancellationReturnLoss";
     89 const char StatsReport::kStatsValueNameEchoReturnLossEnhancement[] =
     90     "googEchoCancellationReturnLossEnhancement";
     91 
     92 const char StatsReport::kStatsValueNameEncodeRelStdDev[] =
     93     "googEncodeRelStdDev";
     94 const char StatsReport::kStatsValueNameEncodeUsagePercent[] =
     95     "googEncodeUsagePercent";
     96 const char StatsReport::kStatsValueNameExpandRate[] = "googExpandRate";
     97 const char StatsReport::kStatsValueNameFingerprint[] = "googFingerprint";
     98 const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
     99     "googFingerprintAlgorithm";
    100 const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
    101 const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
    102 const char StatsReport::kStatsValueNameFrameHeightInput[] =
    103     "googFrameHeightInput";
    104 const char StatsReport::kStatsValueNameFrameHeightReceived[] =
    105     "googFrameHeightReceived";
    106 const char StatsReport::kStatsValueNameFrameHeightSent[] =
    107     "googFrameHeightSent";
    108 const char StatsReport::kStatsValueNameFrameRateReceived[] =
    109     "googFrameRateReceived";
    110 const char StatsReport::kStatsValueNameFrameRateDecoded[] =
    111     "googFrameRateDecoded";
    112 const char StatsReport::kStatsValueNameFrameRateOutput[] =
    113     "googFrameRateOutput";
    114 const char StatsReport::kStatsValueNameDecodeMs[] = "googDecodeMs";
    115 const char StatsReport::kStatsValueNameMaxDecodeMs[] = "googMaxDecodeMs";
    116 const char StatsReport::kStatsValueNameCurrentDelayMs[] = "googCurrentDelayMs";
    117 const char StatsReport::kStatsValueNameTargetDelayMs[] = "googTargetDelayMs";
    118 const char StatsReport::kStatsValueNameJitterBufferMs[] = "googJitterBufferMs";
    119 const char StatsReport::kStatsValueNameMinPlayoutDelayMs[] =
    120     "googMinPlayoutDelayMs";
    121 const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
    122 
    123 const char StatsReport::kStatsValueNameCaptureStartNtpTimeMs[] =
    124     "googCaptureStartNtpTimeMs";
    125 
    126 const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
    127 const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
    128 const char StatsReport::kStatsValueNameFrameWidthInput[] =
    129     "googFrameWidthInput";
    130 const char StatsReport::kStatsValueNameFrameWidthReceived[] =
    131     "googFrameWidthReceived";
    132 const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
    133 const char StatsReport::kStatsValueNameInitiator[] = "googInitiator";
    134 const char StatsReport::kStatsValueNameIssuerId[] = "googIssuerId";
    135 const char StatsReport::kStatsValueNameJitterReceived[] = "googJitterReceived";
    136 const char StatsReport::kStatsValueNameLocalAddress[] = "googLocalAddress";
    137 const char StatsReport::kStatsValueNameLocalCandidateType[] =
    138     "googLocalCandidateType";
    139 const char StatsReport::kStatsValueNameLocalCertificateId[] =
    140     "googLocalCertificateId";
    141 const char StatsReport::kStatsValueNameAdaptationChanges[] =
    142     "googAdaptationChanges";
    143 const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
    144 const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
    145 const char StatsReport::kStatsValueNamePlisReceived[] = "googPlisReceived";
    146 const char StatsReport::kStatsValueNamePlisSent[] = "googPlisSent";
    147 const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
    148 const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
    149 const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
    150 const char StatsReport::kStatsValueNamePreferredJitterBufferMs[] =
    151     "googPreferredJitterBufferMs";
    152 const char StatsReport::kStatsValueNameReadable[] = "googReadable";
    153 const char StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug[] =
    154     "googReceivedPacketGroupArrivalTimeDebug";
    155 const char StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug[] =
    156     "googReceivedPacketGroupPropagationDeltaDebug";
    157 const char
    158 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[] =
    159     "googReceivedPacketGroupPropagationDeltaSumDebug";
    160 const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
    161 const char StatsReport::kStatsValueNameRemoteCandidateType[] =
    162     "googRemoteCandidateType";
    163 const char StatsReport::kStatsValueNameRemoteCertificateId[] =
    164     "googRemoteCertificateId";
    165 const char StatsReport::kStatsValueNameRetransmitBitrate[] =
    166     "googRetransmitBitrate";
    167 const char StatsReport::kStatsValueNameRtt[] = "googRtt";
    168 const char StatsReport::kStatsValueNameSsrc[] = "ssrc";
    169 const char StatsReport::kStatsValueNameTargetEncBitrate[] =
    170     "googTargetEncBitrate";
    171 const char StatsReport::kStatsValueNameTransmitBitrate[] =
    172     "googTransmitBitrate";
    173 const char StatsReport::kStatsValueNameTransportId[] = "transportId";
    174 const char StatsReport::kStatsValueNameTransportType[] = "googTransportType";
    175 const char StatsReport::kStatsValueNameTrackId[] = "googTrackId";
    176 const char StatsReport::kStatsValueNameTypingNoiseState[] =
    177     "googTypingNoiseState";
    178 const char StatsReport::kStatsValueNameViewLimitedResolution[] =
    179     "googViewLimitedResolution";
    180 const char StatsReport::kStatsValueNameWritable[] = "googWritable";
    181 
    182 const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
    183 const char StatsReport::kStatsReportTypeBwe[] = "VideoBwe";
    184 const char StatsReport::kStatsReportTypeRemoteSsrc[] = "remoteSsrc";
    185 const char StatsReport::kStatsReportTypeSsrc[] = "ssrc";
    186 const char StatsReport::kStatsReportTypeTrack[] = "googTrack";
    187 const char StatsReport::kStatsReportTypeIceCandidate[] = "iceCandidate";
    188 const char StatsReport::kStatsReportTypeTransport[] = "googTransport";
    189 const char StatsReport::kStatsReportTypeComponent[] = "googComponent";
    190 const char StatsReport::kStatsReportTypeCandidatePair[] = "googCandidatePair";
    191 const char StatsReport::kStatsReportTypeCertificate[] = "googCertificate";
    192 
    193 const char StatsReport::kStatsReportVideoBweId[] = "bweforvideo";
    194 
    195 // Implementations of functions in statstypes.h
    196 void StatsReport::AddValue(StatsReport::StatsValueName name,
    197                            const std::string& value) {
    198   values.push_back(Value(name, value));
    199 }
    200 
    201 void StatsReport::AddValue(StatsReport::StatsValueName name, int64 value) {
    202   AddValue(name, rtc::ToString<int64>(value));
    203 }
    204 
    205 template <typename T>
    206 void StatsReport::AddValue(StatsReport::StatsValueName name,
    207                            const std::vector<T>& value) {
    208   std::ostringstream oss;
    209   oss << "[";
    210   for (size_t i = 0; i < value.size(); ++i) {
    211     oss << rtc::ToString<T>(value[i]);
    212     if (i != value.size() - 1)
    213       oss << ", ";
    214   }
    215   oss << "]";
    216   AddValue(name, oss.str());
    217 }
    218 
    219 void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) {
    220   AddValue(name, value ? "true" : "false");
    221 }
    222 
    223 void StatsReport::ReplaceValue(StatsReport::StatsValueName name,
    224                                const std::string& value) {
    225   for (Values::iterator it = values.begin(); it != values.end(); ++it) {
    226     if ((*it).name == name) {
    227       it->value = value;
    228       return;
    229     }
    230   }
    231   // It is not reachable here, add an ASSERT to make sure the overwriting is
    232   // always a success.
    233   ASSERT(false);
    234 }
    235 
    236 namespace {
    237 
    238 double GetTimeNow() {
    239   return rtc::Timing::WallTimeNow() * rtc::kNumMillisecsPerSec;
    240 }
    241 
    242 bool GetTransportIdFromProxy(const cricket::ProxyTransportMap& map,
    243                              const std::string& proxy,
    244                              std::string* transport) {
    245   // TODO(hta): Remove handling of empty proxy name once tests do not use it.
    246   if (proxy.empty()) {
    247     transport->clear();
    248     return true;
    249   }
    250 
    251   cricket::ProxyTransportMap::const_iterator found = map.find(proxy);
    252   if (found == map.end()) {
    253     LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
    254     return false;
    255   }
    256 
    257   std::ostringstream ost;
    258   // Component 1 is always used for RTP.
    259   ost << "Channel-" << found->second << "-1";
    260   *transport = ost.str();
    261   return true;
    262 }
    263 
    264 std::string StatsId(const std::string& type, const std::string& id) {
    265   return type + "_" + id;
    266 }
    267 
    268 std::string StatsId(const std::string& type, const std::string& id,
    269                     StatsCollector::TrackDirection direction) {
    270   ASSERT(direction == StatsCollector::kSending ||
    271          direction == StatsCollector::kReceiving);
    272 
    273   // Strings for the direction of the track.
    274   const char kSendDirection[] = "send";
    275   const char kRecvDirection[] = "recv";
    276 
    277   const std::string direction_id = (direction == StatsCollector::kSending) ?
    278       kSendDirection : kRecvDirection;
    279   return type + "_" + id + "_" + direction_id;
    280 }
    281 
    282 bool ExtractValueFromReport(
    283     const StatsReport& report,
    284     StatsReport::StatsValueName name,
    285     std::string* value) {
    286   StatsReport::Values::const_iterator it = report.values.begin();
    287   for (; it != report.values.end(); ++it) {
    288     if (it->name == name) {
    289       *value = it->value;
    290       return true;
    291     }
    292   }
    293   return false;
    294 }
    295 
    296 void AddTrackReport(StatsSet* reports, const std::string& track_id) {
    297   // Adds an empty track report.
    298   StatsReport* report = reports->ReplaceOrAddNew(
    299       StatsId(StatsReport::kStatsReportTypeTrack, track_id));
    300   report->type = StatsReport::kStatsReportTypeTrack;
    301   report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
    302 }
    303 
    304 template <class TrackVector>
    305 void CreateTrackReports(const TrackVector& tracks, StatsSet* reports) {
    306   for (size_t j = 0; j < tracks.size(); ++j) {
    307     webrtc::MediaStreamTrackInterface* track = tracks[j];
    308     AddTrackReport(reports, track->id());
    309   }
    310 }
    311 
    312 void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
    313   report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
    314                    info.audio_level);
    315   report->AddValue(StatsReport::kStatsValueNameBytesReceived,
    316                    info.bytes_rcvd);
    317   report->AddValue(StatsReport::kStatsValueNameJitterReceived,
    318                    info.jitter_ms);
    319   report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
    320                    info.jitter_buffer_ms);
    321   report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
    322                    info.jitter_buffer_preferred_ms);
    323   report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
    324                    info.delay_estimate_ms);
    325   report->AddValue(StatsReport::kStatsValueNameExpandRate,
    326                    rtc::ToString<float>(info.expand_rate));
    327   report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
    328                    info.packets_rcvd);
    329   report->AddValue(StatsReport::kStatsValueNamePacketsLost,
    330                    info.packets_lost);
    331   report->AddValue(StatsReport::kStatsValueNameDecodingCTSG,
    332                    info.decoding_calls_to_silence_generator);
    333   report->AddValue(StatsReport::kStatsValueNameDecodingCTN,
    334                    info.decoding_calls_to_neteq);
    335   report->AddValue(StatsReport::kStatsValueNameDecodingNormal,
    336                    info.decoding_normal);
    337   report->AddValue(StatsReport::kStatsValueNameDecodingPLC,
    338                    info.decoding_plc);
    339   report->AddValue(StatsReport::kStatsValueNameDecodingCNG,
    340                    info.decoding_cng);
    341   report->AddValue(StatsReport::kStatsValueNameDecodingPLCCNG,
    342                    info.decoding_plc_cng);
    343   report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
    344                    info.capture_start_ntp_time_ms);
    345   report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
    346 }
    347 
    348 void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
    349   report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
    350                    info.audio_level);
    351   report->AddValue(StatsReport::kStatsValueNameBytesSent,
    352                    info.bytes_sent);
    353   report->AddValue(StatsReport::kStatsValueNamePacketsSent,
    354                    info.packets_sent);
    355   report->AddValue(StatsReport::kStatsValueNamePacketsLost,
    356                    info.packets_lost);
    357   report->AddValue(StatsReport::kStatsValueNameJitterReceived,
    358                    info.jitter_ms);
    359   report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
    360   report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
    361                    rtc::ToString<float>(info.aec_quality_min));
    362   report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
    363                    info.echo_delay_median_ms);
    364   report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
    365                    info.echo_delay_std_ms);
    366   report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
    367                    info.echo_return_loss);
    368   report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
    369                    info.echo_return_loss_enhancement);
    370   report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
    371   report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
    372                      info.typing_noise_detected);
    373 }
    374 
    375 void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
    376   report->AddValue(StatsReport::kStatsValueNameBytesReceived,
    377                    info.bytes_rcvd);
    378   report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
    379                    info.packets_rcvd);
    380   report->AddValue(StatsReport::kStatsValueNamePacketsLost,
    381                    info.packets_lost);
    382 
    383   report->AddValue(StatsReport::kStatsValueNameFirsSent,
    384                    info.firs_sent);
    385   report->AddValue(StatsReport::kStatsValueNamePlisSent,
    386                    info.plis_sent);
    387   report->AddValue(StatsReport::kStatsValueNameNacksSent,
    388                    info.nacks_sent);
    389   report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
    390                    info.frame_width);
    391   report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
    392                    info.frame_height);
    393   report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
    394                    info.framerate_rcvd);
    395   report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
    396                    info.framerate_decoded);
    397   report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
    398                    info.framerate_output);
    399 
    400   report->AddValue(StatsReport::kStatsValueNameDecodeMs,
    401                    info.decode_ms);
    402   report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
    403                    info.max_decode_ms);
    404   report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
    405                    info.current_delay_ms);
    406   report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
    407                    info.target_delay_ms);
    408   report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
    409                    info.jitter_buffer_ms);
    410   report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
    411                    info.min_playout_delay_ms);
    412   report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
    413                    info.render_delay_ms);
    414 
    415   report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
    416                    info.capture_start_ntp_time_ms);
    417 }
    418 
    419 void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
    420   report->AddValue(StatsReport::kStatsValueNameBytesSent,
    421                    info.bytes_sent);
    422   report->AddValue(StatsReport::kStatsValueNamePacketsSent,
    423                    info.packets_sent);
    424   report->AddValue(StatsReport::kStatsValueNamePacketsLost,
    425                    info.packets_lost);
    426 
    427   report->AddValue(StatsReport::kStatsValueNameFirsReceived,
    428                    info.firs_rcvd);
    429   report->AddValue(StatsReport::kStatsValueNamePlisReceived,
    430                    info.plis_rcvd);
    431   report->AddValue(StatsReport::kStatsValueNameNacksReceived,
    432                    info.nacks_rcvd);
    433   report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
    434                    info.input_frame_width);
    435   report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
    436                    info.input_frame_height);
    437   report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
    438                    info.send_frame_width);
    439   report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
    440                    info.send_frame_height);
    441   report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
    442                    info.framerate_input);
    443   report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
    444                    info.framerate_sent);
    445   report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
    446   report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
    447   report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
    448                      (info.adapt_reason & 0x1) > 0);
    449   report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
    450                      (info.adapt_reason & 0x2) > 0);
    451   report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
    452                      (info.adapt_reason & 0x4) > 0);
    453   report->AddValue(StatsReport::kStatsValueNameAdaptationChanges,
    454                    info.adapt_changes);
    455   report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
    456   report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
    457                    info.capture_jitter_ms);
    458   report->AddValue(StatsReport::kStatsValueNameCaptureQueueDelayMsPerS,
    459                    info.capture_queue_delay_ms_per_s);
    460   report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
    461                    info.encode_usage_percent);
    462   report->AddValue(StatsReport::kStatsValueNameEncodeRelStdDev,
    463                    info.encode_rsd);
    464 }
    465 
    466 void ExtractStats(const cricket::BandwidthEstimationInfo& info,
    467                   double stats_gathering_started,
    468                   PeerConnectionInterface::StatsOutputLevel level,
    469                   StatsReport* report) {
    470   ASSERT(report->id == StatsReport::kStatsReportVideoBweId);
    471   report->type = StatsReport::kStatsReportTypeBwe;
    472 
    473   // Clear out stats from previous GatherStats calls if any.
    474   if (report->timestamp != stats_gathering_started) {
    475     report->values.clear();
    476     report->timestamp = stats_gathering_started;
    477   }
    478 
    479   report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
    480                    info.available_send_bandwidth);
    481   report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
    482                    info.available_recv_bandwidth);
    483   report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
    484                    info.target_enc_bitrate);
    485   report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
    486                    info.actual_enc_bitrate);
    487   report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
    488                    info.retransmit_bitrate);
    489   report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
    490                    info.transmit_bitrate);
    491   report->AddValue(StatsReport::kStatsValueNameBucketDelay,
    492                    info.bucket_delay);
    493   if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
    494     report->AddValue(
    495         StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
    496         info.total_received_propagation_delta_ms);
    497     if (info.recent_received_propagation_delta_ms.size() > 0) {
    498       report->AddValue(
    499           StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
    500           info.recent_received_propagation_delta_ms);
    501       report->AddValue(
    502           StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
    503           info.recent_received_packet_group_arrival_time_ms);
    504     }
    505   }
    506 }
    507 
    508 void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
    509                         StatsReport* report) {
    510   report->timestamp = info.remote_stats[0].timestamp;
    511   // TODO(hta): Extract some stats here.
    512 }
    513 
    514 void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
    515                         StatsReport* report) {
    516   report->timestamp = info.remote_stats[0].timestamp;
    517   // TODO(hta): Extract some stats here.
    518 }
    519 
    520 // Template to extract stats from a data vector.
    521 // In order to use the template, the functions that are called from it,
    522 // ExtractStats and ExtractRemoteStats, must be defined and overloaded
    523 // for each type.
    524 template<typename T>
    525 void ExtractStatsFromList(const std::vector<T>& data,
    526                           const std::string& transport_id,
    527                           StatsCollector* collector,
    528                           StatsCollector::TrackDirection direction) {
    529   typename std::vector<T>::const_iterator it = data.begin();
    530   for (; it != data.end(); ++it) {
    531     std::string id;
    532     uint32 ssrc = it->ssrc();
    533     // Each track can have stats for both local and remote objects.
    534     // TODO(hta): Handle the case of multiple SSRCs per object.
    535     StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id,
    536                                                         direction);
    537     if (report)
    538       ExtractStats(*it, report);
    539 
    540     if (it->remote_stats.size() > 0) {
    541       report = collector->PrepareRemoteReport(ssrc, transport_id,
    542                                               direction);
    543       if (!report) {
    544         continue;
    545       }
    546       ExtractRemoteStats(*it, report);
    547     }
    548   }
    549 }
    550 
    551 }  // namespace
    552 
    553 StatsCollector::StatsCollector(WebRtcSession* session)
    554     : session_(session), stats_gathering_started_(0) {
    555   ASSERT(session_);
    556 }
    557 
    558 StatsCollector::~StatsCollector() {
    559 }
    560 
    561 // Adds a MediaStream with tracks that can be used as a |selector| in a call
    562 // to GetStats.
    563 void StatsCollector::AddStream(MediaStreamInterface* stream) {
    564   ASSERT(stream != NULL);
    565 
    566   CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
    567                                        &reports_);
    568   CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
    569                                        &reports_);
    570 }
    571 
    572 void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
    573                                         uint32 ssrc) {
    574   ASSERT(audio_track != NULL);
    575   for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
    576        it != local_audio_tracks_.end(); ++it) {
    577     ASSERT(it->first != audio_track || it->second != ssrc);
    578   }
    579 
    580   local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
    581 
    582   // Create the kStatsReportTypeTrack report for the new track if there is no
    583   // report yet.
    584   StatsReport* found = reports_.Find(
    585       StatsId(StatsReport::kStatsReportTypeTrack, audio_track->id()));
    586   if (!found)
    587     AddTrackReport(&reports_, audio_track->id());
    588 }
    589 
    590 void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
    591                                            uint32 ssrc) {
    592   ASSERT(audio_track != NULL);
    593   for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
    594        it != local_audio_tracks_.end(); ++it) {
    595     if (it->first == audio_track && it->second == ssrc) {
    596       local_audio_tracks_.erase(it);
    597       return;
    598     }
    599   }
    600 
    601   ASSERT(false);
    602 }
    603 
    604 void StatsCollector::GetStats(MediaStreamTrackInterface* track,
    605                               StatsReports* reports) {
    606   ASSERT(reports != NULL);
    607   ASSERT(reports->empty());
    608 
    609   if (!track) {
    610     StatsSet::const_iterator it;
    611     for (it = reports_.begin(); it != reports_.end(); ++it)
    612       reports->push_back(&(*it));
    613     return;
    614   }
    615 
    616   StatsReport* report =
    617       reports_.Find(StatsId(StatsReport::kStatsReportTypeSession,
    618                             session_->id()));
    619   if (report)
    620     reports->push_back(report);
    621 
    622   report = reports_.Find(
    623       StatsId(StatsReport::kStatsReportTypeTrack, track->id()));
    624 
    625   if (!report)
    626     return;
    627 
    628   reports->push_back(report);
    629 
    630   std::string track_id;
    631   for (StatsSet::const_iterator it = reports_.begin(); it != reports_.end();
    632        ++it) {
    633     if (it->type != StatsReport::kStatsReportTypeSsrc)
    634       continue;
    635 
    636     if (ExtractValueFromReport(*it,
    637                                StatsReport::kStatsValueNameTrackId,
    638                                &track_id)) {
    639       if (track_id == track->id()) {
    640         reports->push_back(&(*it));
    641       }
    642     }
    643   }
    644 }
    645 
    646 void
    647 StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
    648   double time_now = GetTimeNow();
    649   // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
    650   // ms apart will be ignored.
    651   const double kMinGatherStatsPeriod = 50;
    652   if (stats_gathering_started_ != 0 &&
    653       stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
    654     return;
    655   }
    656   stats_gathering_started_ = time_now;
    657 
    658   if (session_) {
    659     ExtractSessionInfo();
    660     ExtractVoiceInfo();
    661     ExtractVideoInfo(level);
    662   }
    663 }
    664 
    665 StatsReport* StatsCollector::PrepareLocalReport(
    666     uint32 ssrc,
    667     const std::string& transport_id,
    668     TrackDirection direction) {
    669   const std::string ssrc_id = rtc::ToString<uint32>(ssrc);
    670   StatsReport* report = reports_.Find(
    671       StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id, direction));
    672 
    673   // Use the ID of the track that is currently mapped to the SSRC, if any.
    674   std::string track_id;
    675   if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
    676     if (!report) {
    677       // The ssrc is not used by any track or existing report, return NULL
    678       // in such case to indicate no report is prepared for the ssrc.
    679       return NULL;
    680     }
    681 
    682     // The ssrc is not used by any existing track. Keeps the old track id
    683     // since we want to report the stats for inactive ssrc.
    684     ExtractValueFromReport(*report,
    685                            StatsReport::kStatsValueNameTrackId,
    686                            &track_id);
    687   }
    688 
    689   report = GetOrCreateReport(
    690       StatsReport::kStatsReportTypeSsrc, ssrc_id, direction);
    691 
    692   // Clear out stats from previous GatherStats calls if any.
    693   // This is required since the report will be returned for the new values.
    694   // Having the old values in the report will lead to multiple values with
    695   // the same name.
    696   // TODO(xians): Consider changing StatsReport to use map instead of vector.
    697   report->values.clear();
    698   report->timestamp = stats_gathering_started_;
    699 
    700   report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
    701   report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
    702   // Add the mapping of SSRC to transport.
    703   report->AddValue(StatsReport::kStatsValueNameTransportId,
    704                    transport_id);
    705   return report;
    706 }
    707 
    708 StatsReport* StatsCollector::PrepareRemoteReport(
    709     uint32 ssrc,
    710     const std::string& transport_id,
    711     TrackDirection direction) {
    712   const std::string ssrc_id = rtc::ToString<uint32>(ssrc);
    713   StatsReport* report = reports_.Find(
    714       StatsId(StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction));
    715 
    716   // Use the ID of the track that is currently mapped to the SSRC, if any.
    717   std::string track_id;
    718   if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
    719     if (!report) {
    720       // The ssrc is not used by any track or existing report, return NULL
    721       // in such case to indicate no report is prepared for the ssrc.
    722       return NULL;
    723     }
    724 
    725     // The ssrc is not used by any existing track. Keeps the old track id
    726     // since we want to report the stats for inactive ssrc.
    727     ExtractValueFromReport(*report,
    728                            StatsReport::kStatsValueNameTrackId,
    729                            &track_id);
    730   }
    731 
    732   report = GetOrCreateReport(
    733       StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction);
    734 
    735   // Clear out stats from previous GatherStats calls if any.
    736   // The timestamp will be added later. Zero it for debugging.
    737   report->values.clear();
    738   report->timestamp = 0;
    739 
    740   report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
    741   report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
    742   // Add the mapping of SSRC to transport.
    743   report->AddValue(StatsReport::kStatsValueNameTransportId,
    744                    transport_id);
    745   return report;
    746 }
    747 
    748 std::string StatsCollector::AddOneCertificateReport(
    749     const rtc::SSLCertificate* cert, const std::string& issuer_id) {
    750   // TODO(bemasc): Move this computation to a helper class that caches these
    751   // values to reduce CPU use in GetStats.  This will require adding a fast
    752   // SSLCertificate::Equals() method to detect certificate changes.
    753 
    754   std::string digest_algorithm;
    755   if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
    756     return std::string();
    757 
    758   rtc::scoped_ptr<rtc::SSLFingerprint> ssl_fingerprint(
    759       rtc::SSLFingerprint::Create(digest_algorithm, cert));
    760 
    761   // SSLFingerprint::Create can fail if the algorithm returned by
    762   // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
    763   // implementation of SSLCertificate::ComputeDigest.  This currently happens
    764   // with MD5- and SHA-224-signed certificates when linked to libNSS.
    765   if (!ssl_fingerprint)
    766     return std::string();
    767 
    768   std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
    769 
    770   rtc::Buffer der_buffer;
    771   cert->ToDER(&der_buffer);
    772   std::string der_base64;
    773   rtc::Base64::EncodeFromArray(
    774       der_buffer.data(), der_buffer.length(), &der_base64);
    775 
    776   StatsReport* report = reports_.ReplaceOrAddNew(
    777       StatsId(StatsReport::kStatsReportTypeCertificate, fingerprint));
    778   report->type = StatsReport::kStatsReportTypeCertificate;
    779   report->timestamp = stats_gathering_started_;
    780   report->AddValue(StatsReport::kStatsValueNameFingerprint, fingerprint);
    781   report->AddValue(StatsReport::kStatsValueNameFingerprintAlgorithm,
    782                    digest_algorithm);
    783   report->AddValue(StatsReport::kStatsValueNameDer, der_base64);
    784   if (!issuer_id.empty())
    785     report->AddValue(StatsReport::kStatsValueNameIssuerId, issuer_id);
    786   return report->id;
    787 }
    788 
    789 std::string StatsCollector::AddCertificateReports(
    790     const rtc::SSLCertificate* cert) {
    791   // Produces a chain of StatsReports representing this certificate and the rest
    792   // of its chain, and adds those reports to |reports_|.  The return value is
    793   // the id of the leaf report.  The provided cert must be non-null, so at least
    794   // one report will always be provided and the returned string will never be
    795   // empty.
    796   ASSERT(cert != NULL);
    797 
    798   std::string issuer_id;
    799   rtc::scoped_ptr<rtc::SSLCertChain> chain;
    800   if (cert->GetChain(chain.accept())) {
    801     // This loop runs in reverse, i.e. from root to leaf, so that each
    802     // certificate's issuer's report ID is known before the child certificate's
    803     // report is generated.  The root certificate does not have an issuer ID
    804     // value.
    805     for (ptrdiff_t i = chain->GetSize() - 1; i >= 0; --i) {
    806       const rtc::SSLCertificate& cert_i = chain->Get(i);
    807       issuer_id = AddOneCertificateReport(&cert_i, issuer_id);
    808     }
    809   }
    810   // Add the leaf certificate.
    811   return AddOneCertificateReport(cert, issuer_id);
    812 }
    813 
    814 void StatsCollector::ExtractSessionInfo() {
    815   // Extract information from the base session.
    816   StatsReport* report = reports_.ReplaceOrAddNew(
    817       StatsId(StatsReport::kStatsReportTypeSession, session_->id()));
    818   report->type = StatsReport::kStatsReportTypeSession;
    819   report->timestamp = stats_gathering_started_;
    820   report->values.clear();
    821   report->AddBoolean(StatsReport::kStatsValueNameInitiator,
    822                      session_->initiator());
    823 
    824   cricket::SessionStats stats;
    825   if (session_->GetStats(&stats)) {
    826     // Store the proxy map away for use in SSRC reporting.
    827     proxy_to_transport_ = stats.proxy_to_transport;
    828 
    829     for (cricket::TransportStatsMap::iterator transport_iter
    830              = stats.transport_stats.begin();
    831          transport_iter != stats.transport_stats.end(); ++transport_iter) {
    832       // Attempt to get a copy of the certificates from the transport and
    833       // expose them in stats reports.  All channels in a transport share the
    834       // same local and remote certificates.
    835       //
    836       // Note that Transport::GetIdentity and Transport::GetRemoteCertificate
    837       // invoke method calls on the worker thread and block this thread, but
    838       // messages are still processed on this thread, which may blow way the
    839       // existing transports. So we cannot reuse |transport| after these calls.
    840       std::string local_cert_report_id, remote_cert_report_id;
    841 
    842       cricket::Transport* transport =
    843           session_->GetTransport(transport_iter->second.content_name);
    844       rtc::scoped_ptr<rtc::SSLIdentity> identity;
    845       if (transport && transport->GetIdentity(identity.accept())) {
    846         local_cert_report_id =
    847             AddCertificateReports(&(identity->certificate()));
    848       }
    849 
    850       transport = session_->GetTransport(transport_iter->second.content_name);
    851       rtc::scoped_ptr<rtc::SSLCertificate> cert;
    852       if (transport && transport->GetRemoteCertificate(cert.accept())) {
    853         remote_cert_report_id = AddCertificateReports(cert.get());
    854       }
    855 
    856       for (cricket::TransportChannelStatsList::iterator channel_iter
    857                = transport_iter->second.channel_stats.begin();
    858            channel_iter != transport_iter->second.channel_stats.end();
    859            ++channel_iter) {
    860         std::ostringstream ostc;
    861         ostc << "Channel-" << transport_iter->second.content_name
    862              << "-" << channel_iter->component;
    863         StatsReport* channel_report = reports_.ReplaceOrAddNew(ostc.str());
    864         channel_report->type = StatsReport::kStatsReportTypeComponent;
    865         channel_report->timestamp = stats_gathering_started_;
    866         channel_report->AddValue(StatsReport::kStatsValueNameComponent,
    867                                  channel_iter->component);
    868         if (!local_cert_report_id.empty())
    869           channel_report->AddValue(
    870               StatsReport::kStatsValueNameLocalCertificateId,
    871               local_cert_report_id);
    872         if (!remote_cert_report_id.empty())
    873           channel_report->AddValue(
    874               StatsReport::kStatsValueNameRemoteCertificateId,
    875               remote_cert_report_id);
    876         for (size_t i = 0;
    877              i < channel_iter->connection_infos.size();
    878              ++i) {
    879           std::ostringstream ost;
    880           ost << "Conn-" << transport_iter->first << "-"
    881               << channel_iter->component << "-" << i;
    882           StatsReport* report = reports_.ReplaceOrAddNew(ost.str());
    883           report->type = StatsReport::kStatsReportTypeCandidatePair;
    884           report->timestamp = stats_gathering_started_;
    885           // Link from connection to its containing channel.
    886           report->AddValue(StatsReport::kStatsValueNameChannelId,
    887                            channel_report->id);
    888 
    889           const cricket::ConnectionInfo& info =
    890               channel_iter->connection_infos[i];
    891           report->AddValue(StatsReport::kStatsValueNameBytesSent,
    892                            info.sent_total_bytes);
    893           report->AddValue(StatsReport::kStatsValueNameBytesReceived,
    894                            info.recv_total_bytes);
    895           report->AddBoolean(StatsReport::kStatsValueNameWritable,
    896                              info.writable);
    897           report->AddBoolean(StatsReport::kStatsValueNameReadable,
    898                              info.readable);
    899           report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
    900                              info.best_connection);
    901           report->AddValue(StatsReport::kStatsValueNameLocalAddress,
    902                            info.local_candidate.address().ToString());
    903           report->AddValue(StatsReport::kStatsValueNameRemoteAddress,
    904                            info.remote_candidate.address().ToString());
    905           report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
    906           report->AddValue(StatsReport::kStatsValueNameTransportType,
    907                            info.local_candidate.protocol());
    908           report->AddValue(StatsReport::kStatsValueNameLocalCandidateType,
    909                            info.local_candidate.type());
    910           report->AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
    911                            info.remote_candidate.type());
    912         }
    913       }
    914     }
    915   }
    916 }
    917 
    918 void StatsCollector::ExtractVoiceInfo() {
    919   if (!session_->voice_channel()) {
    920     return;
    921   }
    922   cricket::VoiceMediaInfo voice_info;
    923   if (!session_->voice_channel()->GetStats(&voice_info)) {
    924     LOG(LS_ERROR) << "Failed to get voice channel stats.";
    925     return;
    926   }
    927   std::string transport_id;
    928   if (!GetTransportIdFromProxy(proxy_to_transport_,
    929                                session_->voice_channel()->content_name(),
    930                                &transport_id)) {
    931     LOG(LS_ERROR) << "Failed to get transport name for proxy "
    932                   << session_->voice_channel()->content_name();
    933     return;
    934   }
    935   ExtractStatsFromList(voice_info.receivers, transport_id, this, kReceiving);
    936   ExtractStatsFromList(voice_info.senders, transport_id, this, kSending);
    937 
    938   UpdateStatsFromExistingLocalAudioTracks();
    939 }
    940 
    941 void StatsCollector::ExtractVideoInfo(
    942     PeerConnectionInterface::StatsOutputLevel level) {
    943   if (!session_->video_channel()) {
    944     return;
    945   }
    946   cricket::StatsOptions options;
    947   options.include_received_propagation_stats =
    948       (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
    949           true : false;
    950   cricket::VideoMediaInfo video_info;
    951   if (!session_->video_channel()->GetStats(options, &video_info)) {
    952     LOG(LS_ERROR) << "Failed to get video channel stats.";
    953     return;
    954   }
    955   std::string transport_id;
    956   if (!GetTransportIdFromProxy(proxy_to_transport_,
    957                                session_->video_channel()->content_name(),
    958                                &transport_id)) {
    959     LOG(LS_ERROR) << "Failed to get transport name for proxy "
    960                   << session_->video_channel()->content_name();
    961     return;
    962   }
    963   ExtractStatsFromList(video_info.receivers, transport_id, this, kReceiving);
    964   ExtractStatsFromList(video_info.senders, transport_id, this, kSending);
    965   if (video_info.bw_estimations.size() != 1) {
    966     LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
    967   } else {
    968     StatsReport* report =
    969         reports_.FindOrAddNew(StatsReport::kStatsReportVideoBweId);
    970     ExtractStats(
    971         video_info.bw_estimations[0], stats_gathering_started_, level, report);
    972   }
    973 }
    974 
    975 StatsReport* StatsCollector::GetReport(const std::string& type,
    976                                        const std::string& id,
    977                                        TrackDirection direction) {
    978   ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
    979          type == StatsReport::kStatsReportTypeRemoteSsrc);
    980   return reports_.Find(StatsId(type, id, direction));
    981 }
    982 
    983 StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
    984                                                const std::string& id,
    985                                                TrackDirection direction) {
    986   ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
    987          type == StatsReport::kStatsReportTypeRemoteSsrc);
    988   StatsReport* report = GetReport(type, id, direction);
    989   if (report == NULL) {
    990     std::string statsid = StatsId(type, id, direction);
    991     report = reports_.FindOrAddNew(statsid);
    992     ASSERT(report->id == statsid);
    993     report->type = type;
    994   }
    995 
    996   return report;
    997 }
    998 
    999 void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
   1000   // Loop through the existing local audio tracks.
   1001   for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
   1002        it != local_audio_tracks_.end(); ++it) {
   1003     AudioTrackInterface* track = it->first;
   1004     uint32 ssrc = it->second;
   1005     std::string ssrc_id = rtc::ToString<uint32>(ssrc);
   1006     StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
   1007                                     ssrc_id,
   1008                                     kSending);
   1009     if (report == NULL) {
   1010       // This can happen if a local audio track is added to a stream on the
   1011       // fly and the report has not been set up yet. Do nothing in this case.
   1012       LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
   1013       continue;
   1014     }
   1015 
   1016     // The same ssrc can be used by both local and remote audio tracks.
   1017     std::string track_id;
   1018     if (!ExtractValueFromReport(*report,
   1019                                 StatsReport::kStatsValueNameTrackId,
   1020                                 &track_id) ||
   1021         track_id != track->id()) {
   1022       continue;
   1023     }
   1024 
   1025     UpdateReportFromAudioTrack(track, report);
   1026   }
   1027 }
   1028 
   1029 void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
   1030                                                 StatsReport* report) {
   1031   ASSERT(track != NULL);
   1032   if (report == NULL)
   1033     return;
   1034 
   1035   int signal_level = 0;
   1036   if (track->GetSignalLevel(&signal_level)) {
   1037     report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
   1038                          rtc::ToString<int>(signal_level));
   1039   }
   1040 
   1041   rtc::scoped_refptr<AudioProcessorInterface> audio_processor(
   1042       track->GetAudioProcessor());
   1043   if (audio_processor.get() == NULL)
   1044     return;
   1045 
   1046   AudioProcessorInterface::AudioProcessorStats stats;
   1047   audio_processor->GetStats(&stats);
   1048   report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
   1049                        stats.typing_noise_detected ? "true" : "false");
   1050   report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
   1051                        rtc::ToString<int>(stats.echo_return_loss));
   1052   report->ReplaceValue(
   1053       StatsReport::kStatsValueNameEchoReturnLossEnhancement,
   1054       rtc::ToString<int>(stats.echo_return_loss_enhancement));
   1055   report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
   1056                        rtc::ToString<int>(stats.echo_delay_median_ms));
   1057   report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
   1058                        rtc::ToString<float>(stats.aec_quality_min));
   1059   report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
   1060                        rtc::ToString<int>(stats.echo_delay_std_ms));
   1061 }
   1062 
   1063 bool StatsCollector::GetTrackIdBySsrc(uint32 ssrc, std::string* track_id,
   1064                                       TrackDirection direction) {
   1065   if (direction == kSending) {
   1066     if (!session_->GetLocalTrackIdBySsrc(ssrc, track_id)) {
   1067       LOG(LS_WARNING) << "The SSRC " << ssrc
   1068                       << " is not associated with a sending track";
   1069       return false;
   1070     }
   1071   } else {
   1072     ASSERT(direction == kReceiving);
   1073     if (!session_->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
   1074       LOG(LS_WARNING) << "The SSRC " << ssrc
   1075                       << " is not associated with a receiving track";
   1076       return false;
   1077     }
   1078   }
   1079 
   1080   return true;
   1081 }
   1082 
   1083 void StatsCollector::ClearUpdateStatsCache() {
   1084   stats_gathering_started_ = 0;
   1085 }
   1086 
   1087 }  // namespace webrtc
   1088