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). 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: 83 BandwidthEstimationId() 84 : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {} 85 std::string ToString() const override { return kStatsReportVideoBweId; } 86 }; 87 88 class 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 106 class 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 126 class 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 148 class 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 162 class 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 198 class 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 223 StatsReport::IdBase::IdBase(StatsType type) : type_(type) {} 224 StatsReport::IdBase::~IdBase() {} 225 226 StatsReport::StatsType StatsReport::IdBase::type() const { return type_; } 227 228 bool StatsReport::IdBase::Equals(const IdBase& other) const { 229 return other.type_ == type_; 230 } 231 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 238 StatsReport::Value::Value(StatsValueName name, float f) 239 : name(name), type_(kFloat) { 240 value_.float_ = f; 241 } 242 243 StatsReport::Value::Value(StatsValueName name, const std::string& value) 244 : name(name), type_(kString) { 245 value_.string_ = new std::string(value); 246 } 247 248 StatsReport::Value::Value(StatsValueName name, const char* value) 249 : name(name), type_(kStaticString) { 250 value_.static_string_ = value; 251 } 252 253 StatsReport::Value::Value(StatsValueName name, bool b) 254 : name(name), type_(kBool) { 255 value_.bool_ = b; 256 } 257 258 StatsReport::Value::Value(StatsValueName name, const Id& value) 259 : name(name), type_(kId) { 260 value_.id_ = new Id(value); 261 } 262 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 280 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 316 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 321 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 334 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 339 bool StatsReport::Value::operator==(bool value) const { 340 return type_ == kBool && value_.bool_ == value; 341 } 342 343 bool StatsReport::Value::operator==(float value) const { 344 return type_ == kFloat && value_.float_ == value; 345 } 346 347 bool StatsReport::Value::operator==(const Id& value) const { 348 return type_ == kId && (*value_.id_)->Equals(value); 349 } 350 351 int StatsReport::Value::int_val() const { 352 RTC_DCHECK(type_ == kInt); 353 return value_.int_; 354 } 355 356 int64_t StatsReport::Value::int64_val() const { 357 RTC_DCHECK(type_ == kInt64); 358 return value_.int64_; 359 } 360 361 float StatsReport::Value::float_val() const { 362 RTC_DCHECK(type_ == kFloat); 363 return value_.float_; 364 } 365 366 const char* StatsReport::Value::static_string_val() const { 367 RTC_DCHECK(type_ == kStaticString); 368 return value_.static_string_; 369 } 370 371 const std::string& StatsReport::Value::string_val() const { 372 RTC_DCHECK(type_ == kString); 373 return *value_.string_; 374 } 375 376 bool StatsReport::Value::bool_val() const { 377 RTC_DCHECK(type_ == kBool); 378 return value_.bool_; 379 } 380 381 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 602 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 623 StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) { 624 RTC_DCHECK(id_.get()); 625 } 626 627 // static 628 StatsReport::Id StatsReport::NewBandwidthEstimationId() { 629 return Id(new RefCountedObject<BandwidthEstimationId>()); 630 } 631 632 // static 633 StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) { 634 return Id(new RefCountedObject<TypedId>(type, id)); 635 } 636 637 // static 638 StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) { 639 return Id(new RefCountedObject<TypedIntId>(type, id)); 640 } 641 642 // static 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 649 StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) { 650 return Id(new RefCountedObject<CandidateId>(local, id)); 651 } 652 653 // static 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 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 666 const char* StatsReport::TypeToString() const { 667 return InternalTypeToString(id_->type()); 668 } 669 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 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 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 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 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 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 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 715 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 720 StatsCollection::StatsCollection() { 721 } 722 723 StatsCollection::~StatsCollection() { 724 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 725 for (auto* r : list_) 726 delete r; 727 } 728 729 StatsCollection::const_iterator StatsCollection::begin() const { 730 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 731 return list_.begin(); 732 } 733 734 StatsCollection::const_iterator StatsCollection::end() const { 735 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 736 return list_.end(); 737 } 738 739 size_t StatsCollection::size() const { 740 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 741 return list_.size(); 742 } 743 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 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 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. 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