blob: f65df289e1df7804bea08354aed04a213cfc5fb9 [file] [log] [blame]
hbos74e1a4f2016-09-15 23:33:01 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#ifndef API_STATS_RTCSTATS_H_
12#define API_STATS_RTCSTATS_H_
hbos74e1a4f2016-09-15 23:33:01 -070013
14#include <map>
15#include <memory>
16#include <string>
17#include <utility>
18#include <vector>
19
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
Mirko Bonadei276827c2018-10-16 14:13:50 +020021#include "rtc_base/system/rtc_export.h"
hbos74e1a4f2016-09-15 23:33:01 -070022
23namespace webrtc {
24
25class RTCStatsMemberInterface;
26
27// Abstract base class for RTCStats-derived dictionaries, see
28// https://w3c.github.io/webrtc-stats/.
29//
30// All derived classes must have the following static variable defined:
31// static const char kType[];
32// It is used as a unique class identifier and a string representation of the
33// class type, see https://w3c.github.io/webrtc-stats/#rtcstatstype-str*.
34// Use the |WEBRTC_RTCSTATS_IMPL| macro when implementing subclasses, see macro
35// for details.
36//
37// Derived classes list their dictionary members, RTCStatsMember<T>, as public
38// fields, allowing the following:
39//
40// RTCFooStats foo("fooId", GetCurrentTime());
41// foo.bar = 42;
42// foo.baz = std::vector<std::string>();
43// foo.baz->push_back("hello world");
44// uint32_t x = *foo.bar;
45//
46// Pointers to all the members are available with |Members|, allowing iteration:
47//
48// for (const RTCStatsMemberInterface* member : foo.Members()) {
49// printf("%s = %s\n", member->name(), member->ValueToString().c_str());
50// }
Mirko Bonadei276827c2018-10-16 14:13:50 +020051class RTC_EXPORT RTCStats {
hbos74e1a4f2016-09-15 23:33:01 -070052 public:
53 RTCStats(const std::string& id, int64_t timestamp_us)
54 : id_(id), timestamp_us_(timestamp_us) {}
55 RTCStats(std::string&& id, int64_t timestamp_us)
56 : id_(std::move(id)), timestamp_us_(timestamp_us) {}
57 virtual ~RTCStats() {}
58
59 virtual std::unique_ptr<RTCStats> copy() const = 0;
60
61 const std::string& id() const { return id_; }
62 // Time relative to the UNIX epoch (Jan 1, 1970, UTC), in microseconds.
63 int64_t timestamp_us() const { return timestamp_us_; }
64 // Returns the static member variable |kType| of the implementing class.
65 virtual const char* type() const = 0;
hbos67c8bc42016-10-25 04:31:23 -070066 // Returns a vector of pointers to all the |RTCStatsMemberInterface| members
67 // of this class. This allows for iteration of members. For a given class,
68 // |Members| always returns the same members in the same order.
hbos74e1a4f2016-09-15 23:33:01 -070069 std::vector<const RTCStatsMemberInterface*> Members() const;
hbos67c8bc42016-10-25 04:31:23 -070070 // Checks if the two stats objects are of the same type and have the same
hbos0583b282016-11-30 01:50:14 -080071 // member values. Timestamps are not compared. These operators are exposed for
72 // testing.
hbos67c8bc42016-10-25 04:31:23 -070073 bool operator==(const RTCStats& other) const;
74 bool operator!=(const RTCStats& other) const;
hbos74e1a4f2016-09-15 23:33:01 -070075
ehmaldonado35a872c2017-07-28 07:29:12 -070076 // Creates a JSON readable string representation of the stats
77 // object, listing all of its members (names and values).
78 std::string ToJson() const;
hbos74e1a4f2016-09-15 23:33:01 -070079
80 // Downcasts the stats object to an |RTCStats| subclass |T|. DCHECKs that the
81 // object is of type |T|.
Yves Gerey665174f2018-06-19 15:03:05 +020082 template <typename T>
hbos74e1a4f2016-09-15 23:33:01 -070083 const T& cast_to() const {
84 RTC_DCHECK_EQ(type(), T::kType);
85 return static_cast<const T&>(*this);
86 }
87
88 protected:
89 // Gets a vector of all members of this |RTCStats| object, including members
90 // derived from parent classes. |additional_capacity| is how many more members
91 // shall be reserved in the vector (so that subclasses can allocate a vector
92 // with room for both parent and child members without it having to resize).
93 virtual std::vector<const RTCStatsMemberInterface*>
Yves Gerey665174f2018-06-19 15:03:05 +020094 MembersOfThisObjectAndAncestors(size_t additional_capacity) const;
hbos74e1a4f2016-09-15 23:33:01 -070095
96 std::string const id_;
97 int64_t timestamp_us_;
98};
99
hbosfc5e0502016-10-06 02:06:10 -0700100// All |RTCStats| classes should use these macros.
101// |WEBRTC_RTCSTATS_DECL| is placed in a public section of the class definition.
102// |WEBRTC_RTCSTATS_IMPL| is placed outside the class definition (in a .cc).
hbos74e1a4f2016-09-15 23:33:01 -0700103//
hbosfc5e0502016-10-06 02:06:10 -0700104// These macros declare (in _DECL) and define (in _IMPL) the static |kType| and
105// overrides methods as required by subclasses of |RTCStats|: |copy|, |type| and
hbos74e1a4f2016-09-15 23:33:01 -0700106// |MembersOfThisObjectAndAncestors|. The |...| argument is a list of addresses
hbosfc5e0502016-10-06 02:06:10 -0700107// to each member defined in the implementing class. The list must have at least
108// one member.
hbos74e1a4f2016-09-15 23:33:01 -0700109//
110// (Since class names need to be known to implement these methods this cannot be
111// part of the base |RTCStats|. While these methods could be implemented using
112// templates, that would only work for immediate subclasses. Subclasses of
113// subclasses also have to override these methods, resulting in boilerplate
114// code. Using a macro avoids this and works for any |RTCStats| class, including
115// grandchildren.)
116//
117// Sample usage:
118//
119// rtcfoostats.h:
120// class RTCFooStats : public RTCStats {
121// public:
hbosfc5e0502016-10-06 02:06:10 -0700122// WEBRTC_RTCSTATS_DECL();
hbos74e1a4f2016-09-15 23:33:01 -0700123//
hbosfc5e0502016-10-06 02:06:10 -0700124// RTCFooStats(const std::string& id, int64_t timestamp_us);
hbos74e1a4f2016-09-15 23:33:01 -0700125//
126// RTCStatsMember<int32_t> foo;
127// RTCStatsMember<int32_t> bar;
128// };
129//
130// rtcfoostats.cc:
hbosfc5e0502016-10-06 02:06:10 -0700131// WEBRTC_RTCSTATS_IMPL(RTCFooStats, RTCStats, "foo-stats"
132// &foo,
133// &bar);
hbos74e1a4f2016-09-15 23:33:01 -0700134//
hbosfc5e0502016-10-06 02:06:10 -0700135// RTCFooStats::RTCFooStats(const std::string& id, int64_t timestamp_us)
136// : RTCStats(id, timestamp_us),
137// foo("foo"),
138// bar("bar") {
139// }
140//
Yves Gerey665174f2018-06-19 15:03:05 +0200141#define WEBRTC_RTCSTATS_DECL() \
142 public: \
143 static const char kType[]; \
144 \
145 std::unique_ptr<webrtc::RTCStats> copy() const override; \
146 const char* type() const override; \
147 \
148 protected: \
149 std::vector<const webrtc::RTCStatsMemberInterface*> \
150 MembersOfThisObjectAndAncestors(size_t local_var_additional_capacity) \
151 const override; \
152 \
hbosfc5e0502016-10-06 02:06:10 -0700153 public:
154
155#define WEBRTC_RTCSTATS_IMPL(this_class, parent_class, type_str, ...) \
156 const char this_class::kType[] = type_str; \
157 \
158 std::unique_ptr<webrtc::RTCStats> this_class::copy() const { \
159 return std::unique_ptr<webrtc::RTCStats>(new this_class(*this)); \
160 } \
161 \
Yves Gerey665174f2018-06-19 15:03:05 +0200162 const char* this_class::type() const { return this_class::kType; } \
hbosfc5e0502016-10-06 02:06:10 -0700163 \
164 std::vector<const webrtc::RTCStatsMemberInterface*> \
165 this_class::MembersOfThisObjectAndAncestors( \
166 size_t local_var_additional_capacity) const { \
hbos74e1a4f2016-09-15 23:33:01 -0700167 const webrtc::RTCStatsMemberInterface* local_var_members[] = { \
Yves Gerey665174f2018-06-19 15:03:05 +0200168 __VA_ARGS__}; \
hbos74e1a4f2016-09-15 23:33:01 -0700169 size_t local_var_members_count = \
170 sizeof(local_var_members) / sizeof(local_var_members[0]); \
Yves Gerey665174f2018-06-19 15:03:05 +0200171 std::vector<const webrtc::RTCStatsMemberInterface*> \
172 local_var_members_vec = parent_class::MembersOfThisObjectAndAncestors( \
hbos74e1a4f2016-09-15 23:33:01 -0700173 local_var_members_count + local_var_additional_capacity); \
174 RTC_DCHECK_GE( \
175 local_var_members_vec.capacity() - local_var_members_vec.size(), \
176 local_var_members_count + local_var_additional_capacity); \
177 local_var_members_vec.insert(local_var_members_vec.end(), \
178 &local_var_members[0], \
179 &local_var_members[local_var_members_count]); \
180 return local_var_members_vec; \
hbosfc5e0502016-10-06 02:06:10 -0700181 }
hbos74e1a4f2016-09-15 23:33:01 -0700182
183// Interface for |RTCStats| members, which have a name and a value of a type
184// defined in a subclass. Only the types listed in |Type| are supported, these
185// are implemented by |RTCStatsMember<T>|. The value of a member may be
186// undefined, the value can only be read if |is_defined|.
187class RTCStatsMemberInterface {
188 public:
189 // Member value types.
190 enum Type {
Yves Gerey665174f2018-06-19 15:03:05 +0200191 kBool, // bool
192 kInt32, // int32_t
193 kUint32, // uint32_t
194 kInt64, // int64_t
195 kUint64, // uint64_t
196 kDouble, // double
197 kString, // std::string
hbos74e1a4f2016-09-15 23:33:01 -0700198
Yves Gerey665174f2018-06-19 15:03:05 +0200199 kSequenceBool, // std::vector<bool>
200 kSequenceInt32, // std::vector<int32_t>
201 kSequenceUint32, // std::vector<uint32_t>
202 kSequenceInt64, // std::vector<int64_t>
203 kSequenceUint64, // std::vector<uint64_t>
204 kSequenceDouble, // std::vector<double>
205 kSequenceString, // std::vector<std::string>
hbos74e1a4f2016-09-15 23:33:01 -0700206 };
207
208 virtual ~RTCStatsMemberInterface() {}
209
210 const char* name() const { return name_; }
211 virtual Type type() const = 0;
212 virtual bool is_sequence() const = 0;
213 virtual bool is_string() const = 0;
214 bool is_defined() const { return is_defined_; }
Taylor Brandstettere2751742018-06-25 13:42:44 -0700215 // Is this part of the stats spec? Used so that chromium can easily filter
216 // out anything unstandardized.
217 virtual bool is_standardized() const = 0;
hbos67c8bc42016-10-25 04:31:23 -0700218 // Type and value comparator. The names are not compared. These operators are
219 // exposed for testing.
220 virtual bool operator==(const RTCStatsMemberInterface& other) const = 0;
221 bool operator!=(const RTCStatsMemberInterface& other) const {
222 return !(*this == other);
223 }
hbos74e1a4f2016-09-15 23:33:01 -0700224 virtual std::string ValueToString() const = 0;
ehmaldonado35a872c2017-07-28 07:29:12 -0700225 // This is the same as ValueToString except for kInt64 and kUint64 types,
226 // where the value is represented as a double instead of as an integer.
227 // Since JSON stores numbers as floating point numbers, very large integers
228 // cannot be accurately represented, so we prefer to display them as doubles
229 // instead.
230 virtual std::string ValueToJson() const = 0;
hbos74e1a4f2016-09-15 23:33:01 -0700231
Yves Gerey665174f2018-06-19 15:03:05 +0200232 template <typename T>
hbos74e1a4f2016-09-15 23:33:01 -0700233 const T& cast_to() const {
234 RTC_DCHECK_EQ(type(), T::kType);
235 return static_cast<const T&>(*this);
236 }
237
238 protected:
239 RTCStatsMemberInterface(const char* name, bool is_defined)
240 : name_(name), is_defined_(is_defined) {}
241
242 const char* const name_;
243 bool is_defined_;
244};
245
246// Template implementation of |RTCStatsMemberInterface|. Every possible |T| is
247// specialized in rtcstats.cc, using a different |T| results in a linker error
248// (undefined reference to |kType|). The supported types are the ones described
249// by |RTCStatsMemberInterface::Type|.
Yves Gerey665174f2018-06-19 15:03:05 +0200250template <typename T>
Mirko Bonadei276827c2018-10-16 14:13:50 +0200251class RTC_EXPORT RTCStatsMember : public RTCStatsMemberInterface {
hbos74e1a4f2016-09-15 23:33:01 -0700252 public:
253 static const Type kType;
254
255 explicit RTCStatsMember(const char* name)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700256 : RTCStatsMemberInterface(name, /*is_defined=*/false), value_() {}
hbos74e1a4f2016-09-15 23:33:01 -0700257 RTCStatsMember(const char* name, const T& value)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700258 : RTCStatsMemberInterface(name, /*is_defined=*/true), value_(value) {}
hbos74e1a4f2016-09-15 23:33:01 -0700259 RTCStatsMember(const char* name, T&& value)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700260 : RTCStatsMemberInterface(name, /*is_defined=*/true),
261 value_(std::move(value)) {}
hbos74e1a4f2016-09-15 23:33:01 -0700262 explicit RTCStatsMember(const RTCStatsMember<T>& other)
263 : RTCStatsMemberInterface(other.name_, other.is_defined_),
264 value_(other.value_) {}
265 explicit RTCStatsMember(RTCStatsMember<T>&& other)
266 : RTCStatsMemberInterface(other.name_, other.is_defined_),
267 value_(std::move(other.value_)) {}
268
269 Type type() const override { return kType; }
270 bool is_sequence() const override;
271 bool is_string() const override;
Taylor Brandstettere2751742018-06-25 13:42:44 -0700272 bool is_standardized() const override { return true; }
hbos67c8bc42016-10-25 04:31:23 -0700273 bool operator==(const RTCStatsMemberInterface& other) const override {
Taylor Brandstettere2751742018-06-25 13:42:44 -0700274 if (type() != other.type() || is_standardized() != other.is_standardized())
hbos67c8bc42016-10-25 04:31:23 -0700275 return false;
276 const RTCStatsMember<T>& other_t =
277 static_cast<const RTCStatsMember<T>&>(other);
278 if (!is_defined_)
279 return !other_t.is_defined();
hbos28747962016-11-21 09:17:41 -0800280 if (!other.is_defined())
281 return false;
hbos67c8bc42016-10-25 04:31:23 -0700282 return value_ == other_t.value_;
283 }
hbos74e1a4f2016-09-15 23:33:01 -0700284 std::string ValueToString() const override;
ehmaldonado35a872c2017-07-28 07:29:12 -0700285 std::string ValueToJson() const override;
hbos74e1a4f2016-09-15 23:33:01 -0700286
287 // Assignment operators.
288 T& operator=(const T& value) {
289 value_ = value;
290 is_defined_ = true;
291 return value_;
292 }
293 T& operator=(const T&& value) {
294 value_ = std::move(value);
295 is_defined_ = true;
296 return value_;
297 }
298 T& operator=(const RTCStatsMember<T>& other) {
299 RTC_DCHECK(other.is_defined_);
Taylor Brandstettere2751742018-06-25 13:42:44 -0700300 // Shouldn't be attempting to assign an RTCNonStandardStatsMember to an
301 // RTCStatsMember or vice versa.
302 RTC_DCHECK(is_standardized() == other.is_standardized());
303 value_ = other.value_;
hbos74e1a4f2016-09-15 23:33:01 -0700304 is_defined_ = true;
305 return value_;
306 }
307
308 // Value getters.
309 T& operator*() {
310 RTC_DCHECK(is_defined_);
311 return value_;
312 }
313 const T& operator*() const {
314 RTC_DCHECK(is_defined_);
315 return value_;
316 }
317
318 // Value getters, arrow operator.
319 T* operator->() {
320 RTC_DCHECK(is_defined_);
321 return &value_;
322 }
323 const T* operator->() const {
324 RTC_DCHECK(is_defined_);
325 return &value_;
326 }
327
328 private:
329 T value_;
330};
331
Taylor Brandstettere2751742018-06-25 13:42:44 -0700332// Same as above, but "is_standardized" returns false.
333//
334// Using inheritance just so that it's obvious from the member's declaration
335// whether it's standardized or not.
336template <typename T>
337class RTCNonStandardStatsMember : public RTCStatsMember<T> {
338 public:
339 explicit RTCNonStandardStatsMember(const char* name)
340 : RTCStatsMember<T>(name) {}
341 RTCNonStandardStatsMember(const char* name, const T& value)
342 : RTCStatsMember<T>(name, value) {}
343 RTCNonStandardStatsMember(const char* name, T&& value)
344 : RTCStatsMember<T>(name, std::move(value)) {}
345 explicit RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T>& other)
346 : RTCStatsMember<T>(other) {}
347 explicit RTCNonStandardStatsMember(RTCNonStandardStatsMember<T>&& other)
348 : RTCStatsMember<T>(std::move(other)) {}
349
350 bool is_standardized() const override { return false; }
351};
hbos74e1a4f2016-09-15 23:33:01 -0700352} // namespace webrtc
353
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200354#endif // API_STATS_RTCSTATS_H_