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