aboutsummaryrefslogtreecommitdiff
path: root/talk/app/webrtc/statstypes.cc
diff options
context:
space:
mode:
Diffstat (limited to 'talk/app/webrtc/statstypes.cc')
-rw-r--r--talk/app/webrtc/statstypes.cc782
1 files changed, 782 insertions, 0 deletions
diff --git a/talk/app/webrtc/statstypes.cc b/talk/app/webrtc/statstypes.cc
new file mode 100644
index 0000000000..e45833c668
--- /dev/null
+++ b/talk/app/webrtc/statstypes.cc
@@ -0,0 +1,782 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/app/webrtc/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 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";
+
+ // '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";
+
+ // 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";
+ default:
+ RTC_DCHECK(false);
+ break;
+ }
+
+ 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