1 /* 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef API_STATS_RTC_STATS_H_ 12 #define API_STATS_RTC_STATS_H_ 13 14 #include <stddef.h> 15 #include <stdint.h> 16 17 #include <memory> 18 #include <string> 19 #include <utility> 20 #include <vector> 21 22 #include "rtc_base/checks.h" 23 #include "rtc_base/system/rtc_export.h" 24 #include "rtc_base/system/rtc_export_template.h" 25 26 namespace webrtc { 27 28 class RTCStatsMemberInterface; 29 30 // Abstract base class for RTCStats-derived dictionaries, see 31 // https://w3c.github.io/webrtc-stats/. 32 // 33 // All derived classes must have the following static variable defined: 34 // static const char kType[]; 35 // It is used as a unique class identifier and a string representation of the 36 // class type, see https://w3c.github.io/webrtc-stats/#rtcstatstype-str*. 37 // Use the |WEBRTC_RTCSTATS_IMPL| macro when implementing subclasses, see macro 38 // for details. 39 // 40 // Derived classes list their dictionary members, RTCStatsMember<T>, as public 41 // fields, allowing the following: 42 // 43 // RTCFooStats foo("fooId", GetCurrentTime()); 44 // foo.bar = 42; 45 // foo.baz = std::vector<std::string>(); 46 // foo.baz->push_back("hello world"); 47 // uint32_t x = *foo.bar; 48 // 49 // Pointers to all the members are available with |Members|, allowing iteration: 50 // 51 // for (const RTCStatsMemberInterface* member : foo.Members()) { 52 // printf("%s = %s\n", member->name(), member->ValueToString().c_str()); 53 // } 54 class RTC_EXPORT RTCStats { 55 public: RTCStats(const std::string & id,int64_t timestamp_us)56 RTCStats(const std::string& id, int64_t timestamp_us) 57 : id_(id), timestamp_us_(timestamp_us) {} RTCStats(std::string && id,int64_t timestamp_us)58 RTCStats(std::string&& id, int64_t timestamp_us) 59 : id_(std::move(id)), timestamp_us_(timestamp_us) {} ~RTCStats()60 virtual ~RTCStats() {} 61 62 virtual std::unique_ptr<RTCStats> copy() const = 0; 63 id()64 const std::string& id() const { return id_; } 65 // Time relative to the UNIX epoch (Jan 1, 1970, UTC), in microseconds. timestamp_us()66 int64_t timestamp_us() const { return timestamp_us_; } 67 // Returns the static member variable |kType| of the implementing class. 68 virtual const char* type() const = 0; 69 // Returns a vector of pointers to all the |RTCStatsMemberInterface| members 70 // of this class. This allows for iteration of members. For a given class, 71 // |Members| always returns the same members in the same order. 72 std::vector<const RTCStatsMemberInterface*> Members() const; 73 // Checks if the two stats objects are of the same type and have the same 74 // member values. Timestamps are not compared. These operators are exposed for 75 // testing. 76 bool operator==(const RTCStats& other) const; 77 bool operator!=(const RTCStats& other) const; 78 79 // Creates a JSON readable string representation of the stats 80 // object, listing all of its members (names and values). 81 std::string ToJson() const; 82 83 // Downcasts the stats object to an |RTCStats| subclass |T|. DCHECKs that the 84 // object is of type |T|. 85 template <typename T> cast_to()86 const T& cast_to() const { 87 RTC_DCHECK_EQ(type(), T::kType); 88 return static_cast<const T&>(*this); 89 } 90 91 protected: 92 // Gets a vector of all members of this |RTCStats| object, including members 93 // derived from parent classes. |additional_capacity| is how many more members 94 // shall be reserved in the vector (so that subclasses can allocate a vector 95 // with room for both parent and child members without it having to resize). 96 virtual std::vector<const RTCStatsMemberInterface*> 97 MembersOfThisObjectAndAncestors(size_t additional_capacity) const; 98 99 std::string const id_; 100 int64_t timestamp_us_; 101 }; 102 103 // All |RTCStats| classes should use these macros. 104 // |WEBRTC_RTCSTATS_DECL| is placed in a public section of the class definition. 105 // |WEBRTC_RTCSTATS_IMPL| is placed outside the class definition (in a .cc). 106 // 107 // These macros declare (in _DECL) and define (in _IMPL) the static |kType| and 108 // overrides methods as required by subclasses of |RTCStats|: |copy|, |type| and 109 // |MembersOfThisObjectAndAncestors|. The |...| argument is a list of addresses 110 // to each member defined in the implementing class. The list must have at least 111 // one member. 112 // 113 // (Since class names need to be known to implement these methods this cannot be 114 // part of the base |RTCStats|. While these methods could be implemented using 115 // templates, that would only work for immediate subclasses. Subclasses of 116 // subclasses also have to override these methods, resulting in boilerplate 117 // code. Using a macro avoids this and works for any |RTCStats| class, including 118 // grandchildren.) 119 // 120 // Sample usage: 121 // 122 // rtcfoostats.h: 123 // class RTCFooStats : public RTCStats { 124 // public: 125 // WEBRTC_RTCSTATS_DECL(); 126 // 127 // RTCFooStats(const std::string& id, int64_t timestamp_us); 128 // 129 // RTCStatsMember<int32_t> foo; 130 // RTCStatsMember<int32_t> bar; 131 // }; 132 // 133 // rtcfoostats.cc: 134 // WEBRTC_RTCSTATS_IMPL(RTCFooStats, RTCStats, "foo-stats" 135 // &foo, 136 // &bar); 137 // 138 // RTCFooStats::RTCFooStats(const std::string& id, int64_t timestamp_us) 139 // : RTCStats(id, timestamp_us), 140 // foo("foo"), 141 // bar("bar") { 142 // } 143 // 144 #define WEBRTC_RTCSTATS_DECL() \ 145 protected: \ 146 std::vector<const webrtc::RTCStatsMemberInterface*> \ 147 MembersOfThisObjectAndAncestors(size_t local_var_additional_capacity) \ 148 const override; \ 149 \ 150 public: \ 151 static const char kType[]; \ 152 \ 153 std::unique_ptr<webrtc::RTCStats> copy() const override; \ 154 const char* type() const override 155 156 #define WEBRTC_RTCSTATS_IMPL(this_class, parent_class, type_str, ...) \ 157 const char this_class::kType[] = type_str; \ 158 \ 159 std::unique_ptr<webrtc::RTCStats> this_class::copy() const { \ 160 return std::unique_ptr<webrtc::RTCStats>(new this_class(*this)); \ 161 } \ 162 \ 163 const char* this_class::type() const { return this_class::kType; } \ 164 \ 165 std::vector<const webrtc::RTCStatsMemberInterface*> \ 166 this_class::MembersOfThisObjectAndAncestors( \ 167 size_t local_var_additional_capacity) const { \ 168 const webrtc::RTCStatsMemberInterface* local_var_members[] = { \ 169 __VA_ARGS__}; \ 170 size_t local_var_members_count = \ 171 sizeof(local_var_members) / sizeof(local_var_members[0]); \ 172 std::vector<const webrtc::RTCStatsMemberInterface*> \ 173 local_var_members_vec = parent_class::MembersOfThisObjectAndAncestors( \ 174 local_var_members_count + local_var_additional_capacity); \ 175 RTC_DCHECK_GE( \ 176 local_var_members_vec.capacity() - local_var_members_vec.size(), \ 177 local_var_members_count + local_var_additional_capacity); \ 178 local_var_members_vec.insert(local_var_members_vec.end(), \ 179 &local_var_members[0], \ 180 &local_var_members[local_var_members_count]); \ 181 return local_var_members_vec; \ 182 } 183 184 // A version of WEBRTC_RTCSTATS_IMPL() where "..." is omitted, used to avoid a 185 // compile error on windows. This is used if the stats dictionary does not 186 // declare any members of its own (but perhaps its parent dictionary does). 187 #define WEBRTC_RTCSTATS_IMPL_NO_MEMBERS(this_class, parent_class, type_str) \ 188 const char this_class::kType[] = type_str; \ 189 \ 190 std::unique_ptr<webrtc::RTCStats> this_class::copy() const { \ 191 return std::unique_ptr<webrtc::RTCStats>(new this_class(*this)); \ 192 } \ 193 \ 194 const char* this_class::type() const { return this_class::kType; } \ 195 \ 196 std::vector<const webrtc::RTCStatsMemberInterface*> \ 197 this_class::MembersOfThisObjectAndAncestors( \ 198 size_t local_var_additional_capacity) const { \ 199 return parent_class::MembersOfThisObjectAndAncestors(0); \ 200 } 201 202 // Non-standard stats members can be exposed to the JavaScript API in Chrome 203 // e.g. through origin trials. The group ID can be used by the blink layer to 204 // determine if a stats member should be exposed or not. Multiple non-standard 205 // stats members can share the same group ID so that they are exposed together. 206 enum class NonStandardGroupId { 207 // Group ID used for testing purposes only. 208 kGroupIdForTesting, 209 // I2E: 210 // https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/hE2B1iItPDk 211 kRtcAudioJitterBufferMaxPackets, 212 // I2E: 213 // https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/YbhMyqLXXXo 214 kRtcStatsRelativePacketArrivalDelay, 215 }; 216 217 // Interface for |RTCStats| members, which have a name and a value of a type 218 // defined in a subclass. Only the types listed in |Type| are supported, these 219 // are implemented by |RTCStatsMember<T>|. The value of a member may be 220 // undefined, the value can only be read if |is_defined|. 221 class RTCStatsMemberInterface { 222 public: 223 // Member value types. 224 enum Type { 225 kBool, // bool 226 kInt32, // int32_t 227 kUint32, // uint32_t 228 kInt64, // int64_t 229 kUint64, // uint64_t 230 kDouble, // double 231 kString, // std::string 232 233 kSequenceBool, // std::vector<bool> 234 kSequenceInt32, // std::vector<int32_t> 235 kSequenceUint32, // std::vector<uint32_t> 236 kSequenceInt64, // std::vector<int64_t> 237 kSequenceUint64, // std::vector<uint64_t> 238 kSequenceDouble, // std::vector<double> 239 kSequenceString, // std::vector<std::string> 240 }; 241 ~RTCStatsMemberInterface()242 virtual ~RTCStatsMemberInterface() {} 243 name()244 const char* name() const { return name_; } 245 virtual Type type() const = 0; 246 virtual bool is_sequence() const = 0; 247 virtual bool is_string() const = 0; is_defined()248 bool is_defined() const { return is_defined_; } 249 // Is this part of the stats spec? Used so that chromium can easily filter 250 // out anything unstandardized. 251 virtual bool is_standardized() const = 0; 252 // Non-standard stats members can have group IDs in order to be exposed in 253 // JavaScript through experiments. Standardized stats have no group IDs. group_ids()254 virtual std::vector<NonStandardGroupId> group_ids() const { return {}; } 255 // Type and value comparator. The names are not compared. These operators are 256 // exposed for testing. 257 virtual bool operator==(const RTCStatsMemberInterface& other) const = 0; 258 bool operator!=(const RTCStatsMemberInterface& other) const { 259 return !(*this == other); 260 } 261 virtual std::string ValueToString() const = 0; 262 // This is the same as ValueToString except for kInt64 and kUint64 types, 263 // where the value is represented as a double instead of as an integer. 264 // Since JSON stores numbers as floating point numbers, very large integers 265 // cannot be accurately represented, so we prefer to display them as doubles 266 // instead. 267 virtual std::string ValueToJson() const = 0; 268 269 template <typename T> cast_to()270 const T& cast_to() const { 271 RTC_DCHECK_EQ(type(), T::StaticType()); 272 return static_cast<const T&>(*this); 273 } 274 275 protected: RTCStatsMemberInterface(const char * name,bool is_defined)276 RTCStatsMemberInterface(const char* name, bool is_defined) 277 : name_(name), is_defined_(is_defined) {} 278 279 const char* const name_; 280 bool is_defined_; 281 }; 282 283 // Template implementation of |RTCStatsMemberInterface|. 284 // The supported types are the ones described by 285 // |RTCStatsMemberInterface::Type|. 286 template <typename T> 287 class RTCStatsMember : public RTCStatsMemberInterface { 288 public: RTCStatsMember(const char * name)289 explicit RTCStatsMember(const char* name) 290 : RTCStatsMemberInterface(name, /*is_defined=*/false), value_() {} RTCStatsMember(const char * name,const T & value)291 RTCStatsMember(const char* name, const T& value) 292 : RTCStatsMemberInterface(name, /*is_defined=*/true), value_(value) {} RTCStatsMember(const char * name,T && value)293 RTCStatsMember(const char* name, T&& value) 294 : RTCStatsMemberInterface(name, /*is_defined=*/true), 295 value_(std::move(value)) {} RTCStatsMember(const RTCStatsMember<T> & other)296 explicit RTCStatsMember(const RTCStatsMember<T>& other) 297 : RTCStatsMemberInterface(other.name_, other.is_defined_), 298 value_(other.value_) {} RTCStatsMember(RTCStatsMember<T> && other)299 explicit RTCStatsMember(RTCStatsMember<T>&& other) 300 : RTCStatsMemberInterface(other.name_, other.is_defined_), 301 value_(std::move(other.value_)) {} 302 303 static Type StaticType(); type()304 Type type() const override { return StaticType(); } 305 bool is_sequence() const override; 306 bool is_string() const override; is_standardized()307 bool is_standardized() const override { return true; } 308 bool operator==(const RTCStatsMemberInterface& other) const override { 309 if (type() != other.type() || is_standardized() != other.is_standardized()) 310 return false; 311 const RTCStatsMember<T>& other_t = 312 static_cast<const RTCStatsMember<T>&>(other); 313 if (!is_defined_) 314 return !other_t.is_defined(); 315 if (!other.is_defined()) 316 return false; 317 return value_ == other_t.value_; 318 } 319 std::string ValueToString() const override; 320 std::string ValueToJson() const override; 321 322 template <typename U> ValueOrDefault(U default_value)323 inline T ValueOrDefault(U default_value) const { 324 if (is_defined()) { 325 return *(*this); 326 } 327 return default_value; 328 } 329 330 // Assignment operators. 331 T& operator=(const T& value) { 332 value_ = value; 333 is_defined_ = true; 334 return value_; 335 } 336 T& operator=(const T&& value) { 337 value_ = std::move(value); 338 is_defined_ = true; 339 return value_; 340 } 341 342 // Value getters. 343 T& operator*() { 344 RTC_DCHECK(is_defined_); 345 return value_; 346 } 347 const T& operator*() const { 348 RTC_DCHECK(is_defined_); 349 return value_; 350 } 351 352 // Value getters, arrow operator. 353 T* operator->() { 354 RTC_DCHECK(is_defined_); 355 return &value_; 356 } 357 const T* operator->() const { 358 RTC_DCHECK(is_defined_); 359 return &value_; 360 } 361 362 private: 363 T value_; 364 }; 365 366 #define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \ 367 template <> \ 368 RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember<T>::StaticType(); \ 369 template <> \ 370 RTC_EXPORT bool RTCStatsMember<T>::is_sequence() const; \ 371 template <> \ 372 RTC_EXPORT bool RTCStatsMember<T>::is_string() const; \ 373 template <> \ 374 RTC_EXPORT std::string RTCStatsMember<T>::ValueToString() const; \ 375 template <> \ 376 RTC_EXPORT std::string RTCStatsMember<T>::ValueToJson() const; \ 377 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) \ 378 RTCStatsMember<T> 379 380 WEBRTC_DECLARE_RTCSTATSMEMBER(bool); 381 WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t); 382 WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t); 383 WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t); 384 WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t); 385 WEBRTC_DECLARE_RTCSTATSMEMBER(double); 386 WEBRTC_DECLARE_RTCSTATSMEMBER(std::string); 387 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<bool>); 388 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int32_t>); 389 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint32_t>); 390 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int64_t>); 391 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint64_t>); 392 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<double>); 393 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<std::string>); 394 395 // Using inheritance just so that it's obvious from the member's declaration 396 // whether it's standardized or not. 397 template <typename T> 398 class RTCNonStandardStatsMember : public RTCStatsMember<T> { 399 public: RTCNonStandardStatsMember(const char * name)400 explicit RTCNonStandardStatsMember(const char* name) 401 : RTCStatsMember<T>(name) {} RTCNonStandardStatsMember(const char * name,std::initializer_list<NonStandardGroupId> group_ids)402 RTCNonStandardStatsMember(const char* name, 403 std::initializer_list<NonStandardGroupId> group_ids) 404 : RTCStatsMember<T>(name), group_ids_(group_ids) {} RTCNonStandardStatsMember(const char * name,const T & value)405 RTCNonStandardStatsMember(const char* name, const T& value) 406 : RTCStatsMember<T>(name, value) {} RTCNonStandardStatsMember(const char * name,T && value)407 RTCNonStandardStatsMember(const char* name, T&& value) 408 : RTCStatsMember<T>(name, std::move(value)) {} RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T> & other)409 explicit RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T>& other) 410 : RTCStatsMember<T>(other), group_ids_(other.group_ids_) {} RTCNonStandardStatsMember(RTCNonStandardStatsMember<T> && other)411 explicit RTCNonStandardStatsMember(RTCNonStandardStatsMember<T>&& other) 412 : RTCStatsMember<T>(std::move(other)), 413 group_ids_(std::move(other.group_ids_)) {} 414 is_standardized()415 bool is_standardized() const override { return false; } 416 group_ids()417 std::vector<NonStandardGroupId> group_ids() const override { 418 return group_ids_; 419 } 420 421 T& operator=(const T& value) { return RTCStatsMember<T>::operator=(value); } 422 T& operator=(const T&& value) { 423 return RTCStatsMember<T>::operator=(std::move(value)); 424 } 425 426 private: 427 std::vector<NonStandardGroupId> group_ids_; 428 }; 429 430 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 431 RTCNonStandardStatsMember<bool>; 432 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 433 RTCNonStandardStatsMember<int32_t>; 434 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 435 RTCNonStandardStatsMember<uint32_t>; 436 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 437 RTCNonStandardStatsMember<int64_t>; 438 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 439 RTCNonStandardStatsMember<uint64_t>; 440 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 441 RTCNonStandardStatsMember<double>; 442 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 443 RTCNonStandardStatsMember<std::string>; 444 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 445 RTCNonStandardStatsMember<std::vector<bool>>; 446 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 447 RTCNonStandardStatsMember<std::vector<int32_t>>; 448 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 449 RTCNonStandardStatsMember<std::vector<uint32_t>>; 450 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 451 RTCNonStandardStatsMember<std::vector<int64_t>>; 452 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 453 RTCNonStandardStatsMember<std::vector<uint64_t>>; 454 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 455 RTCNonStandardStatsMember<std::vector<double>>; 456 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) 457 RTCNonStandardStatsMember<std::vector<std::string>>; 458 459 } // namespace webrtc 460 461 #endif // API_STATS_RTC_STATS_H_ 462