blob: 80a1276417721a808fa3bb70ba927ce8f4deede0 [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
Steve Anton10542f22019-01-11 09:11:00 -080011#ifndef API_STATS_RTC_STATS_H_
12#define API_STATS_RTC_STATS_H_
hbos74e1a4f2016-09-15 23:33:01 -070013
Yves Gerey3e707812018-11-28 16:47:49 +010014#include <stddef.h>
15#include <stdint.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020016
hbos74e1a4f2016-09-15 23:33:01 -070017#include <memory>
18#include <string>
19#include <utility>
20#include <vector>
21
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
Mirko Bonadei276827c2018-10-16 14:13:50 +020023#include "rtc_base/system/rtc_export.h"
Mirko Bonadei054f1852019-11-04 16:31:08 +010024#include "rtc_base/system/rtc_export_template.h"
hbos74e1a4f2016-09-15 23:33:01 -070025
26namespace webrtc {
27
28class 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// }
Mirko Bonadei276827c2018-10-16 14:13:50 +020054class RTC_EXPORT RTCStats {
hbos74e1a4f2016-09-15 23:33:01 -070055 public:
56 RTCStats(const std::string& id, int64_t timestamp_us)
57 : id_(id), timestamp_us_(timestamp_us) {}
58 RTCStats(std::string&& id, int64_t timestamp_us)
59 : id_(std::move(id)), timestamp_us_(timestamp_us) {}
60 virtual ~RTCStats() {}
61
62 virtual std::unique_ptr<RTCStats> copy() const = 0;
63
64 const std::string& id() const { return id_; }
65 // Time relative to the UNIX epoch (Jan 1, 1970, UTC), in microseconds.
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;
hbos67c8bc42016-10-25 04:31:23 -070069 // 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.
hbos74e1a4f2016-09-15 23:33:01 -070072 std::vector<const RTCStatsMemberInterface*> Members() const;
hbos67c8bc42016-10-25 04:31:23 -070073 // Checks if the two stats objects are of the same type and have the same
hbos0583b282016-11-30 01:50:14 -080074 // member values. Timestamps are not compared. These operators are exposed for
75 // testing.
hbos67c8bc42016-10-25 04:31:23 -070076 bool operator==(const RTCStats& other) const;
77 bool operator!=(const RTCStats& other) const;
hbos74e1a4f2016-09-15 23:33:01 -070078
ehmaldonado35a872c2017-07-28 07:29:12 -070079 // Creates a JSON readable string representation of the stats
80 // object, listing all of its members (names and values).
81 std::string ToJson() const;
hbos74e1a4f2016-09-15 23:33:01 -070082
83 // Downcasts the stats object to an |RTCStats| subclass |T|. DCHECKs that the
84 // object is of type |T|.
Yves Gerey665174f2018-06-19 15:03:05 +020085 template <typename T>
hbos74e1a4f2016-09-15 23:33:01 -070086 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*>
Yves Gerey665174f2018-06-19 15:03:05 +020097 MembersOfThisObjectAndAncestors(size_t additional_capacity) const;
hbos74e1a4f2016-09-15 23:33:01 -070098
99 std::string const id_;
100 int64_t timestamp_us_;
101};
102
hbosfc5e0502016-10-06 02:06:10 -0700103// 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).
hbos74e1a4f2016-09-15 23:33:01 -0700106//
hbosfc5e0502016-10-06 02:06:10 -0700107// 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
hbos74e1a4f2016-09-15 23:33:01 -0700109// |MembersOfThisObjectAndAncestors|. The |...| argument is a list of addresses
hbosfc5e0502016-10-06 02:06:10 -0700110// to each member defined in the implementing class. The list must have at least
111// one member.
hbos74e1a4f2016-09-15 23:33:01 -0700112//
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:
hbosfc5e0502016-10-06 02:06:10 -0700125// WEBRTC_RTCSTATS_DECL();
hbos74e1a4f2016-09-15 23:33:01 -0700126//
hbosfc5e0502016-10-06 02:06:10 -0700127// RTCFooStats(const std::string& id, int64_t timestamp_us);
hbos74e1a4f2016-09-15 23:33:01 -0700128//
129// RTCStatsMember<int32_t> foo;
130// RTCStatsMember<int32_t> bar;
131// };
132//
133// rtcfoostats.cc:
hbosfc5e0502016-10-06 02:06:10 -0700134// WEBRTC_RTCSTATS_IMPL(RTCFooStats, RTCStats, "foo-stats"
135// &foo,
136// &bar);
hbos74e1a4f2016-09-15 23:33:01 -0700137//
hbosfc5e0502016-10-06 02:06:10 -0700138// RTCFooStats::RTCFooStats(const std::string& id, int64_t timestamp_us)
139// : RTCStats(id, timestamp_us),
140// foo("foo"),
141// bar("bar") {
142// }
143//
Yves Gerey665174f2018-06-19 15:03:05 +0200144#define WEBRTC_RTCSTATS_DECL() \
Yves Gerey665174f2018-06-19 15:03:05 +0200145 protected: \
146 std::vector<const webrtc::RTCStatsMemberInterface*> \
147 MembersOfThisObjectAndAncestors(size_t local_var_additional_capacity) \
148 const override; \
149 \
Nico Weber22f99252019-02-20 10:13:16 -0500150 public: \
151 static const char kType[]; \
152 \
153 std::unique_ptr<webrtc::RTCStats> copy() const override; \
154 const char* type() const override
hbosfc5e0502016-10-06 02:06:10 -0700155
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 \
Yves Gerey665174f2018-06-19 15:03:05 +0200163 const char* this_class::type() const { return this_class::kType; } \
hbosfc5e0502016-10-06 02:06:10 -0700164 \
165 std::vector<const webrtc::RTCStatsMemberInterface*> \
166 this_class::MembersOfThisObjectAndAncestors( \
167 size_t local_var_additional_capacity) const { \
hbos74e1a4f2016-09-15 23:33:01 -0700168 const webrtc::RTCStatsMemberInterface* local_var_members[] = { \
Yves Gerey665174f2018-06-19 15:03:05 +0200169 __VA_ARGS__}; \
hbos74e1a4f2016-09-15 23:33:01 -0700170 size_t local_var_members_count = \
171 sizeof(local_var_members) / sizeof(local_var_members[0]); \
Yves Gerey665174f2018-06-19 15:03:05 +0200172 std::vector<const webrtc::RTCStatsMemberInterface*> \
173 local_var_members_vec = parent_class::MembersOfThisObjectAndAncestors( \
hbos74e1a4f2016-09-15 23:33:01 -0700174 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; \
hbosfc5e0502016-10-06 02:06:10 -0700182 }
hbos74e1a4f2016-09-15 23:33:01 -0700183
Henrik Boström646fda02019-05-22 15:49:42 +0200184// 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
Jakob Ivarsson22936222019-03-22 11:29:49 +0100202// 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.
206enum class NonStandardGroupId {
Jakob Ivarssonaa023e22019-03-27 10:17:31 +0100207 // Group ID used for testing purposes only.
208 kGroupIdForTesting,
Jakob Ivarsson22936222019-03-22 11:29:49 +0100209 // 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
hbos74e1a4f2016-09-15 23:33:01 -0700217// 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|.
221class RTCStatsMemberInterface {
222 public:
223 // Member value types.
224 enum Type {
Yves Gerey665174f2018-06-19 15:03:05 +0200225 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
hbos74e1a4f2016-09-15 23:33:01 -0700232
Yves Gerey665174f2018-06-19 15:03:05 +0200233 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>
hbos74e1a4f2016-09-15 23:33:01 -0700240 };
241
242 virtual ~RTCStatsMemberInterface() {}
243
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;
248 bool is_defined() const { return is_defined_; }
Taylor Brandstettere2751742018-06-25 13:42:44 -0700249 // 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;
Jakob Ivarsson22936222019-03-22 11:29:49 +0100252 // Non-standard stats members can have group IDs in order to be exposed in
253 // JavaScript through experiments. Standardized stats have no group IDs.
254 virtual std::vector<NonStandardGroupId> group_ids() const { return {}; }
hbos67c8bc42016-10-25 04:31:23 -0700255 // 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 }
hbos74e1a4f2016-09-15 23:33:01 -0700261 virtual std::string ValueToString() const = 0;
ehmaldonado35a872c2017-07-28 07:29:12 -0700262 // 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;
hbos74e1a4f2016-09-15 23:33:01 -0700268
Yves Gerey665174f2018-06-19 15:03:05 +0200269 template <typename T>
hbos74e1a4f2016-09-15 23:33:01 -0700270 const T& cast_to() const {
Mirko Bonadei054f1852019-11-04 16:31:08 +0100271 RTC_DCHECK_EQ(type(), T::StaticType());
hbos74e1a4f2016-09-15 23:33:01 -0700272 return static_cast<const T&>(*this);
273 }
274
275 protected:
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
Mirko Bonadei054f1852019-11-04 16:31:08 +0100283// Template implementation of |RTCStatsMemberInterface|.
284// The supported types are the ones described by
285// |RTCStatsMemberInterface::Type|.
Yves Gerey665174f2018-06-19 15:03:05 +0200286template <typename T>
Mirko Bonadei276827c2018-10-16 14:13:50 +0200287class RTC_EXPORT RTCStatsMember : public RTCStatsMemberInterface {
hbos74e1a4f2016-09-15 23:33:01 -0700288 public:
hbos74e1a4f2016-09-15 23:33:01 -0700289 explicit RTCStatsMember(const char* name)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700290 : RTCStatsMemberInterface(name, /*is_defined=*/false), value_() {}
hbos74e1a4f2016-09-15 23:33:01 -0700291 RTCStatsMember(const char* name, const T& value)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700292 : RTCStatsMemberInterface(name, /*is_defined=*/true), value_(value) {}
hbos74e1a4f2016-09-15 23:33:01 -0700293 RTCStatsMember(const char* name, T&& value)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700294 : RTCStatsMemberInterface(name, /*is_defined=*/true),
295 value_(std::move(value)) {}
hbos74e1a4f2016-09-15 23:33:01 -0700296 explicit RTCStatsMember(const RTCStatsMember<T>& other)
297 : RTCStatsMemberInterface(other.name_, other.is_defined_),
298 value_(other.value_) {}
299 explicit RTCStatsMember(RTCStatsMember<T>&& other)
300 : RTCStatsMemberInterface(other.name_, other.is_defined_),
301 value_(std::move(other.value_)) {}
302
Mirko Bonadei054f1852019-11-04 16:31:08 +0100303 static Type StaticType();
304 Type type() const override { return StaticType(); }
hbos74e1a4f2016-09-15 23:33:01 -0700305 bool is_sequence() const override;
306 bool is_string() const override;
Taylor Brandstettere2751742018-06-25 13:42:44 -0700307 bool is_standardized() const override { return true; }
hbos67c8bc42016-10-25 04:31:23 -0700308 bool operator==(const RTCStatsMemberInterface& other) const override {
Taylor Brandstettere2751742018-06-25 13:42:44 -0700309 if (type() != other.type() || is_standardized() != other.is_standardized())
hbos67c8bc42016-10-25 04:31:23 -0700310 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();
hbos28747962016-11-21 09:17:41 -0800315 if (!other.is_defined())
316 return false;
hbos67c8bc42016-10-25 04:31:23 -0700317 return value_ == other_t.value_;
318 }
hbos74e1a4f2016-09-15 23:33:01 -0700319 std::string ValueToString() const override;
ehmaldonado35a872c2017-07-28 07:29:12 -0700320 std::string ValueToJson() const override;
hbos74e1a4f2016-09-15 23:33:01 -0700321
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 }
hbos74e1a4f2016-09-15 23:33:01 -0700333
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
Mirko Bonadei054f1852019-11-04 16:31:08 +0100358#define WEBRTC_DECLARE_RTCSTATSMEMBER(T) \
359 template <> \
360 RTCStatsMemberInterface::Type RTCStatsMember<T>::StaticType(); \
361 template <> \
362 bool RTCStatsMember<T>::is_sequence() const; \
363 template <> \
364 bool RTCStatsMember<T>::is_string() const; \
365 template <> \
366 std::string RTCStatsMember<T>::ValueToString() const; \
367 template <> \
368 std::string RTCStatsMember<T>::ValueToJson() const; \
369 extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) \
370 RTCStatsMember<T>
371
372WEBRTC_DECLARE_RTCSTATSMEMBER(bool);
373WEBRTC_DECLARE_RTCSTATSMEMBER(int32_t);
374WEBRTC_DECLARE_RTCSTATSMEMBER(uint32_t);
375WEBRTC_DECLARE_RTCSTATSMEMBER(int64_t);
376WEBRTC_DECLARE_RTCSTATSMEMBER(uint64_t);
377WEBRTC_DECLARE_RTCSTATSMEMBER(double);
378WEBRTC_DECLARE_RTCSTATSMEMBER(std::string);
379WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<bool>);
380WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int32_t>);
381WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint32_t>);
382WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<int64_t>);
383WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<uint64_t>);
384WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<double>);
385WEBRTC_DECLARE_RTCSTATSMEMBER(std::vector<std::string>);
386
Taylor Brandstettere2751742018-06-25 13:42:44 -0700387// Using inheritance just so that it's obvious from the member's declaration
388// whether it's standardized or not.
389template <typename T>
390class RTCNonStandardStatsMember : public RTCStatsMember<T> {
391 public:
392 explicit RTCNonStandardStatsMember(const char* name)
393 : RTCStatsMember<T>(name) {}
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100394 RTCNonStandardStatsMember(const char* name,
395 std::initializer_list<NonStandardGroupId> group_ids)
396 : RTCStatsMember<T>(name), group_ids_(group_ids) {}
Taylor Brandstettere2751742018-06-25 13:42:44 -0700397 RTCNonStandardStatsMember(const char* name, const T& value)
398 : RTCStatsMember<T>(name, value) {}
399 RTCNonStandardStatsMember(const char* name, T&& value)
400 : RTCStatsMember<T>(name, std::move(value)) {}
401 explicit RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T>& other)
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100402 : RTCStatsMember<T>(other), group_ids_(other.group_ids_) {}
Taylor Brandstettere2751742018-06-25 13:42:44 -0700403 explicit RTCNonStandardStatsMember(RTCNonStandardStatsMember<T>&& other)
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100404 : group_ids_(std::move(other.group_ids_)),
405 RTCStatsMember<T>(std::move(other)) {}
Taylor Brandstettere2751742018-06-25 13:42:44 -0700406
407 bool is_standardized() const override { return false; }
Ruslan Burakov8af88962018-11-22 17:21:10 +0100408
Jakob Ivarsson22936222019-03-22 11:29:49 +0100409 std::vector<NonStandardGroupId> group_ids() const override {
410 return group_ids_;
411 }
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100412
Ruslan Burakov8af88962018-11-22 17:21:10 +0100413 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 }
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100417
418 private:
419 std::vector<NonStandardGroupId> group_ids_;
Taylor Brandstettere2751742018-06-25 13:42:44 -0700420};
hbos74e1a4f2016-09-15 23:33:01 -0700421} // namespace webrtc
422
Steve Anton10542f22019-01-11 09:11:00 -0800423#endif // API_STATS_RTC_STATS_H_