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