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