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   // Assignment operators.
323   T& operator=(const T& value) {
324     value_ = value;
325     is_defined_ = true;
326     return value_;
327   }
328   T& operator=(const T&& value) {
329     value_ = std::move(value);
330     is_defined_ = true;
331     return value_;
332   }
333 
334   // Value getters.
335   T& operator*() {
336     RTC_DCHECK(is_defined_);
337     return value_;
338   }
339   const T& operator*() const {
340     RTC_DCHECK(is_defined_);
341     return value_;
342   }
343 
344   // Value getters, arrow operator.
345   T* operator->() {
346     RTC_DCHECK(is_defined_);
347     return &value_;
348   }
349   const T* operator->() const {
350     RTC_DCHECK(is_defined_);
351     return &value_;
352   }
353 
354  private:
355   T value_;
356 };
357 
358 #define WEBRTC_DECLARE_RTCSTATSMEMBER(T)                                    \
359   template <>                                                               \
360   RTC_EXPORT RTCStatsMemberInterface::Type RTCStatsMember<T>::StaticType(); \
361   template <>                                                               \
362   RTC_EXPORT bool RTCStatsMember<T>::is_sequence() const;                   \
363   template <>                                                               \
364   RTC_EXPORT bool RTCStatsMember<T>::is_string() const;                     \
365   template <>                                                               \
366   RTC_EXPORT std::string RTCStatsMember<T>::ValueToString() const;          \
367   template <>                                                               \
368   RTC_EXPORT std::string RTCStatsMember<T>::ValueToJson() const;            \
369   extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)             \
370       RTCStatsMember<T>
371 
372 WEBRTC_DECLARE_RTCSTATSMEMBER(bool);
373 WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t);
374 WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t);
375 WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t);
376 WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t);
377 WEBRTC_DECLARE_RTCSTATSMEMBER(double);
378 WEBRTC_DECLARE_RTCSTATSMEMBER(std::string);
379 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<bool>);
380 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int32_t>);
381 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint32_t>);
382 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int64_t>);
383 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint64_t>);
384 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<double>);
385 WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<std::string>);
386 
387 // Using inheritance just so that it's obvious from the member's declaration
388 // whether it's standardized or not.
389 template <typename T>
390 class RTCNonStandardStatsMember : public RTCStatsMember<T> {
391  public:
RTCNonStandardStatsMember(const char * name)392   explicit RTCNonStandardStatsMember(const char* name)
393       : RTCStatsMember<T>(name) {}
RTCNonStandardStatsMember(const char * name,std::initializer_list<NonStandardGroupId> group_ids)394   RTCNonStandardStatsMember(const char* name,
395                             std::initializer_list<NonStandardGroupId> group_ids)
396       : RTCStatsMember<T>(name), group_ids_(group_ids) {}
RTCNonStandardStatsMember(const char * name,const T & value)397   RTCNonStandardStatsMember(const char* name, const T& value)
398       : RTCStatsMember<T>(name, value) {}
RTCNonStandardStatsMember(const char * name,T && value)399   RTCNonStandardStatsMember(const char* name, T&& value)
400       : RTCStatsMember<T>(name, std::move(value)) {}
RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T> & other)401   explicit RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T>& other)
402       : RTCStatsMember<T>(other), group_ids_(other.group_ids_) {}
RTCNonStandardStatsMember(RTCNonStandardStatsMember<T> && other)403   explicit RTCNonStandardStatsMember(RTCNonStandardStatsMember<T>&& other)
404       : RTCStatsMember<T>(std::move(other)),
405         group_ids_(std::move(other.group_ids_)) {}
406 
is_standardized()407   bool is_standardized() const override { return false; }
408 
group_ids()409   std::vector<NonStandardGroupId> group_ids() const override {
410     return group_ids_;
411   }
412 
413   T& operator=(const T& value) { return RTCStatsMember<T>::operator=(value); }
414   T& operator=(const T&& value) {
415     return RTCStatsMember<T>::operator=(std::move(value));
416   }
417 
418  private:
419   std::vector<NonStandardGroupId> group_ids_;
420 };
421 
422 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
423     RTCNonStandardStatsMember<bool>;
424 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
425     RTCNonStandardStatsMember<int32_t>;
426 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
427     RTCNonStandardStatsMember<uint32_t>;
428 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
429     RTCNonStandardStatsMember<int64_t>;
430 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
431     RTCNonStandardStatsMember<uint64_t>;
432 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
433     RTCNonStandardStatsMember<double>;
434 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
435     RTCNonStandardStatsMember<std::string>;
436 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
437     RTCNonStandardStatsMember<std::vector<bool>>;
438 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
439     RTCNonStandardStatsMember<std::vector<int32_t>>;
440 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
441     RTCNonStandardStatsMember<std::vector<uint32_t>>;
442 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
443     RTCNonStandardStatsMember<std::vector<int64_t>>;
444 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
445     RTCNonStandardStatsMember<std::vector<uint64_t>>;
446 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
447     RTCNonStandardStatsMember<std::vector<double>>;
448 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT)
449     RTCNonStandardStatsMember<std::vector<std::string>>;
450 
451 }  // namespace webrtc
452 
453 #endif  // API_STATS_RTC_STATS_H_
454