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