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).
InternalTypeToString(StatsReport::StatsType type)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:
BandwidthEstimationId()83   BandwidthEstimationId()
84       : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {}
ToString() const85   std::string ToString() const override { return kStatsReportVideoBweId; }
86 };
87 
88 class TypedId : public StatsReport::IdBase {
89  public:
TypedId(StatsReport::StatsType type,const std::string & id)90   TypedId(StatsReport::StatsType type, const std::string& id)
91       : StatsReport::IdBase(type), id_(id) {}
92 
Equals(const IdBase & other) const93   bool Equals(const IdBase& other) const override {
94     return IdBase::Equals(other) &&
95            static_cast<const TypedId&>(other).id_ == id_;
96   }
97 
ToString() const98   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:
TypedIntId(StatsReport::StatsType type,int id)108   TypedIntId(StatsReport::StatsType type, int id)
109       : StatsReport::IdBase(type), id_(id) {}
110 
Equals(const IdBase & other) const111   bool Equals(const IdBase& other) const override {
112     return IdBase::Equals(other) &&
113            static_cast<const TypedIntId&>(other).id_ == id_;
114   }
115 
ToString() const116   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:
IdWithDirection(StatsReport::StatsType type,const std::string & id,StatsReport::Direction direction)128   IdWithDirection(StatsReport::StatsType type, const std::string& id,
129                   StatsReport::Direction direction)
130       : TypedId(type, id), direction_(direction) {}
131 
Equals(const IdBase & other) const132   bool Equals(const IdBase& other) const override {
133     return TypedId::Equals(other) &&
134            static_cast<const IdWithDirection&>(other).direction_ == direction_;
135   }
136 
ToString() const137   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:
CandidateId(bool local,const std::string & id)150   CandidateId(bool local, const std::string& id)
151       : TypedId(local ?
152                     StatsReport::kStatsReportTypeIceLocalCandidate :
153                     StatsReport::kStatsReportTypeIceRemoteCandidate,
154                 id) {
155   }
156 
ToString() const157   std::string ToString() const override {
158     return "Cand-" + id_;
159   }
160 };
161 
162 class ComponentId : public StatsReport::IdBase {
163  public:
ComponentId(const std::string & content_name,int component)164   ComponentId(const std::string& content_name, int component)
165       : ComponentId(StatsReport::kStatsReportTypeComponent, content_name,
166             component) {}
167 
Equals(const IdBase & other) const168   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 
ToString() const174   std::string ToString() const override {
175     return ToString("Channel-");
176   }
177 
178  protected:
ComponentId(StatsReport::StatsType type,const std::string & content_name,int component)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 
ToString(const char * prefix) const185   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:
CandidatePairId(const std::string & content_name,int component,int index)200   CandidatePairId(const std::string& content_name, int component, int index)
201       : ComponentId(StatsReport::kStatsReportTypeCandidatePair, content_name,
202             component),
203         index_(index) {}
204 
Equals(const IdBase & other) const205   bool Equals(const IdBase& other) const override {
206     return ComponentId::Equals(other) &&
207         static_cast<const CandidatePairId&>(other).index_ == index_;
208   }
209 
ToString() const210   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 
IdBase(StatsType type)223 StatsReport::IdBase::IdBase(StatsType type) : type_(type) {}
~IdBase()224 StatsReport::IdBase::~IdBase() {}
225 
type() const226 StatsReport::StatsType StatsReport::IdBase::type() const { return type_; }
227 
Equals(const IdBase & other) const228 bool StatsReport::IdBase::Equals(const IdBase& other) const {
229   return other.type_ == type_;
230 }
231 
Value(StatsValueName name,int64_t value,Type int_type)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 
Value(StatsValueName name,float f)238 StatsReport::Value::Value(StatsValueName name, float f)
239     : name(name), type_(kFloat) {
240   value_.float_ = f;
241 }
242 
Value(StatsValueName name,const std::string & value)243 StatsReport::Value::Value(StatsValueName name, const std::string& value)
244     : name(name), type_(kString) {
245   value_.string_ = new std::string(value);
246 }
247 
Value(StatsValueName name,const char * value)248 StatsReport::Value::Value(StatsValueName name, const char* value)
249     : name(name), type_(kStaticString) {
250   value_.static_string_ = value;
251 }
252 
Value(StatsValueName name,bool b)253 StatsReport::Value::Value(StatsValueName name, bool b)
254     : name(name), type_(kBool) {
255   value_.bool_ = b;
256 }
257 
Value(StatsValueName name,const Id & value)258 StatsReport::Value::Value(StatsValueName name, const Id& value)
259     : name(name), type_(kId) {
260   value_.id_ = new Id(value);
261 }
262 
~Value()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 
Equals(const Value & other) const280 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 
operator ==(const std::string & value) const316 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 
operator ==(const char * value) const321 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 
operator ==(int64_t value) const334 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 
operator ==(bool value) const339 bool StatsReport::Value::operator==(bool value) const {
340   return type_ == kBool && value_.bool_ == value;
341 }
342 
operator ==(float value) const343 bool StatsReport::Value::operator==(float value) const {
344   return type_ == kFloat && value_.float_ == value;
345 }
346 
operator ==(const Id & value) const347 bool StatsReport::Value::operator==(const Id& value) const {
348   return type_ == kId && (*value_.id_)->Equals(value);
349 }
350 
int_val() const351 int StatsReport::Value::int_val() const {
352   RTC_DCHECK(type_ == kInt);
353   return value_.int_;
354 }
355 
int64_val() const356 int64_t StatsReport::Value::int64_val() const {
357   RTC_DCHECK(type_ == kInt64);
358   return value_.int64_;
359 }
360 
float_val() const361 float StatsReport::Value::float_val() const {
362   RTC_DCHECK(type_ == kFloat);
363   return value_.float_;
364 }
365 
static_string_val() const366 const char* StatsReport::Value::static_string_val() const {
367   RTC_DCHECK(type_ == kStaticString);
368   return value_.static_string_;
369 }
370 
string_val() const371 const std::string& StatsReport::Value::string_val() const {
372   RTC_DCHECK(type_ == kString);
373   return *value_.string_;
374 }
375 
bool_val() const376 bool StatsReport::Value::bool_val() const {
377   RTC_DCHECK(type_ == kBool);
378   return value_.bool_;
379 }
380 
display_name() const381 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 
ToString() const602 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 
StatsReport(const Id & id)623 StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) {
624   RTC_DCHECK(id_.get());
625 }
626 
627 // static
NewBandwidthEstimationId()628 StatsReport::Id StatsReport::NewBandwidthEstimationId() {
629   return Id(new RefCountedObject<BandwidthEstimationId>());
630 }
631 
632 // static
NewTypedId(StatsType type,const std::string & id)633 StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) {
634   return Id(new RefCountedObject<TypedId>(type, id));
635 }
636 
637 // static
NewTypedIntId(StatsType type,int id)638 StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) {
639   return Id(new RefCountedObject<TypedIntId>(type, id));
640 }
641 
642 // static
NewIdWithDirection(StatsType type,const std::string & id,StatsReport::Direction direction)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
NewCandidateId(bool local,const std::string & id)649 StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) {
650   return Id(new RefCountedObject<CandidateId>(local, id));
651 }
652 
653 // static
NewComponentId(const std::string & content_name,int component)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
NewCandidatePairId(const std::string & content_name,int component,int index)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 
TypeToString() const666 const char* StatsReport::TypeToString() const {
667   return InternalTypeToString(id_->type());
668 }
669 
AddString(StatsReport::StatsValueName name,const std::string & value)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 
AddString(StatsReport::StatsValueName name,const char * value)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 
AddInt64(StatsReport::StatsValueName name,int64_t value)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 
AddInt(StatsReport::StatsValueName name,int value)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 
AddFloat(StatsReport::StatsValueName name,float value)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 
AddBoolean(StatsReport::StatsValueName name,bool value)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 
AddId(StatsReport::StatsValueName name,const Id & value)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 
FindValue(StatsValueName name) const715 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 
StatsCollection()720 StatsCollection::StatsCollection() {
721 }
722 
~StatsCollection()723 StatsCollection::~StatsCollection() {
724   RTC_DCHECK(thread_checker_.CalledOnValidThread());
725   for (auto* r : list_)
726     delete r;
727 }
728 
begin() const729 StatsCollection::const_iterator StatsCollection::begin() const {
730   RTC_DCHECK(thread_checker_.CalledOnValidThread());
731   return list_.begin();
732 }
733 
end() const734 StatsCollection::const_iterator StatsCollection::end() const {
735   RTC_DCHECK(thread_checker_.CalledOnValidThread());
736   return list_.end();
737 }
738 
size() const739 size_t StatsCollection::size() const {
740   RTC_DCHECK(thread_checker_.CalledOnValidThread());
741   return list_.size();
742 }
743 
InsertNew(const StatsReport::Id & id)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 
FindOrAddNew(const StatsReport::Id & id)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 
ReplaceOrAddNew(const StatsReport::Id & id)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.
Find(const StatsReport::Id & id)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