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