/* * Copyright 2016 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 "api/stats/rtc_stats.h" #include #include "rtc_base/arraysize.h" #include "rtc_base/string_encode.h" #include "rtc_base/strings/string_builder.h" namespace webrtc { namespace { // Produces "[a,b,c]". Works for non-vector |RTCStatsMemberInterface::Type| // types. template std::string VectorToString(const std::vector& vector) { rtc::StringBuilder sb; sb << "["; const char* separator = ""; for (const T& element : vector) { sb << separator << rtc::ToString(element); separator = ","; } sb << "]"; return sb.Release(); } // This overload is required because std::vector range loops don't // return references but objects, causing -Wrange-loop-analysis diagnostics. std::string VectorToString(const std::vector& vector) { rtc::StringBuilder sb; sb << "["; const char* separator = ""; for (bool element : vector) { sb << separator << rtc::ToString(element); separator = ","; } sb << "]"; return sb.Release(); } // Produces "[\"a\",\"b\",\"c\"]". Works for vectors of both const char* and // std::string element types. template std::string VectorOfStringsToString(const std::vector& strings) { rtc::StringBuilder sb; sb << "["; const char* separator = ""; for (const T& element : strings) { sb << separator << "\"" << rtc::ToString(element) << "\""; separator = ","; } sb << "]"; return sb.Release(); } template std::string ToStringAsDouble(const T value) { // JSON represents numbers as floating point numbers with about 15 decimal // digits of precision. char buf[32]; const int len = std::snprintf(&buf[0], arraysize(buf), "%.16g", static_cast(value)); RTC_DCHECK_LE(len, arraysize(buf)); return std::string(&buf[0], len); } template std::string VectorToStringAsDouble(const std::vector& vector) { rtc::StringBuilder sb; sb << "["; const char* separator = ""; for (const T& element : vector) { sb << separator << ToStringAsDouble(element); separator = ","; } sb << "]"; return sb.Release(); } } // namespace bool RTCStats::operator==(const RTCStats& other) const { if (type() != other.type() || id() != other.id()) return false; std::vector members = Members(); std::vector other_members = other.Members(); RTC_DCHECK_EQ(members.size(), other_members.size()); for (size_t i = 0; i < members.size(); ++i) { const RTCStatsMemberInterface* member = members[i]; const RTCStatsMemberInterface* other_member = other_members[i]; RTC_DCHECK_EQ(member->type(), other_member->type()); RTC_DCHECK_EQ(member->name(), other_member->name()); if (*member != *other_member) return false; } return true; } bool RTCStats::operator!=(const RTCStats& other) const { return !(*this == other); } std::string RTCStats::ToJson() const { rtc::StringBuilder sb; sb << "{\"type\":\"" << type() << "\"," "\"id\":\"" << id_ << "\"," "\"timestamp\":" << timestamp_us_; for (const RTCStatsMemberInterface* member : Members()) { if (member->is_defined()) { sb << ",\"" << member->name() << "\":"; if (member->is_string()) sb << "\"" << member->ValueToJson() << "\""; else sb << member->ValueToJson(); } } sb << "}"; return sb.Release(); } std::vector RTCStats::Members() const { return MembersOfThisObjectAndAncestors(0); } std::vector RTCStats::MembersOfThisObjectAndAncestors(size_t additional_capacity) const { std::vector members; members.reserve(additional_capacity); return members; } #define WEBRTC_DEFINE_RTCSTATSMEMBER(T, type, is_seq, is_str, to_str, to_json) \ template <> \ RTCStatsMemberInterface::Type RTCStatsMember::StaticType() { \ return type; \ } \ template <> \ bool RTCStatsMember::is_sequence() const { \ return is_seq; \ } \ template <> \ bool RTCStatsMember::is_string() const { \ return is_str; \ } \ template <> \ std::string RTCStatsMember::ValueToString() const { \ RTC_DCHECK(is_defined_); \ return to_str; \ } \ template <> \ std::string RTCStatsMember::ValueToJson() const { \ RTC_DCHECK(is_defined_); \ return to_json; \ } \ template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCStatsMember WEBRTC_DEFINE_RTCSTATSMEMBER(bool, kBool, false, false, rtc::ToString(value_), rtc::ToString(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(int32_t, kInt32, false, false, rtc::ToString(value_), rtc::ToString(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(uint32_t, kUint32, false, false, rtc::ToString(value_), rtc::ToString(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(int64_t, kInt64, false, false, rtc::ToString(value_), ToStringAsDouble(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(uint64_t, kUint64, false, false, rtc::ToString(value_), ToStringAsDouble(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(double, kDouble, false, false, rtc::ToString(value_), ToStringAsDouble(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(std::string, kString, false, true, value_, value_); WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceBool, true, false, VectorToString(value_), VectorToString(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceInt32, true, false, VectorToString(value_), VectorToString(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceUint32, true, false, VectorToString(value_), VectorToString(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceInt64, true, false, VectorToString(value_), VectorToStringAsDouble(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceUint64, true, false, VectorToString(value_), VectorToStringAsDouble(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceDouble, true, false, VectorToString(value_), VectorToStringAsDouble(value_)); WEBRTC_DEFINE_RTCSTATSMEMBER(std::vector, kSequenceString, true, false, VectorOfStringsToString(value_), VectorOfStringsToString(value_)); template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember>; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember>; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember>; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember>; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember>; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember>; template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) RTCNonStandardStatsMember>; } // namespace webrtc