• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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