| /* |
| * Copyright 2014 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/api/statstypes.h" |
| |
| #include <string.h> |
| |
| #include "webrtc/base/checks.h" |
| |
| // TODO(tommi): Could we have a static map of value name -> expected type |
| // and use this to RTC_DCHECK on correct usage (somewhat strongly typed values)? |
| // Alternatively, we could define the names+type in a separate document and |
| // generate strongly typed inline C++ code that forces the correct type to be |
| // used for a given name at compile time. |
| |
| using rtc::RefCountedObject; |
| |
| namespace webrtc { |
| namespace { |
| |
| // The id of StatsReport of type kStatsReportTypeBwe. |
| const char kStatsReportVideoBweId[] = "bweforvideo"; |
| |
| // NOTE: These names need to be consistent with an external |
| // specification (W3C Stats Identifiers). |
| const char* InternalTypeToString(StatsReport::StatsType type) { |
| switch (type) { |
| case StatsReport::kStatsReportTypeSession: |
| return "googLibjingleSession"; |
| case StatsReport::kStatsReportTypeBwe: |
| return "VideoBwe"; |
| case StatsReport::kStatsReportTypeRemoteSsrc: |
| return "remoteSsrc"; |
| case StatsReport::kStatsReportTypeSsrc: |
| return "ssrc"; |
| case StatsReport::kStatsReportTypeTrack: |
| return "googTrack"; |
| case StatsReport::kStatsReportTypeIceLocalCandidate: |
| return "localcandidate"; |
| case StatsReport::kStatsReportTypeIceRemoteCandidate: |
| return "remotecandidate"; |
| case StatsReport::kStatsReportTypeTransport: |
| return "transport"; |
| case StatsReport::kStatsReportTypeComponent: |
| return "googComponent"; |
| case StatsReport::kStatsReportTypeCandidatePair: |
| return "googCandidatePair"; |
| case StatsReport::kStatsReportTypeCertificate: |
| return "googCertificate"; |
| case StatsReport::kStatsReportTypeDataChannel: |
| return "datachannel"; |
| } |
| RTC_DCHECK(false); |
| return nullptr; |
| } |
| |
| class BandwidthEstimationId : public StatsReport::IdBase { |
| public: |
| BandwidthEstimationId() |
| : StatsReport::IdBase(StatsReport::kStatsReportTypeBwe) {} |
| std::string ToString() const override { return kStatsReportVideoBweId; } |
| }; |
| |
| class TypedId : public StatsReport::IdBase { |
| public: |
| TypedId(StatsReport::StatsType type, const std::string& id) |
| : StatsReport::IdBase(type), id_(id) {} |
| |
| bool Equals(const IdBase& other) const override { |
| return IdBase::Equals(other) && |
| static_cast<const TypedId&>(other).id_ == id_; |
| } |
| |
| std::string ToString() const override { |
| return std::string(InternalTypeToString(type_)) + kSeparator + id_; |
| } |
| |
| protected: |
| const std::string id_; |
| }; |
| |
| class TypedIntId : public StatsReport::IdBase { |
| public: |
| TypedIntId(StatsReport::StatsType type, int id) |
| : StatsReport::IdBase(type), id_(id) {} |
| |
| bool Equals(const IdBase& other) const override { |
| return IdBase::Equals(other) && |
| static_cast<const TypedIntId&>(other).id_ == id_; |
| } |
| |
| std::string ToString() const override { |
| return std::string(InternalTypeToString(type_)) + |
| kSeparator + |
| rtc::ToString<int>(id_); |
| } |
| |
| protected: |
| const int id_; |
| }; |
| |
| class IdWithDirection : public TypedId { |
| public: |
| IdWithDirection(StatsReport::StatsType type, const std::string& id, |
| StatsReport::Direction direction) |
| : TypedId(type, id), direction_(direction) {} |
| |
| bool Equals(const IdBase& other) const override { |
| return TypedId::Equals(other) && |
| static_cast<const IdWithDirection&>(other).direction_ == direction_; |
| } |
| |
| std::string ToString() const override { |
| std::string ret(TypedId::ToString()); |
| ret += kSeparator; |
| ret += direction_ == StatsReport::kSend ? "send" : "recv"; |
| return ret; |
| } |
| |
| private: |
| const StatsReport::Direction direction_; |
| }; |
| |
| class CandidateId : public TypedId { |
| public: |
| CandidateId(bool local, const std::string& id) |
| : TypedId(local ? |
| StatsReport::kStatsReportTypeIceLocalCandidate : |
| StatsReport::kStatsReportTypeIceRemoteCandidate, |
| id) { |
| } |
| |
| std::string ToString() const override { |
| return "Cand-" + id_; |
| } |
| }; |
| |
| class ComponentId : public StatsReport::IdBase { |
| public: |
| ComponentId(const std::string& content_name, int component) |
| : ComponentId(StatsReport::kStatsReportTypeComponent, content_name, |
| component) {} |
| |
| bool Equals(const IdBase& other) const override { |
| return IdBase::Equals(other) && |
| static_cast<const ComponentId&>(other).component_ == component_ && |
| static_cast<const ComponentId&>(other).content_name_ == content_name_; |
| } |
| |
| std::string ToString() const override { |
| return ToString("Channel-"); |
| } |
| |
| protected: |
| ComponentId(StatsReport::StatsType type, const std::string& content_name, |
| int component) |
| : IdBase(type), |
| content_name_(content_name), |
| component_(component) {} |
| |
| std::string ToString(const char* prefix) const { |
| std::string ret(prefix); |
| ret += content_name_; |
| ret += '-'; |
| ret += rtc::ToString<>(component_); |
| return ret; |
| } |
| |
| private: |
| const std::string content_name_; |
| const int component_; |
| }; |
| |
| class CandidatePairId : public ComponentId { |
| public: |
| CandidatePairId(const std::string& content_name, int component, int index) |
| : ComponentId(StatsReport::kStatsReportTypeCandidatePair, content_name, |
| component), |
| index_(index) {} |
| |
| bool Equals(const IdBase& other) const override { |
| return ComponentId::Equals(other) && |
| static_cast<const CandidatePairId&>(other).index_ == index_; |
| } |
| |
| std::string ToString() const override { |
| std::string ret(ComponentId::ToString("Conn-")); |
| ret += '-'; |
| ret += rtc::ToString<>(index_); |
| return ret; |
| } |
| |
| private: |
| const int index_; |
| }; |
| |
| } // namespace |
| |
| StatsReport::IdBase::IdBase(StatsType type) : type_(type) {} |
| StatsReport::IdBase::~IdBase() {} |
| |
| StatsReport::StatsType StatsReport::IdBase::type() const { return type_; } |
| |
| bool StatsReport::IdBase::Equals(const IdBase& other) const { |
| return other.type_ == type_; |
| } |
| |
| StatsReport::Value::Value(StatsValueName name, int64_t value, Type int_type) |
| : name(name), type_(int_type) { |
| RTC_DCHECK(type_ == kInt || type_ == kInt64); |
| type_ == kInt ? value_.int_ = static_cast<int>(value) : value_.int64_ = value; |
| } |
| |
| StatsReport::Value::Value(StatsValueName name, float f) |
| : name(name), type_(kFloat) { |
| value_.float_ = f; |
| } |
| |
| StatsReport::Value::Value(StatsValueName name, const std::string& value) |
| : name(name), type_(kString) { |
| value_.string_ = new std::string(value); |
| } |
| |
| StatsReport::Value::Value(StatsValueName name, const char* value) |
| : name(name), type_(kStaticString) { |
| value_.static_string_ = value; |
| } |
| |
| StatsReport::Value::Value(StatsValueName name, bool b) |
| : name(name), type_(kBool) { |
| value_.bool_ = b; |
| } |
| |
| StatsReport::Value::Value(StatsValueName name, const Id& value) |
| : name(name), type_(kId) { |
| value_.id_ = new Id(value); |
| } |
| |
| StatsReport::Value::~Value() { |
| switch (type_) { |
| case kInt: |
| case kInt64: |
| case kFloat: |
| case kBool: |
| case kStaticString: |
| break; |
| case kString: |
| delete value_.string_; |
| break; |
| case kId: |
| delete value_.id_; |
| break; |
| } |
| } |
| |
| bool StatsReport::Value::Equals(const Value& other) const { |
| if (name != other.name) |
| return false; |
| |
| // There's a 1:1 relation between a name and a type, so we don't have to |
| // check that. |
| RTC_DCHECK_EQ(type_, other.type_); |
| |
| switch (type_) { |
| case kInt: |
| return value_.int_ == other.value_.int_; |
| case kInt64: |
| return value_.int64_ == other.value_.int64_; |
| case kFloat: |
| return value_.float_ == other.value_.float_; |
| case kStaticString: { |
| #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) |
| if (value_.static_string_ != other.value_.static_string_) { |
| RTC_DCHECK(strcmp(value_.static_string_, other.value_.static_string_) != |
| 0) |
| << "Duplicate global?"; |
| } |
| #endif |
| return value_.static_string_ == other.value_.static_string_; |
| } |
| case kString: |
| return *value_.string_ == *other.value_.string_; |
| case kBool: |
| return value_.bool_ == other.value_.bool_; |
| case kId: |
| return (*value_.id_)->Equals(*other.value_.id_); |
| } |
| RTC_NOTREACHED(); |
| return false; |
| } |
| |
| bool StatsReport::Value::operator==(const std::string& value) const { |
| return (type_ == kString && value_.string_->compare(value) == 0) || |
| (type_ == kStaticString && value.compare(value_.static_string_) == 0); |
| } |
| |
| bool StatsReport::Value::operator==(const char* value) const { |
| if (type_ == kString) |
| return value_.string_->compare(value) == 0; |
| if (type_ != kStaticString) |
| return false; |
| #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) |
| if (value_.static_string_ != value) |
| RTC_DCHECK(strcmp(value_.static_string_, value) != 0) |
| << "Duplicate global?"; |
| #endif |
| return value == value_.static_string_; |
| } |
| |
| bool StatsReport::Value::operator==(int64_t value) const { |
| return type_ == kInt ? value_.int_ == static_cast<int>(value) : |
| (type_ == kInt64 ? value_.int64_ == value : false); |
| } |
| |
| bool StatsReport::Value::operator==(bool value) const { |
| return type_ == kBool && value_.bool_ == value; |
| } |
| |
| bool StatsReport::Value::operator==(float value) const { |
| return type_ == kFloat && value_.float_ == value; |
| } |
| |
| bool StatsReport::Value::operator==(const Id& value) const { |
| return type_ == kId && (*value_.id_)->Equals(value); |
| } |
| |
| int StatsReport::Value::int_val() const { |
| RTC_DCHECK(type_ == kInt); |
| return value_.int_; |
| } |
| |
| int64_t StatsReport::Value::int64_val() const { |
| RTC_DCHECK(type_ == kInt64); |
| return value_.int64_; |
| } |
| |
| float StatsReport::Value::float_val() const { |
| RTC_DCHECK(type_ == kFloat); |
| return value_.float_; |
| } |
| |
| const char* StatsReport::Value::static_string_val() const { |
| RTC_DCHECK(type_ == kStaticString); |
| return value_.static_string_; |
| } |
| |
| const std::string& StatsReport::Value::string_val() const { |
| RTC_DCHECK(type_ == kString); |
| return *value_.string_; |
| } |
| |
| bool StatsReport::Value::bool_val() const { |
| RTC_DCHECK(type_ == kBool); |
| return value_.bool_; |
| } |
| |
| const char* StatsReport::Value::display_name() const { |
| switch (name) { |
| case kStatsValueNameAecDivergentFilterFraction: |
| return "aecDivergentFilterFraction"; |
| case kStatsValueNameAudioOutputLevel: |
| return "audioOutputLevel"; |
| case kStatsValueNameAudioInputLevel: |
| return "audioInputLevel"; |
| case kStatsValueNameBytesSent: |
| return "bytesSent"; |
| case kStatsValueNamePacketsSent: |
| return "packetsSent"; |
| case kStatsValueNameBytesReceived: |
| return "bytesReceived"; |
| case kStatsValueNameLabel: |
| return "label"; |
| case kStatsValueNamePacketsReceived: |
| return "packetsReceived"; |
| case kStatsValueNamePacketsLost: |
| return "packetsLost"; |
| case kStatsValueNameProtocol: |
| return "protocol"; |
| case kStatsValueNameTransportId: |
| return "transportId"; |
| case kStatsValueNameSelectedCandidatePairId: |
| return "selectedCandidatePairId"; |
| case kStatsValueNameSsrc: |
| return "ssrc"; |
| case kStatsValueNameState: |
| return "state"; |
| case kStatsValueNameDataChannelId: |
| return "datachannelid"; |
| case kStatsValueNameCodecImplementationName: |
| return "codecImplementationName"; |
| case kStatsValueNameMediaType: |
| return "mediaType"; |
| // 'goog' prefixed constants. |
| case kStatsValueNameAccelerateRate: |
| return "googAccelerateRate"; |
| case kStatsValueNameActiveConnection: |
| return "googActiveConnection"; |
| case kStatsValueNameActualEncBitrate: |
| return "googActualEncBitrate"; |
| case kStatsValueNameAvailableReceiveBandwidth: |
| return "googAvailableReceiveBandwidth"; |
| case kStatsValueNameAvailableSendBandwidth: |
| return "googAvailableSendBandwidth"; |
| case kStatsValueNameAvgEncodeMs: |
| return "googAvgEncodeMs"; |
| case kStatsValueNameBucketDelay: |
| return "googBucketDelay"; |
| case kStatsValueNameBandwidthLimitedResolution: |
| return "googBandwidthLimitedResolution"; |
| // STUN ping related attributes. |
| // TODO(zhihuang) Rename these stats to follow the standards. |
| case kStatsValueNameSentPingRequestsTotal: |
| return "requestsSent"; |
| case kStatsValueNameSentPingRequestsBeforeFirstResponse: |
| return "consentRequestsSent"; |
| case kStatsValueNameSentPingResponses: |
| return "responsesSent"; |
| case kStatsValueNameRecvPingRequests: |
| return "requestsReceived"; |
| case kStatsValueNameRecvPingResponses: |
| return "responsesReceived"; |
| |
| // Candidate related attributes. Values are taken from |
| // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*. |
| case kStatsValueNameCandidateIPAddress: |
| return "ipAddress"; |
| case kStatsValueNameCandidateNetworkType: |
| return "networkType"; |
| case kStatsValueNameCandidatePortNumber: |
| return "portNumber"; |
| case kStatsValueNameCandidatePriority: |
| return "priority"; |
| case kStatsValueNameCandidateTransportType: |
| return "transport"; |
| case kStatsValueNameCandidateType: |
| return "candidateType"; |
| |
| case kStatsValueNameChannelId: |
| return "googChannelId"; |
| case kStatsValueNameCodecName: |
| return "googCodecName"; |
| case kStatsValueNameComponent: |
| return "googComponent"; |
| case kStatsValueNameContentName: |
| return "googContentName"; |
| case kStatsValueNameCpuLimitedResolution: |
| return "googCpuLimitedResolution"; |
| case kStatsValueNameDecodingCTSG: |
| return "googDecodingCTSG"; |
| case kStatsValueNameDecodingCTN: |
| return "googDecodingCTN"; |
| case kStatsValueNameDecodingNormal: |
| return "googDecodingNormal"; |
| case kStatsValueNameDecodingPLC: |
| return "googDecodingPLC"; |
| case kStatsValueNameDecodingCNG: |
| return "googDecodingCNG"; |
| case kStatsValueNameDecodingPLCCNG: |
| return "googDecodingPLCCNG"; |
| case kStatsValueNameDer: |
| return "googDerBase64"; |
| case kStatsValueNameDtlsCipher: |
| return "dtlsCipher"; |
| case kStatsValueNameEchoCancellationQualityMin: |
| return "googEchoCancellationQualityMin"; |
| case kStatsValueNameEchoDelayMedian: |
| return "googEchoCancellationEchoDelayMedian"; |
| case kStatsValueNameEchoDelayStdDev: |
| return "googEchoCancellationEchoDelayStdDev"; |
| case kStatsValueNameEchoReturnLoss: |
| return "googEchoCancellationReturnLoss"; |
| case kStatsValueNameEchoReturnLossEnhancement: |
| return "googEchoCancellationReturnLossEnhancement"; |
| case kStatsValueNameEncodeUsagePercent: |
| return "googEncodeUsagePercent"; |
| case kStatsValueNameExpandRate: |
| return "googExpandRate"; |
| case kStatsValueNameFingerprint: |
| return "googFingerprint"; |
| case kStatsValueNameFingerprintAlgorithm: |
| return "googFingerprintAlgorithm"; |
| case kStatsValueNameFirsReceived: |
| return "googFirsReceived"; |
| case kStatsValueNameFirsSent: |
| return "googFirsSent"; |
| case kStatsValueNameFrameHeightInput: |
| return "googFrameHeightInput"; |
| case kStatsValueNameFrameHeightReceived: |
| return "googFrameHeightReceived"; |
| case kStatsValueNameFrameHeightSent: |
| return "googFrameHeightSent"; |
| case kStatsValueNameFrameRateReceived: |
| return "googFrameRateReceived"; |
| case kStatsValueNameFrameRateDecoded: |
| return "googFrameRateDecoded"; |
| case kStatsValueNameFrameRateOutput: |
| return "googFrameRateOutput"; |
| case kStatsValueNameDecodeMs: |
| return "googDecodeMs"; |
| case kStatsValueNameMaxDecodeMs: |
| return "googMaxDecodeMs"; |
| case kStatsValueNameCurrentDelayMs: |
| return "googCurrentDelayMs"; |
| case kStatsValueNameTargetDelayMs: |
| return "googTargetDelayMs"; |
| case kStatsValueNameJitterBufferMs: |
| return "googJitterBufferMs"; |
| case kStatsValueNameMinPlayoutDelayMs: |
| return "googMinPlayoutDelayMs"; |
| case kStatsValueNameRenderDelayMs: |
| return "googRenderDelayMs"; |
| case kStatsValueNameCaptureStartNtpTimeMs: |
| return "googCaptureStartNtpTimeMs"; |
| case kStatsValueNameFrameRateInput: |
| return "googFrameRateInput"; |
| case kStatsValueNameFrameRateSent: |
| return "googFrameRateSent"; |
| case kStatsValueNameFrameWidthInput: |
| return "googFrameWidthInput"; |
| case kStatsValueNameFrameWidthReceived: |
| return "googFrameWidthReceived"; |
| case kStatsValueNameFrameWidthSent: |
| return "googFrameWidthSent"; |
| case kStatsValueNameInitiator: |
| return "googInitiator"; |
| case kStatsValueNameIssuerId: |
| return "googIssuerId"; |
| case kStatsValueNameJitterReceived: |
| return "googJitterReceived"; |
| case kStatsValueNameLocalAddress: |
| return "googLocalAddress"; |
| case kStatsValueNameLocalCandidateId: |
| return "localCandidateId"; |
| case kStatsValueNameLocalCandidateType: |
| return "googLocalCandidateType"; |
| case kStatsValueNameLocalCertificateId: |
| return "localCertificateId"; |
| case kStatsValueNameAdaptationChanges: |
| return "googAdaptationChanges"; |
| case kStatsValueNameNacksReceived: |
| return "googNacksReceived"; |
| case kStatsValueNameNacksSent: |
| return "googNacksSent"; |
| case kStatsValueNamePreemptiveExpandRate: |
| return "googPreemptiveExpandRate"; |
| case kStatsValueNamePlisReceived: |
| return "googPlisReceived"; |
| case kStatsValueNamePlisSent: |
| return "googPlisSent"; |
| case kStatsValueNamePreferredJitterBufferMs: |
| return "googPreferredJitterBufferMs"; |
| case kStatsValueNameReceiving: |
| return "googReadable"; |
| case kStatsValueNameRemoteAddress: |
| return "googRemoteAddress"; |
| case kStatsValueNameRemoteCandidateId: |
| return "remoteCandidateId"; |
| case kStatsValueNameRemoteCandidateType: |
| return "googRemoteCandidateType"; |
| case kStatsValueNameRemoteCertificateId: |
| return "remoteCertificateId"; |
| case kStatsValueNameRetransmitBitrate: |
| return "googRetransmitBitrate"; |
| case kStatsValueNameRtt: |
| return "googRtt"; |
| case kStatsValueNameSecondaryDecodedRate: |
| return "googSecondaryDecodedRate"; |
| case kStatsValueNameSendPacketsDiscarded: |
| return "packetsDiscardedOnSend"; |
| case kStatsValueNameSpeechExpandRate: |
| return "googSpeechExpandRate"; |
| case kStatsValueNameSrtpCipher: |
| return "srtpCipher"; |
| case kStatsValueNameTargetEncBitrate: |
| return "googTargetEncBitrate"; |
| case kStatsValueNameTransmitBitrate: |
| return "googTransmitBitrate"; |
| case kStatsValueNameTransportType: |
| return "googTransportType"; |
| case kStatsValueNameTrackId: |
| return "googTrackId"; |
| case kStatsValueNameTypingNoiseState: |
| return "googTypingNoiseState"; |
| case kStatsValueNameViewLimitedResolution: |
| return "googViewLimitedResolution"; |
| case kStatsValueNameWritable: |
| return "googWritable"; |
| } |
| |
| return nullptr; |
| } |
| |
| std::string StatsReport::Value::ToString() const { |
| switch (type_) { |
| case kInt: |
| return rtc::ToString(value_.int_); |
| case kInt64: |
| return rtc::ToString(value_.int64_); |
| case kFloat: |
| return rtc::ToString(value_.float_); |
| case kStaticString: |
| return std::string(value_.static_string_); |
| case kString: |
| return *value_.string_; |
| case kBool: |
| return value_.bool_ ? "true" : "false"; |
| case kId: |
| return (*value_.id_)->ToString(); |
| } |
| RTC_NOTREACHED(); |
| return std::string(); |
| } |
| |
| StatsReport::StatsReport(const Id& id) : id_(id), timestamp_(0.0) { |
| RTC_DCHECK(id_.get()); |
| } |
| |
| // static |
| StatsReport::Id StatsReport::NewBandwidthEstimationId() { |
| return Id(new RefCountedObject<BandwidthEstimationId>()); |
| } |
| |
| // static |
| StatsReport::Id StatsReport::NewTypedId(StatsType type, const std::string& id) { |
| return Id(new RefCountedObject<TypedId>(type, id)); |
| } |
| |
| // static |
| StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) { |
| return Id(new RefCountedObject<TypedIntId>(type, id)); |
| } |
| |
| // static |
| StatsReport::Id StatsReport::NewIdWithDirection( |
| StatsType type, const std::string& id, StatsReport::Direction direction) { |
| return Id(new RefCountedObject<IdWithDirection>(type, id, direction)); |
| } |
| |
| // static |
| StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) { |
| return Id(new RefCountedObject<CandidateId>(local, id)); |
| } |
| |
| // static |
| StatsReport::Id StatsReport::NewComponentId( |
| const std::string& content_name, int component) { |
| return Id(new RefCountedObject<ComponentId>(content_name, component)); |
| } |
| |
| // static |
| StatsReport::Id StatsReport::NewCandidatePairId( |
| const std::string& content_name, int component, int index) { |
| return Id(new RefCountedObject<CandidatePairId>( |
| content_name, component, index)); |
| } |
| |
| const char* StatsReport::TypeToString() const { |
| return InternalTypeToString(id_->type()); |
| } |
| |
| void StatsReport::AddString(StatsReport::StatsValueName name, |
| const std::string& value) { |
| const Value* found = FindValue(name); |
| if (!found || !(*found == value)) |
| values_[name] = ValuePtr(new Value(name, value)); |
| } |
| |
| void StatsReport::AddString(StatsReport::StatsValueName name, |
| const char* value) { |
| const Value* found = FindValue(name); |
| if (!found || !(*found == value)) |
| values_[name] = ValuePtr(new Value(name, value)); |
| } |
| |
| void StatsReport::AddInt64(StatsReport::StatsValueName name, int64_t value) { |
| const Value* found = FindValue(name); |
| if (!found || !(*found == value)) |
| values_[name] = ValuePtr(new Value(name, value, Value::kInt64)); |
| } |
| |
| void StatsReport::AddInt(StatsReport::StatsValueName name, int value) { |
| const Value* found = FindValue(name); |
| if (!found || !(*found == static_cast<int64_t>(value))) |
| values_[name] = ValuePtr(new Value(name, value, Value::kInt)); |
| } |
| |
| void StatsReport::AddFloat(StatsReport::StatsValueName name, float value) { |
| const Value* found = FindValue(name); |
| if (!found || !(*found == value)) |
| values_[name] = ValuePtr(new Value(name, value)); |
| } |
| |
| void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) { |
| const Value* found = FindValue(name); |
| if (!found || !(*found == value)) |
| values_[name] = ValuePtr(new Value(name, value)); |
| } |
| |
| void StatsReport::AddId(StatsReport::StatsValueName name, |
| const Id& value) { |
| const Value* found = FindValue(name); |
| if (!found || !(*found == value)) |
| values_[name] = ValuePtr(new Value(name, value)); |
| } |
| |
| const StatsReport::Value* StatsReport::FindValue(StatsValueName name) const { |
| Values::const_iterator it = values_.find(name); |
| return it == values_.end() ? nullptr : it->second.get(); |
| } |
| |
| StatsCollection::StatsCollection() { |
| } |
| |
| StatsCollection::~StatsCollection() { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| for (auto* r : list_) |
| delete r; |
| } |
| |
| StatsCollection::const_iterator StatsCollection::begin() const { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| return list_.begin(); |
| } |
| |
| StatsCollection::const_iterator StatsCollection::end() const { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| return list_.end(); |
| } |
| |
| size_t StatsCollection::size() const { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| return list_.size(); |
| } |
| |
| StatsReport* StatsCollection::InsertNew(const StatsReport::Id& id) { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| RTC_DCHECK(Find(id) == nullptr); |
| StatsReport* report = new StatsReport(id); |
| list_.push_back(report); |
| return report; |
| } |
| |
| StatsReport* StatsCollection::FindOrAddNew(const StatsReport::Id& id) { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| StatsReport* ret = Find(id); |
| return ret ? ret : InsertNew(id); |
| } |
| |
| StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| RTC_DCHECK(id.get()); |
| Container::iterator it = std::find_if(list_.begin(), list_.end(), |
| [&id](const StatsReport* r)->bool { return r->id()->Equals(id); }); |
| if (it != end()) { |
| StatsReport* report = new StatsReport((*it)->id()); |
| delete *it; |
| *it = report; |
| return report; |
| } |
| return InsertNew(id); |
| } |
| |
| // Looks for a report with the given |id|. If one is not found, NULL |
| // will be returned. |
| StatsReport* StatsCollection::Find(const StatsReport::Id& id) { |
| RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| Container::iterator it = std::find_if(list_.begin(), list_.end(), |
| [&id](const StatsReport* r)->bool { return r->id()->Equals(id); }); |
| return it == list_.end() ? nullptr : *it; |
| } |
| |
| } // namespace webrtc |