1 /*
2 * libjingle
3 * Copyright 2014 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/app/webrtc/statstypes.h"
29
30 #include <string.h>
31
32 #include "webrtc/base/checks.h"
33
34 // TODO(tommi): Could we have a static map of value name -> expected type
35 // and use this to RTC_DCHECK on correct usage (somewhat strongly typed values)?
36 // Alternatively, we could define the names+type in a separate document and
37 // generate strongly typed inline C++ code that forces the correct type to be
38 // used for a given name at compile time.
39
40 using rtc::RefCountedObject;
41
42 namespace webrtc {
43 namespace {
44
45 // The id of StatsReport of type kStatsReportTypeBwe.
46 const char kStatsReportVideoBweId[] = "bweforvideo";
47
48 // NOTE: These names need to be consistent with an external
49 // specification (W3C Stats Identifiers).
InternalTypeToString(StatsReport::StatsType type)50 const char* InternalTypeToString(StatsReport::StatsType type) {
51 switch (type) {
52 case StatsReport::kStatsReportTypeSession:
53 return "googLibjingleSession";
54 case StatsReport::kStatsReportTypeBwe:
55 return "VideoBwe";
56 case StatsReport::kStatsReportTypeRemoteSsrc:
57 return "remoteSsrc";
58 case StatsReport::kStatsReportTypeSsrc:
59 return "ssrc";
60 case StatsReport::kStatsReportTypeTrack:
61 return "googTrack";
62 case StatsReport::kStatsReportTypeIceLocalCandidate:
63 return "localcandidate";
64 case StatsReport::kStatsReportTypeIceRemoteCandidate:
65 return "remotecandidate";
66 case StatsReport::kStatsReportTypeTransport:
67 return "transport";
68 case StatsReport::kStatsReportTypeComponent:
69 return "googComponent";
70 case StatsReport::kStatsReportTypeCandidatePair:
71 return "googCandidatePair";
72 case StatsReport::kStatsReportTypeCertificate:
73 return "googCertificate";
74 case StatsReport::kStatsReportTypeDataChannel:
75 return "datachannel";
76 }
77 RTC_DCHECK(false);
78 return nullptr;
79 }
80
81 class BandwidthEstimationId : public StatsReport::IdBase {
82 public:
BandwidthEstimationId()83 BandwidthEstimationId()
84 : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {}
ToString() const85 std::string ToString() const override { return kStatsReportVideoBweId; }
86 };
87
88 class TypedId : public StatsReport::IdBase {
89 public:
TypedId(StatsReport::StatsType type,const std::string & id)90 TypedId(StatsReport::StatsType type, const std::string& id)
91 : StatsReport::IdBase(type), id_(id) {}
92
Equals(const IdBase & other) const93 bool Equals(const IdBase& other) const override {
94 return IdBase::Equals(other) &&
95 static_cast<const TypedId&>(other).id_ == id_;
96 }
97
ToString() const98 std::string ToString() const override {
99 return std::string(InternalTypeToString(type_)) + kSeparator + id_;
100 }
101
102 protected:
103 const std::string id_;
104 };
105
106 class TypedIntId : public StatsReport::IdBase {
107 public:
TypedIntId(StatsReport::StatsType type,int id)108 TypedIntId(StatsReport::StatsType type, int id)
109 : StatsReport::IdBase(type), id_(id) {}
110
Equals(const IdBase & other) const111 bool Equals(const IdBase& other) const override {
112 return IdBase::Equals(other) &&
113 static_cast<const TypedIntId&>(other).id_ == id_;
114 }
115
ToString() const116 std::string ToString() const override {
117 return std::string(InternalTypeToString(type_)) +
118 kSeparator +
119 rtc::ToString<int>(id_);
120 }
121
122 protected:
123 const int id_;
124 };
125
126 class IdWithDirection : public TypedId {
127 public:
IdWithDirection(StatsReport::StatsType type,const std::string & id,StatsReport::Direction direction)128 IdWithDirection(StatsReport::StatsType type, const std::string& id,
129 StatsReport::Direction direction)
130 : TypedId(type, id), direction_(direction) {}
131
Equals(const IdBase & other) const132 bool Equals(const IdBase& other) const override {
133 return TypedId::Equals(other) &&
134 static_cast<const IdWithDirection&>(other).direction_ == direction_;
135 }
136
ToString() const137 std::string ToString() const override {
138 std::string ret(TypedId::ToString());
139 ret += kSeparator;
140 ret += direction_ == StatsReport::kSend ? "send" : "recv";
141 return ret;
142 }
143
144 private:
145 const StatsReport::Direction direction_;
146 };
147
148 class CandidateId : public TypedId {
149 public:
CandidateId(bool local,const std::string & id)150 CandidateId(bool local, const std::string& id)
151 : TypedId(local ?
152 StatsReport::kStatsReportTypeIceLocalCandidate :
153 StatsReport::kStatsReportTypeIceRemoteCandidate,
154 id) {
155 }
156
ToString() const157 std::string ToString() const override {
158 return "Cand-" + id_;
159 }
160 };
161
162 class ComponentId : public StatsReport::IdBase {
163 public:
ComponentId(const std::string & content_name,int component)164 ComponentId(const std::string& content_name, int component)
165 : ComponentId(StatsReport::kStatsReportTypeComponent, content_name,
166 component) {}
167
Equals(const IdBase & other) const168 bool Equals(const IdBase& other) const override {
169 return IdBase::Equals(other) &&
170 static_cast<const ComponentId&>(other).component_ == component_ &&
171 static_cast<const ComponentId&>(other).content_name_ == content_name_;
172 }
173
ToString() const174 std::string ToString() const override {
175 return ToString("Channel-");
176 }
177
178 protected:
ComponentId(StatsReport::StatsType type,const std::string & content_name,int component)179 ComponentId(StatsReport::StatsType type, const std::string& content_name,
180 int component)
181 : IdBase(type),
182 content_name_(content_name),
183 component_(component) {}
184
ToString(const char * prefix) const185 std::string ToString(const char* prefix) const {
186 std::string ret(prefix);
187 ret += content_name_;
188 ret += '-';
189 ret += rtc::ToString<>(component_);
190 return ret;
191 }
192
193 private:
194 const std::string content_name_;
195 const int component_;
196 };
197
198 class CandidatePairId : public ComponentId {
199 public:
CandidatePairId(const std::string & content_name,int component,int index)200 CandidatePairId(const std::string& content_name, int component, int index)
201 : ComponentId(StatsReport::kStatsReportTypeCandidatePair, content_name,
202 component),
203 index_(index) {}
204
Equals(const IdBase & other) const205 bool Equals(const IdBase& other) const override {
206 return ComponentId::Equals(other) &&
207 static_cast<const CandidatePairId&>(other).index_ == index_;
208 }
209
ToString() const210 std::string ToString() const override {
211 std::string ret(ComponentId::ToString("Conn-"));
212 ret += '-';
213 ret += rtc::ToString<>(index_);
214 return ret;
215 }
216
217 private:
218 const int index_;
219 };
220
221 } // namespace
222
IdBase(StatsType type)223 StatsReport::IdBase::IdBase(StatsType type) : type_(type) {}
~IdBase()224 StatsReport::IdBase::~IdBase() {}
225
type() const226 StatsReport::StatsType StatsReport::IdBase::type() const { return type_; }
227
Equals(const IdBase & other) const228 bool StatsReport::IdBase::Equals(const IdBase& other) const {
229 return other.type_ == type_;
230 }
231
Value(StatsValueName name,int64_t value,Type int_type)232 StatsReport::Value::Value(StatsValueName name, int64_t value, Type int_type)
233 : name(name), type_(int_type) {
234 RTC_DCHECK(type_ == kInt || type_ == kInt64);
235 type_ == kInt ? value_.int_ = static_cast<int>(value) : value_.int64_ = value;
236 }
237
Value(StatsValueName name,float f)238 StatsReport::Value::Value(StatsValueName name, float f)
239 : name(name), type_(kFloat) {
240 value_.float_ = f;
241 }
242
Value(StatsValueName name,const std::string & value)243 StatsReport::Value::Value(StatsValueName name, const std::string& value)
244 : name(name), type_(kString) {
245 value_.string_ = new std::string(value);
246 }
247
Value(StatsValueName name,const char * value)248 StatsReport::Value::Value(StatsValueName name, const char* value)
249 : name(name), type_(kStaticString) {
250 value_.static_string_ = value;
251 }
252
Value(StatsValueName name,bool b)253 StatsReport::Value::Value(StatsValueName name, bool b)
254 : name(name), type_(kBool) {
255 value_.bool_ = b;
256 }
257
Value(StatsValueName name,const Id & value)258 StatsReport::Value::Value(StatsValueName name, const Id& value)
259 : name(name), type_(kId) {
260 value_.id_ = new Id(value);
261 }
262
~Value()263 StatsReport::Value::~Value() {
264 switch (type_) {
265 case kInt:
266 case kInt64:
267 case kFloat:
268 case kBool:
269 case kStaticString:
270 break;
271 case kString:
272 delete value_.string_;
273 break;
274 case kId:
275 delete value_.id_;
276 break;
277 }
278 }
279
Equals(const Value & other) const280 bool StatsReport::Value::Equals(const Value& other) const {
281 if (name != other.name)
282 return false;
283
284 // There's a 1:1 relation between a name and a type, so we don't have to
285 // check that.
286 RTC_DCHECK_EQ(type_, other.type_);
287
288 switch (type_) {
289 case kInt:
290 return value_.int_ == other.value_.int_;
291 case kInt64:
292 return value_.int64_ == other.value_.int64_;
293 case kFloat:
294 return value_.float_ == other.value_.float_;
295 case kStaticString: {
296 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
297 if (value_.static_string_ != other.value_.static_string_) {
298 RTC_DCHECK(strcmp(value_.static_string_, other.value_.static_string_) !=
299 0)
300 << "Duplicate global?";
301 }
302 #endif
303 return value_.static_string_ == other.value_.static_string_;
304 }
305 case kString:
306 return *value_.string_ == *other.value_.string_;
307 case kBool:
308 return value_.bool_ == other.value_.bool_;
309 case kId:
310 return (*value_.id_)->Equals(*other.value_.id_);
311 }
312 RTC_NOTREACHED();
313 return false;
314 }
315
operator ==(const std::string & value) const316 bool StatsReport::Value::operator==(const std::string& value) const {
317 return (type_ == kString && value_.string_->compare(value) == 0) ||
318 (type_ == kStaticString && value.compare(value_.static_string_) == 0);
319 }
320
operator ==(const char * value) const321 bool StatsReport::Value::operator==(const char* value) const {
322 if (type_ == kString)
323 return value_.string_->compare(value) == 0;
324 if (type_ != kStaticString)
325 return false;
326 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
327 if (value_.static_string_ != value)
328 RTC_DCHECK(strcmp(value_.static_string_, value) != 0)
329 << "Duplicate global?";
330 #endif
331 return value == value_.static_string_;
332 }
333
operator ==(int64_t value) const334 bool StatsReport::Value::operator==(int64_t value) const {
335 return type_ == kInt ? value_.int_ == static_cast<int>(value) :
336 (type_ == kInt64 ? value_.int64_ == value : false);
337 }
338
operator ==(bool value) const339 bool StatsReport::Value::operator==(bool value) const {
340 return type_ == kBool && value_.bool_ == value;
341 }
342
operator ==(float value) const343 bool StatsReport::Value::operator==(float value) const {
344 return type_ == kFloat && value_.float_ == value;
345 }
346
operator ==(const Id & value) const347 bool StatsReport::Value::operator==(const Id& value) const {
348 return type_ == kId && (*value_.id_)->Equals(value);
349 }
350
int_val() const351 int StatsReport::Value::int_val() const {
352 RTC_DCHECK(type_ == kInt);
353 return value_.int_;
354 }
355
int64_val() const356 int64_t StatsReport::Value::int64_val() const {
357 RTC_DCHECK(type_ == kInt64);
358 return value_.int64_;
359 }
360
float_val() const361 float StatsReport::Value::float_val() const {
362 RTC_DCHECK(type_ == kFloat);
363 return value_.float_;
364 }
365
static_string_val() const366 const char* StatsReport::Value::static_string_val() const {
367 RTC_DCHECK(type_ == kStaticString);
368 return value_.static_string_;
369 }
370
string_val() const371 const std::string& StatsReport::Value::string_val() const {
372 RTC_DCHECK(type_ == kString);
373 return *value_.string_;
374 }
375
bool_val() const376 bool StatsReport::Value::bool_val() const {
377 RTC_DCHECK(type_ == kBool);
378 return value_.bool_;
379 }
380
display_name() const381 const char* StatsReport::Value::display_name() const {
382 switch (name) {
383 case kStatsValueNameAudioOutputLevel:
384 return "audioOutputLevel";
385 case kStatsValueNameAudioInputLevel:
386 return "audioInputLevel";
387 case kStatsValueNameBytesSent:
388 return "bytesSent";
389 case kStatsValueNamePacketsSent:
390 return "packetsSent";
391 case kStatsValueNameBytesReceived:
392 return "bytesReceived";
393 case kStatsValueNameLabel:
394 return "label";
395 case kStatsValueNamePacketsReceived:
396 return "packetsReceived";
397 case kStatsValueNamePacketsLost:
398 return "packetsLost";
399 case kStatsValueNameProtocol:
400 return "protocol";
401 case kStatsValueNameTransportId:
402 return "transportId";
403 case kStatsValueNameSelectedCandidatePairId:
404 return "selectedCandidatePairId";
405 case kStatsValueNameSsrc:
406 return "ssrc";
407 case kStatsValueNameState:
408 return "state";
409 case kStatsValueNameDataChannelId:
410 return "datachannelid";
411 case kStatsValueNameCodecImplementationName:
412 return "codecImplementationName";
413
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
432 // Candidate related attributes. Values are taken from
433 // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
434 case kStatsValueNameCandidateIPAddress:
435 return "ipAddress";
436 case kStatsValueNameCandidateNetworkType:
437 return "networkType";
438 case kStatsValueNameCandidatePortNumber:
439 return "portNumber";
440 case kStatsValueNameCandidatePriority:
441 return "priority";
442 case kStatsValueNameCandidateTransportType:
443 return "transport";
444 case kStatsValueNameCandidateType:
445 return "candidateType";
446
447 case kStatsValueNameChannelId:
448 return "googChannelId";
449 case kStatsValueNameCodecName:
450 return "googCodecName";
451 case kStatsValueNameComponent:
452 return "googComponent";
453 case kStatsValueNameContentName:
454 return "googContentName";
455 case kStatsValueNameCpuLimitedResolution:
456 return "googCpuLimitedResolution";
457 case kStatsValueNameDecodingCTSG:
458 return "googDecodingCTSG";
459 case kStatsValueNameDecodingCTN:
460 return "googDecodingCTN";
461 case kStatsValueNameDecodingNormal:
462 return "googDecodingNormal";
463 case kStatsValueNameDecodingPLC:
464 return "googDecodingPLC";
465 case kStatsValueNameDecodingCNG:
466 return "googDecodingCNG";
467 case kStatsValueNameDecodingPLCCNG:
468 return "googDecodingPLCCNG";
469 case kStatsValueNameDer:
470 return "googDerBase64";
471 case kStatsValueNameDtlsCipher:
472 return "dtlsCipher";
473 case kStatsValueNameEchoCancellationQualityMin:
474 return "googEchoCancellationQualityMin";
475 case kStatsValueNameEchoDelayMedian:
476 return "googEchoCancellationEchoDelayMedian";
477 case kStatsValueNameEchoDelayStdDev:
478 return "googEchoCancellationEchoDelayStdDev";
479 case kStatsValueNameEchoReturnLoss:
480 return "googEchoCancellationReturnLoss";
481 case kStatsValueNameEchoReturnLossEnhancement:
482 return "googEchoCancellationReturnLossEnhancement";
483 case kStatsValueNameEncodeUsagePercent:
484 return "googEncodeUsagePercent";
485 case kStatsValueNameExpandRate:
486 return "googExpandRate";
487 case kStatsValueNameFingerprint:
488 return "googFingerprint";
489 case kStatsValueNameFingerprintAlgorithm:
490 return "googFingerprintAlgorithm";
491 case kStatsValueNameFirsReceived:
492 return "googFirsReceived";
493 case kStatsValueNameFirsSent:
494 return "googFirsSent";
495 case kStatsValueNameFrameHeightInput:
496 return "googFrameHeightInput";
497 case kStatsValueNameFrameHeightReceived:
498 return "googFrameHeightReceived";
499 case kStatsValueNameFrameHeightSent:
500 return "googFrameHeightSent";
501 case kStatsValueNameFrameRateReceived:
502 return "googFrameRateReceived";
503 case kStatsValueNameFrameRateDecoded:
504 return "googFrameRateDecoded";
505 case kStatsValueNameFrameRateOutput:
506 return "googFrameRateOutput";
507 case kStatsValueNameDecodeMs:
508 return "googDecodeMs";
509 case kStatsValueNameMaxDecodeMs:
510 return "googMaxDecodeMs";
511 case kStatsValueNameCurrentDelayMs:
512 return "googCurrentDelayMs";
513 case kStatsValueNameTargetDelayMs:
514 return "googTargetDelayMs";
515 case kStatsValueNameJitterBufferMs:
516 return "googJitterBufferMs";
517 case kStatsValueNameMinPlayoutDelayMs:
518 return "googMinPlayoutDelayMs";
519 case kStatsValueNameRenderDelayMs:
520 return "googRenderDelayMs";
521 case kStatsValueNameCaptureStartNtpTimeMs:
522 return "googCaptureStartNtpTimeMs";
523 case kStatsValueNameFrameRateInput:
524 return "googFrameRateInput";
525 case kStatsValueNameFrameRateSent:
526 return "googFrameRateSent";
527 case kStatsValueNameFrameWidthInput:
528 return "googFrameWidthInput";
529 case kStatsValueNameFrameWidthReceived:
530 return "googFrameWidthReceived";
531 case kStatsValueNameFrameWidthSent:
532 return "googFrameWidthSent";
533 case kStatsValueNameInitiator:
534 return "googInitiator";
535 case kStatsValueNameIssuerId:
536 return "googIssuerId";
537 case kStatsValueNameJitterReceived:
538 return "googJitterReceived";
539 case kStatsValueNameLocalAddress:
540 return "googLocalAddress";
541 case kStatsValueNameLocalCandidateId:
542 return "localCandidateId";
543 case kStatsValueNameLocalCandidateType:
544 return "googLocalCandidateType";
545 case kStatsValueNameLocalCertificateId:
546 return "localCertificateId";
547 case kStatsValueNameAdaptationChanges:
548 return "googAdaptationChanges";
549 case kStatsValueNameNacksReceived:
550 return "googNacksReceived";
551 case kStatsValueNameNacksSent:
552 return "googNacksSent";
553 case kStatsValueNamePreemptiveExpandRate:
554 return "googPreemptiveExpandRate";
555 case kStatsValueNamePlisReceived:
556 return "googPlisReceived";
557 case kStatsValueNamePlisSent:
558 return "googPlisSent";
559 case kStatsValueNamePreferredJitterBufferMs:
560 return "googPreferredJitterBufferMs";
561 case kStatsValueNameReceiving:
562 return "googReadable";
563 case kStatsValueNameRemoteAddress:
564 return "googRemoteAddress";
565 case kStatsValueNameRemoteCandidateId:
566 return "remoteCandidateId";
567 case kStatsValueNameRemoteCandidateType:
568 return "googRemoteCandidateType";
569 case kStatsValueNameRemoteCertificateId:
570 return "remoteCertificateId";
571 case kStatsValueNameRetransmitBitrate:
572 return "googRetransmitBitrate";
573 case kStatsValueNameRtt:
574 return "googRtt";
575 case kStatsValueNameSecondaryDecodedRate:
576 return "googSecondaryDecodedRate";
577 case kStatsValueNameSendPacketsDiscarded:
578 return "packetsDiscardedOnSend";
579 case kStatsValueNameSpeechExpandRate:
580 return "googSpeechExpandRate";
581 case kStatsValueNameSrtpCipher:
582 return "srtpCipher";
583 case kStatsValueNameTargetEncBitrate:
584 return "googTargetEncBitrate";
585 case kStatsValueNameTransmitBitrate:
586 return "googTransmitBitrate";
587 case kStatsValueNameTransportType:
588 return "googTransportType";
589 case kStatsValueNameTrackId:
590 return "googTrackId";
591 case kStatsValueNameTypingNoiseState:
592 return "googTypingNoiseState";
593 case kStatsValueNameViewLimitedResolution:
594 return "googViewLimitedResolution";
595 case kStatsValueNameWritable:
596 return "googWritable";
597 }
598
599 return nullptr;
600 }
601
ToString() const602 std::string StatsReport::Value::ToString() const {
603 switch (type_) {
604 case kInt:
605 return rtc::ToString(value_.int_);
606 case kInt64:
607 return rtc::ToString(value_.int64_);
608 case kFloat:
609 return rtc::ToString(value_.float_);
610 case kStaticString:
611 return std::string(value_.static_string_);
612 case kString:
613 return *value_.string_;
614 case kBool:
615 return value_.bool_ ? "true" : "false";
616 case kId:
617 return (*value_.id_)->ToString();
618 }
619 RTC_NOTREACHED();
620 return std::string();
621 }
622
StatsReport(const Id & id)623 StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) {
624 RTC_DCHECK(id_.get());
625 }
626
627 // static
NewBandwidthEstimationId()628 StatsReport::Id StatsReport::NewBandwidthEstimationId() {
629 return Id(new RefCountedObject<BandwidthEstimationId>());
630 }
631
632 // static
NewTypedId(StatsType type,const std::string & id)633 StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) {
634 return Id(new RefCountedObject<TypedId>(type, id));
635 }
636
637 // static
NewTypedIntId(StatsType type,int id)638 StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) {
639 return Id(new RefCountedObject<TypedIntId>(type, id));
640 }
641
642 // static
NewIdWithDirection(StatsType type,const std::string & id,StatsReport::Direction direction)643 StatsReport::Id StatsReport::NewIdWithDirection(
644 StatsType type, const std::string& id, StatsReport::Direction direction) {
645 return Id(new RefCountedObject<IdWithDirection>(type, id, direction));
646 }
647
648 // static
NewCandidateId(bool local,const std::string & id)649 StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) {
650 return Id(new RefCountedObject<CandidateId>(local, id));
651 }
652
653 // static
NewComponentId(const std::string & content_name,int component)654 StatsReport::Id StatsReport::NewComponentId(
655 const std::string& content_name, int component) {
656 return Id(new RefCountedObject<ComponentId>(content_name, component));
657 }
658
659 // static
NewCandidatePairId(const std::string & content_name,int component,int index)660 StatsReport::Id StatsReport::NewCandidatePairId(
661 const std::string& content_name, int component, int index) {
662 return Id(new RefCountedObject<CandidatePairId>(
663 content_name, component, index));
664 }
665
TypeToString() const666 const char* StatsReport::TypeToString() const {
667 return InternalTypeToString(id_->type());
668 }
669
AddString(StatsReport::StatsValueName name,const std::string & value)670 void StatsReport::AddString(StatsReport::StatsValueName name,
671 const std::string& value) {
672 const Value* found = FindValue(name);
673 if (!found || !(*found == value))
674 values_[name] = ValuePtr(new Value(name, value));
675 }
676
AddString(StatsReport::StatsValueName name,const char * value)677 void StatsReport::AddString(StatsReport::StatsValueName name,
678 const char* value) {
679 const Value* found = FindValue(name);
680 if (!found || !(*found == value))
681 values_[name] = ValuePtr(new Value(name, value));
682 }
683
AddInt64(StatsReport::StatsValueName name,int64_t value)684 void StatsReport::AddInt64(StatsReport::StatsValueName name, int64_t value) {
685 const Value* found = FindValue(name);
686 if (!found || !(*found == value))
687 values_[name] = ValuePtr(new Value(name, value, Value::kInt64));
688 }
689
AddInt(StatsReport::StatsValueName name,int value)690 void StatsReport::AddInt(StatsReport::StatsValueName name, int value) {
691 const Value* found = FindValue(name);
692 if (!found || !(*found == static_cast<int64_t>(value)))
693 values_[name] = ValuePtr(new Value(name, value, Value::kInt));
694 }
695
AddFloat(StatsReport::StatsValueName name,float value)696 void StatsReport::AddFloat(StatsReport::StatsValueName name, float value) {
697 const Value* found = FindValue(name);
698 if (!found || !(*found == value))
699 values_[name] = ValuePtr(new Value(name, value));
700 }
701
AddBoolean(StatsReport::StatsValueName name,bool value)702 void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) {
703 const Value* found = FindValue(name);
704 if (!found || !(*found == value))
705 values_[name] = ValuePtr(new Value(name, value));
706 }
707
AddId(StatsReport::StatsValueName name,const Id & value)708 void StatsReport::AddId(StatsReport::StatsValueName name,
709 const Id& value) {
710 const Value* found = FindValue(name);
711 if (!found || !(*found == value))
712 values_[name] = ValuePtr(new Value(name, value));
713 }
714
FindValue(StatsValueName name) const715 const StatsReport::Value* StatsReport::FindValue(StatsValueName name) const {
716 Values::const_iterator it = values_.find(name);
717 return it == values_.end() ? nullptr : it->second.get();
718 }
719
StatsCollection()720 StatsCollection::StatsCollection() {
721 }
722
~StatsCollection()723 StatsCollection::~StatsCollection() {
724 RTC_DCHECK(thread_checker_.CalledOnValidThread());
725 for (auto* r : list_)
726 delete r;
727 }
728
begin() const729 StatsCollection::const_iterator StatsCollection::begin() const {
730 RTC_DCHECK(thread_checker_.CalledOnValidThread());
731 return list_.begin();
732 }
733
end() const734 StatsCollection::const_iterator StatsCollection::end() const {
735 RTC_DCHECK(thread_checker_.CalledOnValidThread());
736 return list_.end();
737 }
738
size() const739 size_t StatsCollection::size() const {
740 RTC_DCHECK(thread_checker_.CalledOnValidThread());
741 return list_.size();
742 }
743
InsertNew(const StatsReport::Id & id)744 StatsReport* StatsCollection::InsertNew(const StatsReport::Id& id) {
745 RTC_DCHECK(thread_checker_.CalledOnValidThread());
746 RTC_DCHECK(Find(id) == nullptr);
747 StatsReport* report = new StatsReport(id);
748 list_.push_back(report);
749 return report;
750 }
751
FindOrAddNew(const StatsReport::Id & id)752 StatsReport* StatsCollection::FindOrAddNew(const StatsReport::Id& id) {
753 RTC_DCHECK(thread_checker_.CalledOnValidThread());
754 StatsReport* ret = Find(id);
755 return ret ? ret : InsertNew(id);
756 }
757
ReplaceOrAddNew(const StatsReport::Id & id)758 StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) {
759 RTC_DCHECK(thread_checker_.CalledOnValidThread());
760 RTC_DCHECK(id.get());
761 Container::iterator it = std::find_if(list_.begin(), list_.end(),
762 [&id](const StatsReport* r)->bool { return r->id()->Equals(id); });
763 if (it != end()) {
764 StatsReport* report = new StatsReport((*it)->id());
765 delete *it;
766 *it = report;
767 return report;
768 }
769 return InsertNew(id);
770 }
771
772 // Looks for a report with the given |id|. If one is not found, NULL
773 // will be returned.
Find(const StatsReport::Id & id)774 StatsReport* StatsCollection::Find(const StatsReport::Id& id) {
775 RTC_DCHECK(thread_checker_.CalledOnValidThread());
776 Container::iterator it = std::find_if(list_.begin(), list_.end(),
777 [&id](const StatsReport* r)->bool { return r->id()->Equals(id); });
778 return it == list_.end() ? nullptr : *it;
779 }
780
781 } // namespace webrtc
782