blob: bb23490ce43f354513d30cdf67a66273433ba69f [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>
hbos74e1a4f2016-09-15 23:33:01 -070016#include <memory>
17#include <string>
18#include <utility>
19#include <vector>
20
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/checks.h"
Mirko Bonadei276827c2018-10-16 14:13:50 +020022#include "rtc_base/system/rtc_export.h"
hbos74e1a4f2016-09-15 23:33:01 -070023
24namespace webrtc {
25
26class RTCStatsMemberInterface;
27
28// Abstract base class for RTCStats-derived dictionaries, see
29// https://w3c.github.io/webrtc-stats/.
30//
31// All derived classes must have the following static variable defined:
32// static const char kType[];
33// It is used as a unique class identifier and a string representation of the
34// class type, see https://w3c.github.io/webrtc-stats/#rtcstatstype-str*.
35// Use the |WEBRTC_RTCSTATS_IMPL| macro when implementing subclasses, see macro
36// for details.
37//
38// Derived classes list their dictionary members, RTCStatsMember<T>, as public
39// fields, allowing the following:
40//
41// RTCFooStats foo("fooId", GetCurrentTime());
42// foo.bar = 42;
43// foo.baz = std::vector<std::string>();
44// foo.baz->push_back("hello world");
45// uint32_t x = *foo.bar;
46//
47// Pointers to all the members are available with |Members|, allowing iteration:
48//
49// for (const RTCStatsMemberInterface* member : foo.Members()) {
50// printf("%s = %s\n", member->name(), member->ValueToString().c_str());
51// }
Mirko Bonadei276827c2018-10-16 14:13:50 +020052class RTC_EXPORT RTCStats {
hbos74e1a4f2016-09-15 23:33:01 -070053 public:
54 RTCStats(const std::string& id, int64_t timestamp_us)
55 : id_(id), timestamp_us_(timestamp_us) {}
56 RTCStats(std::string&& id, int64_t timestamp_us)
57 : id_(std::move(id)), timestamp_us_(timestamp_us) {}
58 virtual ~RTCStats() {}
59
60 virtual std::unique_ptr<RTCStats> copy() const = 0;
61
62 const std::string& id() const { return id_; }
63 // Time relative to the UNIX epoch (Jan 1, 1970, UTC), in microseconds.
64 int64_t timestamp_us() const { return timestamp_us_; }
65 // Returns the static member variable |kType| of the implementing class.
66 virtual const char* type() const = 0;
hbos67c8bc42016-10-25 04:31:23 -070067 // Returns a vector of pointers to all the |RTCStatsMemberInterface| members
68 // of this class. This allows for iteration of members. For a given class,
69 // |Members| always returns the same members in the same order.
hbos74e1a4f2016-09-15 23:33:01 -070070 std::vector<const RTCStatsMemberInterface*> Members() const;
hbos67c8bc42016-10-25 04:31:23 -070071 // Checks if the two stats objects are of the same type and have the same
hbos0583b282016-11-30 01:50:14 -080072 // member values. Timestamps are not compared. These operators are exposed for
73 // testing.
hbos67c8bc42016-10-25 04:31:23 -070074 bool operator==(const RTCStats& other) const;
75 bool operator!=(const RTCStats& other) const;
hbos74e1a4f2016-09-15 23:33:01 -070076
ehmaldonado35a872c2017-07-28 07:29:12 -070077 // Creates a JSON readable string representation of the stats
78 // object, listing all of its members (names and values).
79 std::string ToJson() const;
hbos74e1a4f2016-09-15 23:33:01 -070080
81 // Downcasts the stats object to an |RTCStats| subclass |T|. DCHECKs that the
82 // object is of type |T|.
Yves Gerey665174f2018-06-19 15:03:05 +020083 template <typename T>
hbos74e1a4f2016-09-15 23:33:01 -070084 const T& cast_to() const {
85 RTC_DCHECK_EQ(type(), T::kType);
86 return static_cast<const T&>(*this);
87 }
88
89 protected:
90 // Gets a vector of all members of this |RTCStats| object, including members
91 // derived from parent classes. |additional_capacity| is how many more members
92 // shall be reserved in the vector (so that subclasses can allocate a vector
93 // with room for both parent and child members without it having to resize).
94 virtual std::vector<const RTCStatsMemberInterface*>
Yves Gerey665174f2018-06-19 15:03:05 +020095 MembersOfThisObjectAndAncestors(size_t additional_capacity) const;
hbos74e1a4f2016-09-15 23:33:01 -070096
97 std::string const id_;
98 int64_t timestamp_us_;
99};
100
hbosfc5e0502016-10-06 02:06:10 -0700101// All |RTCStats| classes should use these macros.
102// |WEBRTC_RTCSTATS_DECL| is placed in a public section of the class definition.
103// |WEBRTC_RTCSTATS_IMPL| is placed outside the class definition (in a .cc).
hbos74e1a4f2016-09-15 23:33:01 -0700104//
hbosfc5e0502016-10-06 02:06:10 -0700105// These macros declare (in _DECL) and define (in _IMPL) the static |kType| and
106// overrides methods as required by subclasses of |RTCStats|: |copy|, |type| and
hbos74e1a4f2016-09-15 23:33:01 -0700107// |MembersOfThisObjectAndAncestors|. The |...| argument is a list of addresses
hbosfc5e0502016-10-06 02:06:10 -0700108// to each member defined in the implementing class. The list must have at least
109// one member.
hbos74e1a4f2016-09-15 23:33:01 -0700110//
111// (Since class names need to be known to implement these methods this cannot be
112// part of the base |RTCStats|. While these methods could be implemented using
113// templates, that would only work for immediate subclasses. Subclasses of
114// subclasses also have to override these methods, resulting in boilerplate
115// code. Using a macro avoids this and works for any |RTCStats| class, including
116// grandchildren.)
117//
118// Sample usage:
119//
120// rtcfoostats.h:
121// class RTCFooStats : public RTCStats {
122// public:
hbosfc5e0502016-10-06 02:06:10 -0700123// WEBRTC_RTCSTATS_DECL();
hbos74e1a4f2016-09-15 23:33:01 -0700124//
hbosfc5e0502016-10-06 02:06:10 -0700125// RTCFooStats(const std::string& id, int64_t timestamp_us);
hbos74e1a4f2016-09-15 23:33:01 -0700126//
127// RTCStatsMember<int32_t> foo;
128// RTCStatsMember<int32_t> bar;
129// };
130//
131// rtcfoostats.cc:
hbosfc5e0502016-10-06 02:06:10 -0700132// WEBRTC_RTCSTATS_IMPL(RTCFooStats, RTCStats, "foo-stats"
133// &foo,
134// &bar);
hbos74e1a4f2016-09-15 23:33:01 -0700135//
hbosfc5e0502016-10-06 02:06:10 -0700136// RTCFooStats::RTCFooStats(const std::string& id, int64_t timestamp_us)
137// : RTCStats(id, timestamp_us),
138// foo("foo"),
139// bar("bar") {
140// }
141//
Yves Gerey665174f2018-06-19 15:03:05 +0200142#define WEBRTC_RTCSTATS_DECL() \
Yves Gerey665174f2018-06-19 15:03:05 +0200143 protected: \
144 std::vector<const webrtc::RTCStatsMemberInterface*> \
145 MembersOfThisObjectAndAncestors(size_t local_var_additional_capacity) \
146 const override; \
147 \
Nico Weber22f99252019-02-20 10:13:16 -0500148 public: \
149 static const char kType[]; \
150 \
151 std::unique_ptr<webrtc::RTCStats> copy() const override; \
152 const char* type() const override
hbosfc5e0502016-10-06 02:06:10 -0700153
154#define WEBRTC_RTCSTATS_IMPL(this_class, parent_class, type_str, ...) \
155 const char this_class::kType[] = type_str; \
156 \
157 std::unique_ptr<webrtc::RTCStats> this_class::copy() const { \
158 return std::unique_ptr<webrtc::RTCStats>(new this_class(*this)); \
159 } \
160 \
Yves Gerey665174f2018-06-19 15:03:05 +0200161 const char* this_class::type() const { return this_class::kType; } \
hbosfc5e0502016-10-06 02:06:10 -0700162 \
163 std::vector<const webrtc::RTCStatsMemberInterface*> \
164 this_class::MembersOfThisObjectAndAncestors( \
165 size_t local_var_additional_capacity) const { \
hbos74e1a4f2016-09-15 23:33:01 -0700166 const webrtc::RTCStatsMemberInterface* local_var_members[] = { \
Yves Gerey665174f2018-06-19 15:03:05 +0200167 __VA_ARGS__}; \
hbos74e1a4f2016-09-15 23:33:01 -0700168 size_t local_var_members_count = \
169 sizeof(local_var_members) / sizeof(local_var_members[0]); \
Yves Gerey665174f2018-06-19 15:03:05 +0200170 std::vector<const webrtc::RTCStatsMemberInterface*> \
171 local_var_members_vec = parent_class::MembersOfThisObjectAndAncestors( \
hbos74e1a4f2016-09-15 23:33:01 -0700172 local_var_members_count + local_var_additional_capacity); \
173 RTC_DCHECK_GE( \
174 local_var_members_vec.capacity() - local_var_members_vec.size(), \
175 local_var_members_count + local_var_additional_capacity); \
176 local_var_members_vec.insert(local_var_members_vec.end(), \
177 &local_var_members[0], \
178 &local_var_members[local_var_members_count]); \
179 return local_var_members_vec; \
hbosfc5e0502016-10-06 02:06:10 -0700180 }
hbos74e1a4f2016-09-15 23:33:01 -0700181
Jakob Ivarsson22936222019-03-22 11:29:49 +0100182// Non-standard stats members can be exposed to the JavaScript API in Chrome
183// e.g. through origin trials. The group ID can be used by the blink layer to
184// determine if a stats member should be exposed or not. Multiple non-standard
185// stats members can share the same group ID so that they are exposed together.
186enum class NonStandardGroupId {
Jakob Ivarssonaa023e22019-03-27 10:17:31 +0100187 // Group ID used for testing purposes only.
188 kGroupIdForTesting,
Jakob Ivarsson22936222019-03-22 11:29:49 +0100189 // I2E:
190 // https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/hE2B1iItPDk
191 kRtcAudioJitterBufferMaxPackets,
192 // I2E:
193 // https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/YbhMyqLXXXo
194 kRtcStatsRelativePacketArrivalDelay,
195};
196
hbos74e1a4f2016-09-15 23:33:01 -0700197// Interface for |RTCStats| members, which have a name and a value of a type
198// defined in a subclass. Only the types listed in |Type| are supported, these
199// are implemented by |RTCStatsMember<T>|. The value of a member may be
200// undefined, the value can only be read if |is_defined|.
201class RTCStatsMemberInterface {
202 public:
203 // Member value types.
204 enum Type {
Yves Gerey665174f2018-06-19 15:03:05 +0200205 kBool, // bool
206 kInt32, // int32_t
207 kUint32, // uint32_t
208 kInt64, // int64_t
209 kUint64, // uint64_t
210 kDouble, // double
211 kString, // std::string
hbos74e1a4f2016-09-15 23:33:01 -0700212
Yves Gerey665174f2018-06-19 15:03:05 +0200213 kSequenceBool, // std::vector<bool>
214 kSequenceInt32, // std::vector<int32_t>
215 kSequenceUint32, // std::vector<uint32_t>
216 kSequenceInt64, // std::vector<int64_t>
217 kSequenceUint64, // std::vector<uint64_t>
218 kSequenceDouble, // std::vector<double>
219 kSequenceString, // std::vector<std::string>
hbos74e1a4f2016-09-15 23:33:01 -0700220 };
221
222 virtual ~RTCStatsMemberInterface() {}
223
224 const char* name() const { return name_; }
225 virtual Type type() const = 0;
226 virtual bool is_sequence() const = 0;
227 virtual bool is_string() const = 0;
228 bool is_defined() const { return is_defined_; }
Taylor Brandstettere2751742018-06-25 13:42:44 -0700229 // Is this part of the stats spec? Used so that chromium can easily filter
230 // out anything unstandardized.
231 virtual bool is_standardized() const = 0;
Jakob Ivarsson22936222019-03-22 11:29:49 +0100232 // Non-standard stats members can have group IDs in order to be exposed in
233 // JavaScript through experiments. Standardized stats have no group IDs.
234 virtual std::vector<NonStandardGroupId> group_ids() const { return {}; }
hbos67c8bc42016-10-25 04:31:23 -0700235 // Type and value comparator. The names are not compared. These operators are
236 // exposed for testing.
237 virtual bool operator==(const RTCStatsMemberInterface& other) const = 0;
238 bool operator!=(const RTCStatsMemberInterface& other) const {
239 return !(*this == other);
240 }
hbos74e1a4f2016-09-15 23:33:01 -0700241 virtual std::string ValueToString() const = 0;
ehmaldonado35a872c2017-07-28 07:29:12 -0700242 // This is the same as ValueToString except for kInt64 and kUint64 types,
243 // where the value is represented as a double instead of as an integer.
244 // Since JSON stores numbers as floating point numbers, very large integers
245 // cannot be accurately represented, so we prefer to display them as doubles
246 // instead.
247 virtual std::string ValueToJson() const = 0;
hbos74e1a4f2016-09-15 23:33:01 -0700248
Yves Gerey665174f2018-06-19 15:03:05 +0200249 template <typename T>
hbos74e1a4f2016-09-15 23:33:01 -0700250 const T& cast_to() const {
251 RTC_DCHECK_EQ(type(), T::kType);
252 return static_cast<const T&>(*this);
253 }
254
255 protected:
256 RTCStatsMemberInterface(const char* name, bool is_defined)
257 : name_(name), is_defined_(is_defined) {}
258
259 const char* const name_;
260 bool is_defined_;
261};
262
263// Template implementation of |RTCStatsMemberInterface|. Every possible |T| is
264// specialized in rtcstats.cc, using a different |T| results in a linker error
265// (undefined reference to |kType|). The supported types are the ones described
266// by |RTCStatsMemberInterface::Type|.
Yves Gerey665174f2018-06-19 15:03:05 +0200267template <typename T>
Mirko Bonadei276827c2018-10-16 14:13:50 +0200268class RTC_EXPORT RTCStatsMember : public RTCStatsMemberInterface {
hbos74e1a4f2016-09-15 23:33:01 -0700269 public:
270 static const Type kType;
271
272 explicit RTCStatsMember(const char* name)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700273 : RTCStatsMemberInterface(name, /*is_defined=*/false), value_() {}
hbos74e1a4f2016-09-15 23:33:01 -0700274 RTCStatsMember(const char* name, const T& value)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700275 : RTCStatsMemberInterface(name, /*is_defined=*/true), value_(value) {}
hbos74e1a4f2016-09-15 23:33:01 -0700276 RTCStatsMember(const char* name, T&& value)
Taylor Brandstettere2751742018-06-25 13:42:44 -0700277 : RTCStatsMemberInterface(name, /*is_defined=*/true),
278 value_(std::move(value)) {}
hbos74e1a4f2016-09-15 23:33:01 -0700279 explicit RTCStatsMember(const RTCStatsMember<T>& other)
280 : RTCStatsMemberInterface(other.name_, other.is_defined_),
281 value_(other.value_) {}
282 explicit RTCStatsMember(RTCStatsMember<T>&& other)
283 : RTCStatsMemberInterface(other.name_, other.is_defined_),
284 value_(std::move(other.value_)) {}
285
286 Type type() const override { return kType; }
287 bool is_sequence() const override;
288 bool is_string() const override;
Taylor Brandstettere2751742018-06-25 13:42:44 -0700289 bool is_standardized() const override { return true; }
hbos67c8bc42016-10-25 04:31:23 -0700290 bool operator==(const RTCStatsMemberInterface& other) const override {
Taylor Brandstettere2751742018-06-25 13:42:44 -0700291 if (type() != other.type() || is_standardized() != other.is_standardized())
hbos67c8bc42016-10-25 04:31:23 -0700292 return false;
293 const RTCStatsMember<T>& other_t =
294 static_cast<const RTCStatsMember<T>&>(other);
295 if (!is_defined_)
296 return !other_t.is_defined();
hbos28747962016-11-21 09:17:41 -0800297 if (!other.is_defined())
298 return false;
hbos67c8bc42016-10-25 04:31:23 -0700299 return value_ == other_t.value_;
300 }
hbos74e1a4f2016-09-15 23:33:01 -0700301 std::string ValueToString() const override;
ehmaldonado35a872c2017-07-28 07:29:12 -0700302 std::string ValueToJson() const override;
hbos74e1a4f2016-09-15 23:33:01 -0700303
304 // Assignment operators.
305 T& operator=(const T& value) {
306 value_ = value;
307 is_defined_ = true;
308 return value_;
309 }
310 T& operator=(const T&& value) {
311 value_ = std::move(value);
312 is_defined_ = true;
313 return value_;
314 }
hbos74e1a4f2016-09-15 23:33:01 -0700315
316 // Value getters.
317 T& operator*() {
318 RTC_DCHECK(is_defined_);
319 return value_;
320 }
321 const T& operator*() const {
322 RTC_DCHECK(is_defined_);
323 return value_;
324 }
325
326 // Value getters, arrow operator.
327 T* operator->() {
328 RTC_DCHECK(is_defined_);
329 return &value_;
330 }
331 const T* operator->() const {
332 RTC_DCHECK(is_defined_);
333 return &value_;
334 }
335
336 private:
337 T value_;
338};
339
Taylor Brandstettere2751742018-06-25 13:42:44 -0700340// Using inheritance just so that it's obvious from the member's declaration
341// whether it's standardized or not.
342template <typename T>
343class RTCNonStandardStatsMember : public RTCStatsMember<T> {
344 public:
345 explicit RTCNonStandardStatsMember(const char* name)
346 : RTCStatsMember<T>(name) {}
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100347 RTCNonStandardStatsMember(const char* name,
348 std::initializer_list<NonStandardGroupId> group_ids)
349 : RTCStatsMember<T>(name), group_ids_(group_ids) {}
Taylor Brandstettere2751742018-06-25 13:42:44 -0700350 RTCNonStandardStatsMember(const char* name, const T& value)
351 : RTCStatsMember<T>(name, value) {}
352 RTCNonStandardStatsMember(const char* name, T&& value)
353 : RTCStatsMember<T>(name, std::move(value)) {}
354 explicit RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T>& other)
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100355 : RTCStatsMember<T>(other), group_ids_(other.group_ids_) {}
Taylor Brandstettere2751742018-06-25 13:42:44 -0700356 explicit RTCNonStandardStatsMember(RTCNonStandardStatsMember<T>&& other)
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100357 : group_ids_(std::move(other.group_ids_)),
358 RTCStatsMember<T>(std::move(other)) {}
Taylor Brandstettere2751742018-06-25 13:42:44 -0700359
360 bool is_standardized() const override { return false; }
Ruslan Burakov8af88962018-11-22 17:21:10 +0100361
Jakob Ivarsson22936222019-03-22 11:29:49 +0100362 std::vector<NonStandardGroupId> group_ids() const override {
363 return group_ids_;
364 }
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100365
Ruslan Burakov8af88962018-11-22 17:21:10 +0100366 T& operator=(const T& value) { return RTCStatsMember<T>::operator=(value); }
367 T& operator=(const T&& value) {
368 return RTCStatsMember<T>::operator=(std::move(value));
369 }
Jakob Ivarsson758d9462019-03-19 15:38:49 +0100370
371 private:
372 std::vector<NonStandardGroupId> group_ids_;
Taylor Brandstettere2751742018-06-25 13:42:44 -0700373};
hbos74e1a4f2016-09-15 23:33:01 -0700374} // namespace webrtc
375
Steve Anton10542f22019-01-11 09:11:00 -0800376#endif // API_STATS_RTC_STATS_H_