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/legacy_stats_types.h"
12
13 #include <string.h>
14
15 #include "absl/algorithm/container.h"
16 #include "api/make_ref_counted.h"
17 #include "rtc_base/checks.h"
18 #include "rtc_base/string_encode.h"
19
20 // TODO(tommi): Could we have a static map of value name -> expected type
21 // and use this to RTC_DCHECK on correct usage (somewhat strongly typed values)?
22 // Alternatively, we could define the names+type in a separate document and
23 // generate strongly typed inline C++ code that forces the correct type to be
24 // used for a given name at compile time.
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_DCHECK_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_)) + kSeparator +
102 rtc::ToString(id_);
103 }
104
105 protected:
106 const int id_;
107 };
108
109 class IdWithDirection : public TypedId {
110 public:
IdWithDirection(StatsReport::StatsType type,const std::string & id,StatsReport::Direction direction)111 IdWithDirection(StatsReport::StatsType type,
112 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 ? StatsReport::kStatsReportTypeIceLocalCandidate
136 : StatsReport::kStatsReportTypeIceRemoteCandidate,
137 id) {}
138
ToString() const139 std::string ToString() const override { return "Cand-" + id_; }
140 };
141
142 class ComponentId : public StatsReport::IdBase {
143 public:
ComponentId(const std::string & content_name,int component)144 ComponentId(const std::string& content_name, int component)
145 : ComponentId(StatsReport::kStatsReportTypeComponent,
146 content_name,
147 component) {}
148
Equals(const IdBase & other) const149 bool Equals(const IdBase& other) const override {
150 return IdBase::Equals(other) &&
151 static_cast<const ComponentId&>(other).component_ == component_ &&
152 static_cast<const ComponentId&>(other).content_name_ ==
153 content_name_;
154 }
155
ToString() const156 std::string ToString() const override { return ToString("Channel-"); }
157
158 protected:
ComponentId(StatsReport::StatsType type,const std::string & content_name,int component)159 ComponentId(StatsReport::StatsType type,
160 const std::string& content_name,
161 int component)
162 : IdBase(type), content_name_(content_name), component_(component) {}
163
ToString(const char * prefix) const164 std::string ToString(const char* prefix) const {
165 std::string ret(prefix);
166 ret += content_name_;
167 ret += '-';
168 ret += rtc::ToString(component_);
169 return ret;
170 }
171
172 private:
173 const std::string content_name_;
174 const int component_;
175 };
176
177 class CandidatePairId : public ComponentId {
178 public:
CandidatePairId(const std::string & content_name,int component,int index)179 CandidatePairId(const std::string& content_name, int component, int index)
180 : ComponentId(StatsReport::kStatsReportTypeCandidatePair,
181 content_name,
182 component),
183 index_(index) {}
184
Equals(const IdBase & other) const185 bool Equals(const IdBase& other) const override {
186 return ComponentId::Equals(other) &&
187 static_cast<const CandidatePairId&>(other).index_ == index_;
188 }
189
ToString() const190 std::string ToString() const override {
191 std::string ret(ComponentId::ToString("Conn-"));
192 ret += '-';
193 ret += rtc::ToString(index_);
194 return ret;
195 }
196
197 private:
198 const int index_;
199 };
200
201 } // namespace
202
IdBase(StatsType type)203 StatsReport::IdBase::IdBase(StatsType type) : type_(type) {}
~IdBase()204 StatsReport::IdBase::~IdBase() {}
205
type() const206 StatsReport::StatsType StatsReport::IdBase::type() const {
207 return type_;
208 }
209
Equals(const IdBase & other) const210 bool StatsReport::IdBase::Equals(const IdBase& other) const {
211 return other.type_ == type_;
212 }
213
Value(StatsValueName name,int64_t value,Type int_type)214 StatsReport::Value::Value(StatsValueName name, int64_t value, Type int_type)
215 : name(name), type_(int_type) {
216 RTC_DCHECK(type_ == kInt || type_ == kInt64);
217 type_ == kInt ? value_.int_ = static_cast<int>(value) : value_.int64_ = value;
218 }
219
Value(StatsValueName name,float f)220 StatsReport::Value::Value(StatsValueName name, float f)
221 : name(name), type_(kFloat) {
222 value_.float_ = f;
223 }
224
Value(StatsValueName name,const std::string & value)225 StatsReport::Value::Value(StatsValueName name, const std::string& value)
226 : name(name), type_(kString) {
227 value_.string_ = new std::string(value);
228 }
229
Value(StatsValueName name,const char * value)230 StatsReport::Value::Value(StatsValueName name, const char* value)
231 : name(name), type_(kStaticString) {
232 value_.static_string_ = value;
233 }
234
Value(StatsValueName name,bool b)235 StatsReport::Value::Value(StatsValueName name, bool b)
236 : name(name), type_(kBool) {
237 value_.bool_ = b;
238 }
239
Value(StatsValueName name,const Id & value)240 StatsReport::Value::Value(StatsValueName name, const Id& value)
241 : name(name), type_(kId) {
242 value_.id_ = new Id(value);
243 }
244
~Value()245 StatsReport::Value::~Value() {
246 switch (type_) {
247 case kInt:
248 case kInt64:
249 case kFloat:
250 case kBool:
251 case kStaticString:
252 break;
253 case kString:
254 delete value_.string_;
255 break;
256 case kId:
257 delete value_.id_;
258 break;
259 }
260 }
261
Equals(const Value & other) const262 bool StatsReport::Value::Equals(const Value& other) const {
263 if (name != other.name)
264 return false;
265
266 // There's a 1:1 relation between a name and a type, so we don't have to
267 // check that.
268 RTC_DCHECK_EQ(type_, other.type_);
269
270 switch (type_) {
271 case kInt:
272 return value_.int_ == other.value_.int_;
273 case kInt64:
274 return value_.int64_ == other.value_.int64_;
275 case kFloat:
276 return value_.float_ == other.value_.float_;
277 case kStaticString: {
278 #if RTC_DCHECK_IS_ON
279 if (value_.static_string_ != other.value_.static_string_) {
280 RTC_DCHECK(strcmp(value_.static_string_, other.value_.static_string_) !=
281 0)
282 << "Duplicate global?";
283 }
284 #endif
285 return value_.static_string_ == other.value_.static_string_;
286 }
287 case kString:
288 return *value_.string_ == *other.value_.string_;
289 case kBool:
290 return value_.bool_ == other.value_.bool_;
291 case kId:
292 return (*value_.id_)->Equals(*other.value_.id_);
293 }
294 RTC_DCHECK_NOTREACHED();
295 return false;
296 }
297
operator ==(const std::string & value) const298 bool StatsReport::Value::operator==(const std::string& value) const {
299 return (type_ == kString && value_.string_->compare(value) == 0) ||
300 (type_ == kStaticString && value.compare(value_.static_string_) == 0);
301 }
302
operator ==(const char * value) const303 bool StatsReport::Value::operator==(const char* value) const {
304 if (type_ == kString)
305 return value_.string_->compare(value) == 0;
306 if (type_ != kStaticString)
307 return false;
308 #if RTC_DCHECK_IS_ON
309 if (value_.static_string_ != value)
310 RTC_DCHECK(strcmp(value_.static_string_, value) != 0)
311 << "Duplicate global?";
312 #endif
313 return value == value_.static_string_;
314 }
315
operator ==(int64_t value) const316 bool StatsReport::Value::operator==(int64_t value) const {
317 return type_ == kInt ? value_.int_ == static_cast<int>(value)
318 : (type_ == kInt64 ? value_.int64_ == value : false);
319 }
320
operator ==(bool value) const321 bool StatsReport::Value::operator==(bool value) const {
322 return type_ == kBool && value_.bool_ == value;
323 }
324
operator ==(float value) const325 bool StatsReport::Value::operator==(float value) const {
326 return type_ == kFloat && value_.float_ == value;
327 }
328
operator ==(const Id & value) const329 bool StatsReport::Value::operator==(const Id& value) const {
330 return type_ == kId && (*value_.id_)->Equals(value);
331 }
332
int_val() const333 int StatsReport::Value::int_val() const {
334 RTC_DCHECK_EQ(type_, kInt);
335 return value_.int_;
336 }
337
int64_val() const338 int64_t StatsReport::Value::int64_val() const {
339 RTC_DCHECK_EQ(type_, kInt64);
340 return value_.int64_;
341 }
342
float_val() const343 float StatsReport::Value::float_val() const {
344 RTC_DCHECK_EQ(type_, kFloat);
345 return value_.float_;
346 }
347
static_string_val() const348 const char* StatsReport::Value::static_string_val() const {
349 RTC_DCHECK_EQ(type_, kStaticString);
350 return value_.static_string_;
351 }
352
string_val() const353 const std::string& StatsReport::Value::string_val() const {
354 RTC_DCHECK_EQ(type_, kString);
355 return *value_.string_;
356 }
357
bool_val() const358 bool StatsReport::Value::bool_val() const {
359 RTC_DCHECK_EQ(type_, kBool);
360 return value_.bool_;
361 }
362
display_name() const363 const char* StatsReport::Value::display_name() const {
364 switch (name) {
365 case kStatsValueNameAecDivergentFilterFraction:
366 return "aecDivergentFilterFraction";
367 case kStatsValueNameAudioOutputLevel:
368 return "audioOutputLevel";
369 case kStatsValueNameAudioInputLevel:
370 return "audioInputLevel";
371 case kStatsValueNameBytesSent:
372 return "bytesSent";
373 case kStatsValueNameConcealedSamples:
374 return "concealedSamples";
375 case kStatsValueNameConcealmentEvents:
376 return "concealmentEvents";
377 case kStatsValueNamePacketsSent:
378 return "packetsSent";
379 case kStatsValueNameBytesReceived:
380 return "bytesReceived";
381 case kStatsValueNameLabel:
382 return "label";
383 case kStatsValueNamePacketsReceived:
384 return "packetsReceived";
385 case kStatsValueNamePacketsLost:
386 return "packetsLost";
387 case kStatsValueNameProtocol:
388 return "protocol";
389 case kStatsValueNameTotalSamplesReceived:
390 return "totalSamplesReceived";
391 case kStatsValueNameTransportId:
392 return "transportId";
393 case kStatsValueNameSelectedCandidatePairId:
394 return "selectedCandidatePairId";
395 case kStatsValueNameSsrc:
396 return "ssrc";
397 case kStatsValueNameState:
398 return "state";
399 case kStatsValueNameDataChannelId:
400 return "datachannelid";
401 case kStatsValueNameFramesDecoded:
402 return "framesDecoded";
403 case kStatsValueNameFramesEncoded:
404 return "framesEncoded";
405 case kStatsValueNameJitterBufferDelay:
406 return "jitterBufferDelay";
407 case kStatsValueNameCodecImplementationName:
408 return "codecImplementationName";
409 case kStatsValueNameMediaType:
410 return "mediaType";
411 case kStatsValueNameQpSum:
412 return "qpSum";
413 // 'goog' prefixed constants.
414 case kStatsValueNameAccelerateRate:
415 return "googAccelerateRate";
416 case kStatsValueNameActiveConnection:
417 return "googActiveConnection";
418 case kStatsValueNameActualEncBitrate:
419 return "googActualEncBitrate";
420 case kStatsValueNameAvailableReceiveBandwidth:
421 return "googAvailableReceiveBandwidth";
422 case kStatsValueNameAvailableSendBandwidth:
423 return "googAvailableSendBandwidth";
424 case kStatsValueNameAvgEncodeMs:
425 return "googAvgEncodeMs";
426 case kStatsValueNameBucketDelay:
427 return "googBucketDelay";
428 case kStatsValueNameBandwidthLimitedResolution:
429 return "googBandwidthLimitedResolution";
430 // STUN ping related attributes.
431 //
432 // TODO(zhihuang) Rename these stats to follow the standards.
433 // Connectivity checks.
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 // STUN Keepalive pings.
445 case kStatsValueNameSentStunKeepaliveRequests:
446 return "stunKeepaliveRequestsSent";
447 case kStatsValueNameRecvStunKeepaliveResponses:
448 return "stunKeepaliveResponsesReceived";
449 case kStatsValueNameStunKeepaliveRttTotal:
450 return "stunKeepaliveRttTotal";
451 case kStatsValueNameStunKeepaliveRttSquaredTotal:
452 return "stunKeepaliveRttSquaredTotal";
453
454 // Candidate related attributes. Values are taken from
455 // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
456 case kStatsValueNameCandidateIPAddress:
457 return "ipAddress";
458 case kStatsValueNameCandidateNetworkType:
459 return "networkType";
460 case kStatsValueNameCandidatePortNumber:
461 return "portNumber";
462 case kStatsValueNameCandidatePriority:
463 return "priority";
464 case kStatsValueNameCandidateTransportType:
465 return "transport";
466 case kStatsValueNameCandidateType:
467 return "candidateType";
468
469 case kStatsValueNameChannelId:
470 return "googChannelId";
471 case kStatsValueNameCodecName:
472 return "googCodecName";
473 case kStatsValueNameComponent:
474 return "googComponent";
475 case kStatsValueNameContentName:
476 return "googContentName";
477 case kStatsValueNameContentType:
478 return "googContentType";
479 case kStatsValueNameCpuLimitedResolution:
480 return "googCpuLimitedResolution";
481 case kStatsValueNameDecodingCTSG:
482 return "googDecodingCTSG";
483 case kStatsValueNameDecodingCTN:
484 return "googDecodingCTN";
485 case kStatsValueNameDecodingMutedOutput:
486 return "googDecodingMuted";
487 case kStatsValueNameDecodingNormal:
488 return "googDecodingNormal";
489 case kStatsValueNameDecodingPLC:
490 return "googDecodingPLC";
491 case kStatsValueNameDecodingCodecPLC:
492 return "googDecodingCodecPLC";
493 case kStatsValueNameDecodingCNG:
494 return "googDecodingCNG";
495 case kStatsValueNameDecodingPLCCNG:
496 return "googDecodingPLCCNG";
497 case kStatsValueNameDer:
498 return "googDerBase64";
499 case kStatsValueNameDtlsCipher:
500 return "dtlsCipher";
501 case kStatsValueNameEchoDelayMedian:
502 return "googEchoCancellationEchoDelayMedian";
503 case kStatsValueNameEchoDelayStdDev:
504 return "googEchoCancellationEchoDelayStdDev";
505 case kStatsValueNameEchoReturnLoss:
506 return "googEchoCancellationReturnLoss";
507 case kStatsValueNameEchoReturnLossEnhancement:
508 return "googEchoCancellationReturnLossEnhancement";
509 case kStatsValueNameEncodeUsagePercent:
510 return "googEncodeUsagePercent";
511 case kStatsValueNameExpandRate:
512 return "googExpandRate";
513 case kStatsValueNameFingerprint:
514 return "googFingerprint";
515 case kStatsValueNameFingerprintAlgorithm:
516 return "googFingerprintAlgorithm";
517 case kStatsValueNameFirsReceived:
518 return "googFirsReceived";
519 case kStatsValueNameFirsSent:
520 return "googFirsSent";
521 case kStatsValueNameFirstFrameReceivedToDecodedMs:
522 return "googFirstFrameReceivedToDecodedMs";
523 case kStatsValueNameFrameHeightInput:
524 return "googFrameHeightInput";
525 case kStatsValueNameFrameHeightReceived:
526 return "googFrameHeightReceived";
527 case kStatsValueNameFrameHeightSent:
528 return "googFrameHeightSent";
529 case kStatsValueNameFrameRateReceived:
530 return "googFrameRateReceived";
531 case kStatsValueNameFrameRateDecoded:
532 return "googFrameRateDecoded";
533 case kStatsValueNameFrameRateOutput:
534 return "googFrameRateOutput";
535 case kStatsValueNameDecodeMs:
536 return "googDecodeMs";
537 case kStatsValueNameMaxDecodeMs:
538 return "googMaxDecodeMs";
539 case kStatsValueNameCurrentDelayMs:
540 return "googCurrentDelayMs";
541 case kStatsValueNameTargetDelayMs:
542 return "googTargetDelayMs";
543 case kStatsValueNameJitterBufferMs:
544 return "googJitterBufferMs";
545 case kStatsValueNameMinPlayoutDelayMs:
546 return "googMinPlayoutDelayMs";
547 case kStatsValueNameRenderDelayMs:
548 return "googRenderDelayMs";
549 case kStatsValueNameCaptureStartNtpTimeMs:
550 return "googCaptureStartNtpTimeMs";
551 case kStatsValueNameFrameRateInput:
552 return "googFrameRateInput";
553 case kStatsValueNameFrameRateSent:
554 return "googFrameRateSent";
555 case kStatsValueNameFrameWidthInput:
556 return "googFrameWidthInput";
557 case kStatsValueNameFrameWidthReceived:
558 return "googFrameWidthReceived";
559 case kStatsValueNameFrameWidthSent:
560 return "googFrameWidthSent";
561 case kStatsValueNameHasEnteredLowResolution:
562 return "googHasEnteredLowResolution";
563 case kStatsValueNameHugeFramesSent:
564 return "hugeFramesSent";
565 case kStatsValueNameInitiator:
566 return "googInitiator";
567 case kStatsValueNameInterframeDelayMaxMs:
568 return "googInterframeDelayMax";
569 case kStatsValueNameIssuerId:
570 return "googIssuerId";
571 case kStatsValueNameJitterReceived:
572 return "googJitterReceived";
573 case kStatsValueNameLocalAddress:
574 return "googLocalAddress";
575 case kStatsValueNameLocalCandidateId:
576 return "localCandidateId";
577 case kStatsValueNameLocalCandidateType:
578 return "googLocalCandidateType";
579 case kStatsValueNameLocalCertificateId:
580 return "localCertificateId";
581 case kStatsValueNameAdaptationChanges:
582 return "googAdaptationChanges";
583 case kStatsValueNameNacksReceived:
584 return "googNacksReceived";
585 case kStatsValueNameNacksSent:
586 return "googNacksSent";
587 case kStatsValueNamePreemptiveExpandRate:
588 return "googPreemptiveExpandRate";
589 case kStatsValueNamePlisReceived:
590 return "googPlisReceived";
591 case kStatsValueNamePlisSent:
592 return "googPlisSent";
593 case kStatsValueNamePreferredJitterBufferMs:
594 return "googPreferredJitterBufferMs";
595 case kStatsValueNameReceiving:
596 return "googReadable";
597 case kStatsValueNameRemoteAddress:
598 return "googRemoteAddress";
599 case kStatsValueNameRemoteCandidateId:
600 return "remoteCandidateId";
601 case kStatsValueNameRemoteCandidateType:
602 return "googRemoteCandidateType";
603 case kStatsValueNameRemoteCertificateId:
604 return "remoteCertificateId";
605 case kStatsValueNameResidualEchoLikelihood:
606 return "googResidualEchoLikelihood";
607 case kStatsValueNameResidualEchoLikelihoodRecentMax:
608 return "googResidualEchoLikelihoodRecentMax";
609 case kStatsValueNameAnaBitrateActionCounter:
610 return "googAnaBitrateActionCounter";
611 case kStatsValueNameAnaChannelActionCounter:
612 return "googAnaChannelActionCounter";
613 case kStatsValueNameAnaDtxActionCounter:
614 return "googAnaDtxActionCounter";
615 case kStatsValueNameAnaFecActionCounter:
616 return "googAnaFecActionCounter";
617 case kStatsValueNameAnaFrameLengthIncreaseCounter:
618 return "googAnaFrameLengthIncreaseCounter";
619 case kStatsValueNameAnaFrameLengthDecreaseCounter:
620 return "googAnaFrameLengthDecreaseCounter";
621 case kStatsValueNameAnaUplinkPacketLossFraction:
622 return "googAnaUplinkPacketLossFraction";
623 case kStatsValueNameRetransmitBitrate:
624 return "googRetransmitBitrate";
625 case kStatsValueNameRtt:
626 return "googRtt";
627 case kStatsValueNameSecondaryDecodedRate:
628 return "googSecondaryDecodedRate";
629 case kStatsValueNameSecondaryDiscardedRate:
630 return "googSecondaryDiscardedRate";
631 case kStatsValueNameSendPacketsDiscarded:
632 return "packetsDiscardedOnSend";
633 case kStatsValueNameSpeechExpandRate:
634 return "googSpeechExpandRate";
635 case kStatsValueNameSrtpCipher:
636 return "srtpCipher";
637 case kStatsValueNameTargetEncBitrate:
638 return "googTargetEncBitrate";
639 case kStatsValueNameTotalAudioEnergy:
640 return "totalAudioEnergy";
641 case kStatsValueNameTotalSamplesDuration:
642 return "totalSamplesDuration";
643 case kStatsValueNameTransmitBitrate:
644 return "googTransmitBitrate";
645 case kStatsValueNameTransportType:
646 return "googTransportType";
647 case kStatsValueNameTrackId:
648 return "googTrackId";
649 case kStatsValueNameTimingFrameInfo:
650 return "googTimingFrameInfo";
651 case kStatsValueNameWritable:
652 return "googWritable";
653 case kStatsValueNameAudioDeviceUnderrunCounter:
654 return "googAudioDeviceUnderrunCounter";
655 case kStatsValueNameLocalCandidateRelayProtocol:
656 return "googLocalCandidateRelayProtocol";
657 }
658
659 return nullptr;
660 }
661
ToString() const662 std::string StatsReport::Value::ToString() const {
663 switch (type_) {
664 case kInt:
665 return rtc::ToString(value_.int_);
666 case kInt64:
667 return rtc::ToString(value_.int64_);
668 case kFloat:
669 return rtc::ToString(value_.float_);
670 case kStaticString:
671 return std::string(value_.static_string_);
672 case kString:
673 return *value_.string_;
674 case kBool:
675 return value_.bool_ ? "true" : "false";
676 case kId:
677 return (*value_.id_)->ToString();
678 }
679 RTC_DCHECK_NOTREACHED();
680 return std::string();
681 }
682
StatsReport(const Id & id)683 StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) {
684 RTC_DCHECK(id_.get());
685 }
686
687 StatsReport::~StatsReport() = default;
688
689 // static
NewBandwidthEstimationId()690 StatsReport::Id StatsReport::NewBandwidthEstimationId() {
691 return rtc::make_ref_counted<BandwidthEstimationId>();
692 }
693
694 // static
NewTypedId(StatsType type,const std::string & id)695 StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) {
696 return rtc::make_ref_counted<TypedId>(type, id);
697 }
698
699 // static
NewTypedIntId(StatsType type,int id)700 StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) {
701 return rtc::make_ref_counted<TypedIntId>(type, id);
702 }
703
704 // static
NewIdWithDirection(StatsType type,const std::string & id,StatsReport::Direction direction)705 StatsReport::Id StatsReport::NewIdWithDirection(
706 StatsType type,
707 const std::string& id,
708 StatsReport::Direction direction) {
709 return rtc::make_ref_counted<IdWithDirection>(type, id, direction);
710 }
711
712 // static
NewCandidateId(bool local,const std::string & id)713 StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) {
714 return rtc::make_ref_counted<CandidateId>(local, id);
715 }
716
717 // static
NewComponentId(const std::string & content_name,int component)718 StatsReport::Id StatsReport::NewComponentId(const std::string& content_name,
719 int component) {
720 return rtc::make_ref_counted<ComponentId>(content_name, component);
721 }
722
723 // static
NewCandidatePairId(const std::string & content_name,int component,int index)724 StatsReport::Id StatsReport::NewCandidatePairId(const std::string& content_name,
725 int component,
726 int index) {
727 return rtc::make_ref_counted<CandidatePairId>(content_name, component, index);
728 }
729
TypeToString() const730 const char* StatsReport::TypeToString() const {
731 return InternalTypeToString(id_->type());
732 }
733
AddString(StatsReport::StatsValueName name,const std::string & value)734 void StatsReport::AddString(StatsReport::StatsValueName name,
735 const std::string& value) {
736 const Value* found = FindValue(name);
737 if (!found || !(*found == value))
738 values_[name] = ValuePtr(new Value(name, value));
739 }
740
AddString(StatsReport::StatsValueName name,const char * value)741 void StatsReport::AddString(StatsReport::StatsValueName name,
742 const char* value) {
743 const Value* found = FindValue(name);
744 if (!found || !(*found == value))
745 values_[name] = ValuePtr(new Value(name, value));
746 }
747
AddInt64(StatsReport::StatsValueName name,int64_t value)748 void StatsReport::AddInt64(StatsReport::StatsValueName name, int64_t value) {
749 const Value* found = FindValue(name);
750 if (!found || !(*found == value))
751 values_[name] = ValuePtr(new Value(name, value, Value::kInt64));
752 }
753
AddInt(StatsReport::StatsValueName name,int value)754 void StatsReport::AddInt(StatsReport::StatsValueName name, int value) {
755 const Value* found = FindValue(name);
756 if (!found || !(*found == static_cast<int64_t>(value)))
757 values_[name] = ValuePtr(new Value(name, value, Value::kInt));
758 }
759
AddFloat(StatsReport::StatsValueName name,float value)760 void StatsReport::AddFloat(StatsReport::StatsValueName name, float value) {
761 const Value* found = FindValue(name);
762 if (!found || !(*found == value))
763 values_[name] = ValuePtr(new Value(name, value));
764 }
765
AddBoolean(StatsReport::StatsValueName name,bool value)766 void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) {
767 const Value* found = FindValue(name);
768 if (!found || !(*found == value))
769 values_[name] = ValuePtr(new Value(name, value));
770 }
771
AddId(StatsReport::StatsValueName name,const Id & value)772 void StatsReport::AddId(StatsReport::StatsValueName name, const Id& value) {
773 const Value* found = FindValue(name);
774 if (!found || !(*found == value))
775 values_[name] = ValuePtr(new Value(name, value));
776 }
777
FindValue(StatsValueName name) const778 const StatsReport::Value* StatsReport::FindValue(StatsValueName name) const {
779 Values::const_iterator it = values_.find(name);
780 return it == values_.end() ? nullptr : it->second.get();
781 }
782
StatsCollection()783 StatsCollection::StatsCollection() {}
784
~StatsCollection()785 StatsCollection::~StatsCollection() {
786 RTC_DCHECK(thread_checker_.IsCurrent());
787 for (auto* r : list_)
788 delete r;
789 }
790
begin() const791 StatsCollection::const_iterator StatsCollection::begin() const {
792 RTC_DCHECK(thread_checker_.IsCurrent());
793 return list_.begin();
794 }
795
end() const796 StatsCollection::const_iterator StatsCollection::end() const {
797 RTC_DCHECK(thread_checker_.IsCurrent());
798 return list_.end();
799 }
800
size() const801 size_t StatsCollection::size() const {
802 RTC_DCHECK(thread_checker_.IsCurrent());
803 return list_.size();
804 }
805
InsertNew(const StatsReport::Id & id)806 StatsReport* StatsCollection::InsertNew(const StatsReport::Id& id) {
807 RTC_DCHECK(thread_checker_.IsCurrent());
808 RTC_DCHECK(Find(id) == nullptr);
809 StatsReport* report = new StatsReport(id);
810 list_.push_back(report);
811 return report;
812 }
813
FindOrAddNew(const StatsReport::Id & id)814 StatsReport* StatsCollection::FindOrAddNew(const StatsReport::Id& id) {
815 RTC_DCHECK(thread_checker_.IsCurrent());
816 StatsReport* ret = Find(id);
817 return ret ? ret : InsertNew(id);
818 }
819
ReplaceOrAddNew(const StatsReport::Id & id)820 StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) {
821 RTC_DCHECK(thread_checker_.IsCurrent());
822 RTC_DCHECK(id.get());
823 Container::iterator it = absl::c_find_if(
824 list_,
825 [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); });
826 if (it != end()) {
827 StatsReport* report = new StatsReport((*it)->id());
828 delete *it;
829 *it = report;
830 return report;
831 }
832 return InsertNew(id);
833 }
834
835 // Looks for a report with the given `id`. If one is not found, null
836 // will be returned.
Find(const StatsReport::Id & id)837 StatsReport* StatsCollection::Find(const StatsReport::Id& id) {
838 RTC_DCHECK(thread_checker_.IsCurrent());
839 Container::iterator it = absl::c_find_if(
840 list_,
841 [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); });
842 return it == list_.end() ? nullptr : *it;
843 }
844
845 } // namespace webrtc
846