Home | History | Annotate | Download | only in webrtc
      1 /*
      2  * libjingle
      3  * Copyright 2014 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/statstypes.h"
     29 
     30 #include <string.h>
     31 
     32 #include "webrtc/base/checks.h"
     33 
     34 // TODO(tommi): Could we have a static map of value name -> expected type
     35 // and use this to RTC_DCHECK on correct usage (somewhat strongly typed values)?
     36 // Alternatively, we could define the names+type in a separate document and
     37 // generate strongly typed inline C++ code that forces the correct type to be
     38 // used for a given name at compile time.
     39 
     40 using rtc::RefCountedObject;
     41 
     42 namespace webrtc {
     43 namespace {
     44 
     45 // The id of StatsReport of type kStatsReportTypeBwe.
     46 const char kStatsReportVideoBweId[] = "bweforvideo";
     47 
     48 // NOTE: These names need to be consistent with an external
     49 // specification (W3C Stats Identifiers).
     50 const char* InternalTypeToString(StatsReport::StatsType type) {
     51   switch (type) {
     52     case StatsReport::kStatsReportTypeSession:
     53       return "googLibjingleSession";
     54     case StatsReport::kStatsReportTypeBwe:
     55       return "VideoBwe";
     56     case StatsReport::kStatsReportTypeRemoteSsrc:
     57       return "remoteSsrc";
     58     case StatsReport::kStatsReportTypeSsrc:
     59       return "ssrc";
     60     case StatsReport::kStatsReportTypeTrack:
     61       return "googTrack";
     62     case StatsReport::kStatsReportTypeIceLocalCandidate:
     63       return "localcandidate";
     64     case StatsReport::kStatsReportTypeIceRemoteCandidate:
     65       return "remotecandidate";
     66     case StatsReport::kStatsReportTypeTransport:
     67       return "transport";
     68     case StatsReport::kStatsReportTypeComponent:
     69       return "googComponent";
     70     case StatsReport::kStatsReportTypeCandidatePair:
     71       return "googCandidatePair";
     72     case StatsReport::kStatsReportTypeCertificate:
     73       return "googCertificate";
     74     case StatsReport::kStatsReportTypeDataChannel:
     75       return "datachannel";
     76   }
     77   RTC_DCHECK(false);
     78   return nullptr;
     79 }
     80 
     81 class BandwidthEstimationId : public StatsReport::IdBase {
     82  public:
     83   BandwidthEstimationId()
     84       : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {}
     85   std::string ToString() const override { return kStatsReportVideoBweId; }
     86 };
     87 
     88 class TypedId : public StatsReport::IdBase {
     89  public:
     90   TypedId(StatsReport::StatsType type, const std::string& id)
     91       : StatsReport::IdBase(type), id_(id) {}
     92 
     93   bool Equals(const IdBase& other) const override {
     94     return IdBase::Equals(other) &&
     95            static_cast<const TypedId&>(other).id_ == id_;
     96   }
     97 
     98   std::string ToString() const override {
     99     return std::string(InternalTypeToString(type_)) + kSeparator + id_;
    100   }
    101 
    102  protected:
    103   const std::string id_;
    104 };
    105 
    106 class TypedIntId : public StatsReport::IdBase {
    107  public:
    108   TypedIntId(StatsReport::StatsType type, int id)
    109       : StatsReport::IdBase(type), id_(id) {}
    110 
    111   bool Equals(const IdBase& other) const override {
    112     return IdBase::Equals(other) &&
    113            static_cast<const TypedIntId&>(other).id_ == id_;
    114   }
    115 
    116   std::string ToString() const override {
    117     return std::string(InternalTypeToString(type_)) +
    118            kSeparator +
    119            rtc::ToString<int>(id_);
    120   }
    121 
    122  protected:
    123   const int id_;
    124 };
    125 
    126 class IdWithDirection : public TypedId {
    127  public:
    128   IdWithDirection(StatsReport::StatsType type, const std::string& id,
    129                   StatsReport::Direction direction)
    130       : TypedId(type, id), direction_(direction) {}
    131 
    132   bool Equals(const IdBase& other) const override {
    133     return TypedId::Equals(other) &&
    134            static_cast<const IdWithDirection&>(other).direction_ == direction_;
    135   }
    136 
    137   std::string ToString() const override {
    138     std::string ret(TypedId::ToString());
    139     ret += kSeparator;
    140     ret += direction_ == StatsReport::kSend ? "send" : "recv";
    141     return ret;
    142   }
    143 
    144  private:
    145   const StatsReport::Direction direction_;
    146 };
    147 
    148 class CandidateId : public TypedId {
    149  public:
    150   CandidateId(bool local, const std::string& id)
    151       : TypedId(local ?
    152                     StatsReport::kStatsReportTypeIceLocalCandidate :
    153                     StatsReport::kStatsReportTypeIceRemoteCandidate,
    154                 id) {
    155   }
    156 
    157   std::string ToString() const override {
    158     return "Cand-" + id_;
    159   }
    160 };
    161 
    162 class ComponentId : public StatsReport::IdBase {
    163  public:
    164   ComponentId(const std::string& content_name, int component)
    165       : ComponentId(StatsReport::kStatsReportTypeComponent, content_name,
    166             component) {}
    167 
    168   bool Equals(const IdBase& other) const override {
    169     return IdBase::Equals(other) &&
    170         static_cast<const ComponentId&>(other).component_ == component_ &&
    171         static_cast<const ComponentId&>(other).content_name_ == content_name_;
    172   }
    173 
    174   std::string ToString() const override {
    175     return ToString("Channel-");
    176   }
    177 
    178  protected:
    179   ComponentId(StatsReport::StatsType type, const std::string& content_name,
    180               int component)
    181       : IdBase(type),
    182         content_name_(content_name),
    183         component_(component) {}
    184 
    185   std::string ToString(const char* prefix) const {
    186     std::string ret(prefix);
    187     ret += content_name_;
    188     ret += '-';
    189     ret += rtc::ToString<>(component_);
    190     return ret;
    191   }
    192 
    193  private:
    194   const std::string content_name_;
    195   const int component_;
    196 };
    197 
    198 class CandidatePairId : public ComponentId {
    199  public:
    200   CandidatePairId(const std::string& content_name, int component, int index)
    201       : ComponentId(StatsReport::kStatsReportTypeCandidatePair, content_name,
    202             component),
    203         index_(index) {}
    204 
    205   bool Equals(const IdBase& other) const override {
    206     return ComponentId::Equals(other) &&
    207         static_cast<const CandidatePairId&>(other).index_ == index_;
    208   }
    209 
    210   std::string ToString() const override {
    211     std::string ret(ComponentId::ToString("Conn-"));
    212     ret += '-';
    213     ret += rtc::ToString<>(index_);
    214     return ret;
    215   }
    216 
    217  private:
    218   const int index_;
    219 };
    220 
    221 }  // namespace
    222 
    223 StatsReport::IdBase::IdBase(StatsType type) : type_(type) {}
    224 StatsReport::IdBase::~IdBase() {}
    225 
    226 StatsReport::StatsType StatsReport::IdBase::type() const { return type_; }
    227 
    228 bool StatsReport::IdBase::Equals(const IdBase& other) const {
    229   return other.type_ == type_;
    230 }
    231 
    232 StatsReport::Value::Value(StatsValueName name, int64_t value, Type int_type)
    233     : name(name), type_(int_type) {
    234   RTC_DCHECK(type_ == kInt || type_ == kInt64);
    235   type_ == kInt ? value_.int_ = static_cast<int>(value) : value_.int64_ = value;
    236 }
    237 
    238 StatsReport::Value::Value(StatsValueName name, float f)
    239     : name(name), type_(kFloat) {
    240   value_.float_ = f;
    241 }
    242 
    243 StatsReport::Value::Value(StatsValueName name, const std::string& value)
    244     : name(name), type_(kString) {
    245   value_.string_ = new std::string(value);
    246 }
    247 
    248 StatsReport::Value::Value(StatsValueName name, const char* value)
    249     : name(name), type_(kStaticString) {
    250   value_.static_string_ = value;
    251 }
    252 
    253 StatsReport::Value::Value(StatsValueName name, bool b)
    254     : name(name), type_(kBool) {
    255   value_.bool_ = b;
    256 }
    257 
    258 StatsReport::Value::Value(StatsValueName name, const Id& value)
    259     : name(name), type_(kId) {
    260   value_.id_ = new Id(value);
    261 }
    262 
    263 StatsReport::Value::~Value() {
    264   switch (type_) {
    265     case kInt:
    266     case kInt64:
    267     case kFloat:
    268     case kBool:
    269     case kStaticString:
    270       break;
    271     case kString:
    272       delete value_.string_;
    273       break;
    274     case kId:
    275       delete value_.id_;
    276       break;
    277   }
    278 }
    279 
    280 bool StatsReport::Value::Equals(const Value& other) const {
    281   if (name != other.name)
    282     return false;
    283 
    284   // There's a 1:1 relation between a name and a type, so we don't have to
    285   // check that.
    286   RTC_DCHECK_EQ(type_, other.type_);
    287 
    288   switch (type_) {
    289     case kInt:
    290       return value_.int_ == other.value_.int_;
    291     case kInt64:
    292       return value_.int64_ == other.value_.int64_;
    293     case kFloat:
    294       return value_.float_ == other.value_.float_;
    295     case kStaticString: {
    296 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
    297       if (value_.static_string_ != other.value_.static_string_) {
    298         RTC_DCHECK(strcmp(value_.static_string_, other.value_.static_string_) !=
    299                    0)
    300             << "Duplicate global?";
    301       }
    302 #endif
    303       return value_.static_string_ == other.value_.static_string_;
    304     }
    305     case kString:
    306       return *value_.string_ == *other.value_.string_;
    307     case kBool:
    308       return value_.bool_ == other.value_.bool_;
    309     case kId:
    310       return (*value_.id_)->Equals(*other.value_.id_);
    311   }
    312   RTC_NOTREACHED();
    313   return false;
    314 }
    315 
    316 bool StatsReport::Value::operator==(const std::string& value) const {
    317   return (type_ == kString && value_.string_->compare(value) == 0) ||
    318          (type_ == kStaticString && value.compare(value_.static_string_) == 0);
    319 }
    320 
    321 bool StatsReport::Value::operator==(const char* value) const {
    322   if (type_ == kString)
    323     return value_.string_->compare(value) == 0;
    324   if (type_ != kStaticString)
    325     return false;
    326 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
    327   if (value_.static_string_ != value)
    328     RTC_DCHECK(strcmp(value_.static_string_, value) != 0)
    329         << "Duplicate global?";
    330 #endif
    331   return value == value_.static_string_;
    332 }
    333 
    334 bool StatsReport::Value::operator==(int64_t value) const {
    335   return type_ == kInt ? value_.int_ == static_cast<int>(value) :
    336       (type_ == kInt64 ? value_.int64_ == value : false);
    337 }
    338 
    339 bool StatsReport::Value::operator==(bool value) const {
    340   return type_ == kBool && value_.bool_ == value;
    341 }
    342 
    343 bool StatsReport::Value::operator==(float value) const {
    344   return type_ == kFloat && value_.float_ == value;
    345 }
    346 
    347 bool StatsReport::Value::operator==(const Id& value) const {
    348   return type_ == kId && (*value_.id_)->Equals(value);
    349 }
    350 
    351 int StatsReport::Value::int_val() const {
    352   RTC_DCHECK(type_ == kInt);
    353   return value_.int_;
    354 }
    355 
    356 int64_t StatsReport::Value::int64_val() const {
    357   RTC_DCHECK(type_ == kInt64);
    358   return value_.int64_;
    359 }
    360 
    361 float StatsReport::Value::float_val() const {
    362   RTC_DCHECK(type_ == kFloat);
    363   return value_.float_;
    364 }
    365 
    366 const char* StatsReport::Value::static_string_val() const {
    367   RTC_DCHECK(type_ == kStaticString);
    368   return value_.static_string_;
    369 }
    370 
    371 const std::string& StatsReport::Value::string_val() const {
    372   RTC_DCHECK(type_ == kString);
    373   return *value_.string_;
    374 }
    375 
    376 bool StatsReport::Value::bool_val() const {
    377   RTC_DCHECK(type_ == kBool);
    378   return value_.bool_;
    379 }
    380 
    381 const char* StatsReport::Value::display_name() const {
    382   switch (name) {
    383     case kStatsValueNameAudioOutputLevel:
    384       return "audioOutputLevel";
    385     case kStatsValueNameAudioInputLevel:
    386       return "audioInputLevel";
    387     case kStatsValueNameBytesSent:
    388       return "bytesSent";
    389     case kStatsValueNamePacketsSent:
    390       return "packetsSent";
    391     case kStatsValueNameBytesReceived:
    392       return "bytesReceived";
    393     case kStatsValueNameLabel:
    394       return "label";
    395     case kStatsValueNamePacketsReceived:
    396       return "packetsReceived";
    397     case kStatsValueNamePacketsLost:
    398       return "packetsLost";
    399     case kStatsValueNameProtocol:
    400       return "protocol";
    401     case kStatsValueNameTransportId:
    402       return "transportId";
    403     case kStatsValueNameSelectedCandidatePairId:
    404       return "selectedCandidatePairId";
    405     case kStatsValueNameSsrc:
    406       return "ssrc";
    407     case kStatsValueNameState:
    408       return "state";
    409     case kStatsValueNameDataChannelId:
    410       return "datachannelid";
    411     case kStatsValueNameCodecImplementationName:
    412       return "codecImplementationName";
    413 
    414     // 'goog' prefixed constants.
    415     case kStatsValueNameAccelerateRate:
    416       return "googAccelerateRate";
    417     case kStatsValueNameActiveConnection:
    418       return "googActiveConnection";
    419     case kStatsValueNameActualEncBitrate:
    420       return "googActualEncBitrate";
    421     case kStatsValueNameAvailableReceiveBandwidth:
    422       return "googAvailableReceiveBandwidth";
    423     case kStatsValueNameAvailableSendBandwidth:
    424       return "googAvailableSendBandwidth";
    425     case kStatsValueNameAvgEncodeMs:
    426       return "googAvgEncodeMs";
    427     case kStatsValueNameBucketDelay:
    428       return "googBucketDelay";
    429     case kStatsValueNameBandwidthLimitedResolution:
    430       return "googBandwidthLimitedResolution";
    431 
    432     // Candidate related attributes. Values are taken from
    433     // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
    434     case kStatsValueNameCandidateIPAddress:
    435       return "ipAddress";
    436     case kStatsValueNameCandidateNetworkType:
    437       return "networkType";
    438     case kStatsValueNameCandidatePortNumber:
    439       return "portNumber";
    440     case kStatsValueNameCandidatePriority:
    441       return "priority";
    442     case kStatsValueNameCandidateTransportType:
    443       return "transport";
    444     case kStatsValueNameCandidateType:
    445       return "candidateType";
    446 
    447     case kStatsValueNameChannelId:
    448       return "googChannelId";
    449     case kStatsValueNameCodecName:
    450       return "googCodecName";
    451     case kStatsValueNameComponent:
    452       return "googComponent";
    453     case kStatsValueNameContentName:
    454       return "googContentName";
    455     case kStatsValueNameCpuLimitedResolution:
    456       return "googCpuLimitedResolution";
    457     case kStatsValueNameDecodingCTSG:
    458       return "googDecodingCTSG";
    459     case kStatsValueNameDecodingCTN:
    460       return "googDecodingCTN";
    461     case kStatsValueNameDecodingNormal:
    462       return "googDecodingNormal";
    463     case kStatsValueNameDecodingPLC:
    464       return "googDecodingPLC";
    465     case kStatsValueNameDecodingCNG:
    466       return "googDecodingCNG";
    467     case kStatsValueNameDecodingPLCCNG:
    468       return "googDecodingPLCCNG";
    469     case kStatsValueNameDer:
    470       return "googDerBase64";
    471     case kStatsValueNameDtlsCipher:
    472       return "dtlsCipher";
    473     case kStatsValueNameEchoCancellationQualityMin:
    474       return "googEchoCancellationQualityMin";
    475     case kStatsValueNameEchoDelayMedian:
    476       return "googEchoCancellationEchoDelayMedian";
    477     case kStatsValueNameEchoDelayStdDev:
    478       return "googEchoCancellationEchoDelayStdDev";
    479     case kStatsValueNameEchoReturnLoss:
    480       return "googEchoCancellationReturnLoss";
    481     case kStatsValueNameEchoReturnLossEnhancement:
    482       return "googEchoCancellationReturnLossEnhancement";
    483     case kStatsValueNameEncodeUsagePercent:
    484       return "googEncodeUsagePercent";
    485     case kStatsValueNameExpandRate:
    486       return "googExpandRate";
    487     case kStatsValueNameFingerprint:
    488       return "googFingerprint";
    489     case kStatsValueNameFingerprintAlgorithm:
    490       return "googFingerprintAlgorithm";
    491     case kStatsValueNameFirsReceived:
    492       return "googFirsReceived";
    493     case kStatsValueNameFirsSent:
    494       return "googFirsSent";
    495     case kStatsValueNameFrameHeightInput:
    496       return "googFrameHeightInput";
    497     case kStatsValueNameFrameHeightReceived:
    498       return "googFrameHeightReceived";
    499     case kStatsValueNameFrameHeightSent:
    500       return "googFrameHeightSent";
    501     case kStatsValueNameFrameRateReceived:
    502       return "googFrameRateReceived";
    503     case kStatsValueNameFrameRateDecoded:
    504       return "googFrameRateDecoded";
    505     case kStatsValueNameFrameRateOutput:
    506       return "googFrameRateOutput";
    507     case kStatsValueNameDecodeMs:
    508       return "googDecodeMs";
    509     case kStatsValueNameMaxDecodeMs:
    510       return "googMaxDecodeMs";
    511     case kStatsValueNameCurrentDelayMs:
    512       return "googCurrentDelayMs";
    513     case kStatsValueNameTargetDelayMs:
    514       return "googTargetDelayMs";
    515     case kStatsValueNameJitterBufferMs:
    516       return "googJitterBufferMs";
    517     case kStatsValueNameMinPlayoutDelayMs:
    518       return "googMinPlayoutDelayMs";
    519     case kStatsValueNameRenderDelayMs:
    520       return "googRenderDelayMs";
    521     case kStatsValueNameCaptureStartNtpTimeMs:
    522       return "googCaptureStartNtpTimeMs";
    523     case kStatsValueNameFrameRateInput:
    524       return "googFrameRateInput";
    525     case kStatsValueNameFrameRateSent:
    526       return "googFrameRateSent";
    527     case kStatsValueNameFrameWidthInput:
    528       return "googFrameWidthInput";
    529     case kStatsValueNameFrameWidthReceived:
    530       return "googFrameWidthReceived";
    531     case kStatsValueNameFrameWidthSent:
    532       return "googFrameWidthSent";
    533     case kStatsValueNameInitiator:
    534       return "googInitiator";
    535     case kStatsValueNameIssuerId:
    536       return "googIssuerId";
    537     case kStatsValueNameJitterReceived:
    538       return "googJitterReceived";
    539     case kStatsValueNameLocalAddress:
    540       return "googLocalAddress";
    541     case kStatsValueNameLocalCandidateId:
    542       return "localCandidateId";
    543     case kStatsValueNameLocalCandidateType:
    544       return "googLocalCandidateType";
    545     case kStatsValueNameLocalCertificateId:
    546       return "localCertificateId";
    547     case kStatsValueNameAdaptationChanges:
    548       return "googAdaptationChanges";
    549     case kStatsValueNameNacksReceived:
    550       return "googNacksReceived";
    551     case kStatsValueNameNacksSent:
    552       return "googNacksSent";
    553     case kStatsValueNamePreemptiveExpandRate:
    554       return "googPreemptiveExpandRate";
    555     case kStatsValueNamePlisReceived:
    556       return "googPlisReceived";
    557     case kStatsValueNamePlisSent:
    558       return "googPlisSent";
    559     case kStatsValueNamePreferredJitterBufferMs:
    560       return "googPreferredJitterBufferMs";
    561     case kStatsValueNameReceiving:
    562       return "googReadable";
    563     case kStatsValueNameRemoteAddress:
    564       return "googRemoteAddress";
    565     case kStatsValueNameRemoteCandidateId:
    566       return "remoteCandidateId";
    567     case kStatsValueNameRemoteCandidateType:
    568       return "googRemoteCandidateType";
    569     case kStatsValueNameRemoteCertificateId:
    570       return "remoteCertificateId";
    571     case kStatsValueNameRetransmitBitrate:
    572       return "googRetransmitBitrate";
    573     case kStatsValueNameRtt:
    574       return "googRtt";
    575     case kStatsValueNameSecondaryDecodedRate:
    576       return "googSecondaryDecodedRate";
    577     case kStatsValueNameSendPacketsDiscarded:
    578       return "packetsDiscardedOnSend";
    579     case kStatsValueNameSpeechExpandRate:
    580       return "googSpeechExpandRate";
    581     case kStatsValueNameSrtpCipher:
    582       return "srtpCipher";
    583     case kStatsValueNameTargetEncBitrate:
    584       return "googTargetEncBitrate";
    585     case kStatsValueNameTransmitBitrate:
    586       return "googTransmitBitrate";
    587     case kStatsValueNameTransportType:
    588       return "googTransportType";
    589     case kStatsValueNameTrackId:
    590       return "googTrackId";
    591     case kStatsValueNameTypingNoiseState:
    592       return "googTypingNoiseState";
    593     case kStatsValueNameViewLimitedResolution:
    594       return "googViewLimitedResolution";
    595     case kStatsValueNameWritable:
    596       return "googWritable";
    597   }
    598 
    599   return nullptr;
    600 }
    601 
    602 std::string StatsReport::Value::ToString() const {
    603   switch (type_) {
    604     case kInt:
    605       return rtc::ToString(value_.int_);
    606     case kInt64:
    607       return rtc::ToString(value_.int64_);
    608     case kFloat:
    609       return rtc::ToString(value_.float_);
    610     case kStaticString:
    611       return std::string(value_.static_string_);
    612     case kString:
    613       return *value_.string_;
    614     case kBool:
    615       return value_.bool_ ? "true" : "false";
    616     case kId:
    617       return (*value_.id_)->ToString();
    618   }
    619   RTC_NOTREACHED();
    620   return std::string();
    621 }
    622 
    623 StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) {
    624   RTC_DCHECK(id_.get());
    625 }
    626 
    627 // static
    628 StatsReport::Id StatsReport::NewBandwidthEstimationId() {
    629   return Id(new RefCountedObject<BandwidthEstimationId>());
    630 }
    631 
    632 // static
    633 StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) {
    634   return Id(new RefCountedObject<TypedId>(type, id));
    635 }
    636 
    637 // static
    638 StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) {
    639   return Id(new RefCountedObject<TypedIntId>(type, id));
    640 }
    641 
    642 // static
    643 StatsReport::Id StatsReport::NewIdWithDirection(
    644     StatsType type, const std::string& id, StatsReport::Direction direction) {
    645   return Id(new RefCountedObject<IdWithDirection>(type, id, direction));
    646 }
    647 
    648 // static
    649 StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) {
    650   return Id(new RefCountedObject<CandidateId>(local, id));
    651 }
    652 
    653 // static
    654 StatsReport::Id StatsReport::NewComponentId(
    655     const std::string& content_name, int component) {
    656   return Id(new RefCountedObject<ComponentId>(content_name, component));
    657 }
    658 
    659 // static
    660 StatsReport::Id StatsReport::NewCandidatePairId(
    661     const std::string& content_name, int component, int index) {
    662   return Id(new RefCountedObject<CandidatePairId>(
    663       content_name, component, index));
    664 }
    665 
    666 const char* StatsReport::TypeToString() const {
    667   return InternalTypeToString(id_->type());
    668 }
    669 
    670 void StatsReport::AddString(StatsReport::StatsValueName name,
    671                             const std::string& value) {
    672   const Value* found = FindValue(name);
    673   if (!found || !(*found == value))
    674     values_[name] = ValuePtr(new Value(name, value));
    675 }
    676 
    677 void StatsReport::AddString(StatsReport::StatsValueName name,
    678                             const char* value) {
    679   const Value* found = FindValue(name);
    680   if (!found || !(*found == value))
    681     values_[name] = ValuePtr(new Value(name, value));
    682 }
    683 
    684 void StatsReport::AddInt64(StatsReport::StatsValueName name, int64_t value) {
    685   const Value* found = FindValue(name);
    686   if (!found || !(*found == value))
    687     values_[name] = ValuePtr(new Value(name, value, Value::kInt64));
    688 }
    689 
    690 void StatsReport::AddInt(StatsReport::StatsValueName name, int value) {
    691   const Value* found = FindValue(name);
    692   if (!found || !(*found == static_cast<int64_t>(value)))
    693     values_[name] = ValuePtr(new Value(name, value, Value::kInt));
    694 }
    695 
    696 void StatsReport::AddFloat(StatsReport::StatsValueName name, float value) {
    697   const Value* found = FindValue(name);
    698   if (!found || !(*found == value))
    699     values_[name] = ValuePtr(new Value(name, value));
    700 }
    701 
    702 void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) {
    703   const Value* found = FindValue(name);
    704   if (!found || !(*found == value))
    705     values_[name] = ValuePtr(new Value(name, value));
    706 }
    707 
    708 void StatsReport::AddId(StatsReport::StatsValueName name,
    709                         const Id& value) {
    710   const Value* found = FindValue(name);
    711   if (!found || !(*found == value))
    712     values_[name] = ValuePtr(new Value(name, value));
    713 }
    714 
    715 const StatsReport::Value* StatsReport::FindValue(StatsValueName name) const {
    716   Values::const_iterator it = values_.find(name);
    717   return it == values_.end() ? nullptr : it->second.get();
    718 }
    719 
    720 StatsCollection::StatsCollection() {
    721 }
    722 
    723 StatsCollection::~StatsCollection() {
    724   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    725   for (auto* r : list_)
    726     delete r;
    727 }
    728 
    729 StatsCollection::const_iterator StatsCollection::begin() const {
    730   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    731   return list_.begin();
    732 }
    733 
    734 StatsCollection::const_iterator StatsCollection::end() const {
    735   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    736   return list_.end();
    737 }
    738 
    739 size_t StatsCollection::size() const {
    740   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    741   return list_.size();
    742 }
    743 
    744 StatsReport* StatsCollection::InsertNew(const StatsReport::Id& id) {
    745   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    746   RTC_DCHECK(Find(id) == nullptr);
    747   StatsReport* report = new StatsReport(id);
    748   list_.push_back(report);
    749   return report;
    750 }
    751 
    752 StatsReport* StatsCollection::FindOrAddNew(const StatsReport::Id& id) {
    753   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    754   StatsReport* ret = Find(id);
    755   return ret ? ret : InsertNew(id);
    756 }
    757 
    758 StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) {
    759   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    760   RTC_DCHECK(id.get());
    761   Container::iterator it = std::find_if(list_.begin(), list_.end(),
    762       [&id](const StatsReport* r)->bool { return r->id()->Equals(id); });
    763   if (it != end()) {
    764     StatsReport* report = new StatsReport((*it)->id());
    765     delete *it;
    766     *it = report;
    767     return report;
    768   }
    769   return InsertNew(id);
    770 }
    771 
    772 // Looks for a report with the given |id|.  If one is not found, NULL
    773 // will be returned.
    774 StatsReport* StatsCollection::Find(const StatsReport::Id& id) {
    775   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    776   Container::iterator it = std::find_if(list_.begin(), list_.end(),
    777       [&id](const StatsReport* r)->bool { return r->id()->Equals(id); });
    778   return it == list_.end() ? nullptr : *it;
    779 }
    780 
    781 }  // namespace webrtc
    782