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 40using rtc::RefCountedObject; 41 42namespace webrtc { 43namespace { 44 45// The id of StatsReport of type kStatsReportTypeBwe. 46const char kStatsReportVideoBweId[] = "bweforvideo"; 47 48// NOTE: These names need to be consistent with an external 49// specification (W3C Stats Identifiers). 50const 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 81class BandwidthEstimationId : public StatsReport::IdBase { 82 public: 83 BandwidthEstimationId() 84 : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {} 85 std::string ToString() const override { return kStatsReportVideoBweId; } 86}; 87 88class TypedId : public StatsReport::IdBase { 89 public: 90 TypedId(StatsReport::StatsType type, const std::string& id) 91 : StatsReport::IdBase(type), id_(id) {} 92 93 bool Equals(const IdBase& other) const override { 94 return IdBase::Equals(other) && 95 static_cast<const TypedId&>(other).id_ == id_; 96 } 97 98 std::string ToString() const override { 99 return std::string(InternalTypeToString(type_)) + kSeparator + id_; 100 } 101 102 protected: 103 const std::string id_; 104}; 105 106class TypedIntId : public StatsReport::IdBase { 107 public: 108 TypedIntId(StatsReport::StatsType type, int id) 109 : StatsReport::IdBase(type), id_(id) {} 110 111 bool Equals(const IdBase& other) const override { 112 return IdBase::Equals(other) && 113 static_cast<const TypedIntId&>(other).id_ == id_; 114 } 115 116 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 126class IdWithDirection : public TypedId { 127 public: 128 IdWithDirection(StatsReport::StatsType type, const std::string& id, 129 StatsReport::Direction direction) 130 : TypedId(type, id), direction_(direction) {} 131 132 bool Equals(const IdBase& other) const override { 133 return TypedId::Equals(other) && 134 static_cast<const IdWithDirection&>(other).direction_ == direction_; 135 } 136 137 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 148class CandidateId : public TypedId { 149 public: 150 CandidateId(bool local, const std::string& id) 151 : TypedId(local ? 152 StatsReport::kStatsReportTypeIceLocalCandidate : 153 StatsReport::kStatsReportTypeIceRemoteCandidate, 154 id) { 155 } 156 157 std::string ToString() const override { 158 return "Cand-" + id_; 159 } 160}; 161 162class ComponentId : public StatsReport::IdBase { 163 public: 164 ComponentId(const std::string& content_name, int component) 165 : ComponentId(StatsReport::kStatsReportTypeComponent, content_name, 166 component) {} 167 168 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 174 std::string ToString() const override { 175 return ToString("Channel-"); 176 } 177 178 protected: 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 185 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 198class CandidatePairId : public ComponentId { 199 public: 200 CandidatePairId(const std::string& content_name, int component, int index) 201 : ComponentId(StatsReport::kStatsReportTypeCandidatePair, content_name, 202 component), 203 index_(index) {} 204 205 bool Equals(const IdBase& other) const override { 206 return ComponentId::Equals(other) && 207 static_cast<const CandidatePairId&>(other).index_ == index_; 208 } 209 210 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 223StatsReport::IdBase::IdBase(StatsType type) : type_(type) {} 224StatsReport::IdBase::~IdBase() {} 225 226StatsReport::StatsType StatsReport::IdBase::type() const { return type_; } 227 228bool StatsReport::IdBase::Equals(const IdBase& other) const { 229 return other.type_ == type_; 230} 231 232StatsReport::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 238StatsReport::Value::Value(StatsValueName name, float f) 239 : name(name), type_(kFloat) { 240 value_.float_ = f; 241} 242 243StatsReport::Value::Value(StatsValueName name, const std::string& value) 244 : name(name), type_(kString) { 245 value_.string_ = new std::string(value); 246} 247 248StatsReport::Value::Value(StatsValueName name, const char* value) 249 : name(name), type_(kStaticString) { 250 value_.static_string_ = value; 251} 252 253StatsReport::Value::Value(StatsValueName name, bool b) 254 : name(name), type_(kBool) { 255 value_.bool_ = b; 256} 257 258StatsReport::Value::Value(StatsValueName name, const Id& value) 259 : name(name), type_(kId) { 260 value_.id_ = new Id(value); 261} 262 263StatsReport::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 280bool 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 316bool 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 321bool 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 334bool 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 339bool StatsReport::Value::operator==(bool value) const { 340 return type_ == kBool && value_.bool_ == value; 341} 342 343bool StatsReport::Value::operator==(float value) const { 344 return type_ == kFloat && value_.float_ == value; 345} 346 347bool StatsReport::Value::operator==(const Id& value) const { 348 return type_ == kId && (*value_.id_)->Equals(value); 349} 350 351int StatsReport::Value::int_val() const { 352 RTC_DCHECK(type_ == kInt); 353 return value_.int_; 354} 355 356int64_t StatsReport::Value::int64_val() const { 357 RTC_DCHECK(type_ == kInt64); 358 return value_.int64_; 359} 360 361float StatsReport::Value::float_val() const { 362 RTC_DCHECK(type_ == kFloat); 363 return value_.float_; 364} 365 366const char* StatsReport::Value::static_string_val() const { 367 RTC_DCHECK(type_ == kStaticString); 368 return value_.static_string_; 369} 370 371const std::string& StatsReport::Value::string_val() const { 372 RTC_DCHECK(type_ == kString); 373 return *value_.string_; 374} 375 376bool StatsReport::Value::bool_val() const { 377 RTC_DCHECK(type_ == kBool); 378 return value_.bool_; 379} 380 381const 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 602std::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 623StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) { 624 RTC_DCHECK(id_.get()); 625} 626 627// static 628StatsReport::Id StatsReport::NewBandwidthEstimationId() { 629 return Id(new RefCountedObject<BandwidthEstimationId>()); 630} 631 632// static 633StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) { 634 return Id(new RefCountedObject<TypedId>(type, id)); 635} 636 637// static 638StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) { 639 return Id(new RefCountedObject<TypedIntId>(type, id)); 640} 641 642// static 643StatsReport::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 649StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) { 650 return Id(new RefCountedObject<CandidateId>(local, id)); 651} 652 653// static 654StatsReport::Id StatsReport::NewComponentId( 655 const std::string& content_name, int component) { 656 return Id(new RefCountedObject<ComponentId>(content_name, component)); 657} 658 659// static 660StatsReport::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 666const char* StatsReport::TypeToString() const { 667 return InternalTypeToString(id_->type()); 668} 669 670void 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 677void 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 684void 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 690void 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 696void 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 702void 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 708void 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 715const 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 720StatsCollection::StatsCollection() { 721} 722 723StatsCollection::~StatsCollection() { 724 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 725 for (auto* r : list_) 726 delete r; 727} 728 729StatsCollection::const_iterator StatsCollection::begin() const { 730 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 731 return list_.begin(); 732} 733 734StatsCollection::const_iterator StatsCollection::end() const { 735 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 736 return list_.end(); 737} 738 739size_t StatsCollection::size() const { 740 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 741 return list_.size(); 742} 743 744StatsReport* 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 752StatsReport* 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 758StatsReport* 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. 774StatsReport* 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