Adding entry point for the v2 stats API.
Bug: webrtc:10345
Change-Id: I9271376ff60f5fc6e9014b7dd9a8a5682bdbf452
Reviewed-on: https://webrtc-review.googlesource.com/c/123780
Commit-Queue: Peter Hanspers <peterhanspers@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Anders Carlsson <andersc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26801}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 7963405..5ffd964 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -887,6 +887,9 @@
"objc/api/peerconnection/RTCSessionDescription+Private.h",
"objc/api/peerconnection/RTCSessionDescription.h",
"objc/api/peerconnection/RTCSessionDescription.mm",
+ "objc/api/peerconnection/RTCStatisticsReport+Private.h",
+ "objc/api/peerconnection/RTCStatisticsReport.h",
+ "objc/api/peerconnection/RTCStatisticsReport.mm",
"objc/api/peerconnection/RTCTracing.h",
"objc/api/peerconnection/RTCTracing.mm",
"objc/api/peerconnection/RTCVideoTrack+Private.h",
@@ -917,6 +920,7 @@
":videotoolbox_objc",
"../api:create_peerconnection_factory",
"../api:libjingle_peerconnection_api",
+ "../api:rtc_stats_api",
"../api:scoped_refptr",
"../api/audio_codecs:audio_codecs_api",
"../api/audio_codecs:builtin_audio_decoder_factory",
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Stats.mm b/sdk/objc/api/peerconnection/RTCPeerConnection+Stats.mm
index 72e8e5a..e035caa 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnection+Stats.mm
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Stats.mm
@@ -12,12 +12,29 @@
#import "RTCLegacyStatsReport+Private.h"
#import "RTCMediaStreamTrack+Private.h"
+#import "RTCStatisticsReport+Private.h"
#import "helpers/NSString+StdString.h"
#include "rtc_base/checks.h"
namespace webrtc {
+class StatsCollectorCallbackAdapter : public RTCStatsCollectorCallback {
+ public:
+ StatsCollectorCallbackAdapter(RTCStatisticsCompletionHandler completion_handler)
+ : completion_handler_(completion_handler) {}
+
+ void OnStatsDelivered(const rtc::scoped_refptr<const RTCStatsReport> &report) override {
+ RTC_DCHECK(completion_handler_);
+ RTCStatisticsReport *statisticsReport = [[RTCStatisticsReport alloc] initWithReport:*report];
+ completion_handler_(statisticsReport);
+ completion_handler_ = nil;
+ }
+
+ private:
+ RTCStatisticsCompletionHandler completion_handler_;
+};
+
class StatsObserverAdapter : public StatsObserver {
public:
StatsObserverAdapter(void (^completionHandler)
@@ -46,6 +63,12 @@
@implementation RTCPeerConnection (Stats)
+- (void)statisticsWithCompletionHandler:(RTCStatisticsCompletionHandler)completionHandler {
+ rtc::scoped_refptr<webrtc::StatsCollectorCallbackAdapter> collector(
+ new rtc::RefCountedObject<webrtc::StatsCollectorCallbackAdapter>(completionHandler));
+ self.nativePeerConnection->GetStats(collector);
+}
+
- (void)statsForTrack:(RTCMediaStreamTrack *)mediaStreamTrack
statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel
completionHandler:
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.h b/sdk/objc/api/peerconnection/RTCPeerConnection.h
index 393a50b..500a7ce 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnection.h
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection.h
@@ -25,6 +25,7 @@
@class RTCRtpTransceiver;
@class RTCRtpTransceiverInit;
@class RTCSessionDescription;
+@class RTCStatisticsReport;
@class RTCLegacyStatsReport;
typedef NS_ENUM(NSInteger, RTCRtpMediaType);
@@ -316,6 +317,8 @@
@end
+typedef void (^RTCStatisticsCompletionHandler)(RTCStatisticsReport *);
+
@interface RTCPeerConnection (Stats)
/** Gather stats for the given RTCMediaStreamTrack. If |mediaStreamTrack| is nil
@@ -325,6 +328,9 @@
statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel
completionHandler:(nullable void (^)(NSArray<RTCLegacyStatsReport *> *stats))completionHandler;
+/** Gather statistic through the v2 statistics API. */
+- (void)statisticsWithCompletionHandler:(RTCStatisticsCompletionHandler)completionHandler;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCStatisticsReport+Private.h b/sdk/objc/api/peerconnection/RTCStatisticsReport+Private.h
new file mode 100644
index 0000000..0220d18
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCStatisticsReport+Private.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCStatisticsReport.h"
+
+#include "api/stats/rtc_stats_report.h"
+
+@interface RTCStatisticsReport (Private)
+
+- (instancetype)initWithReport:(const webrtc::RTCStatsReport &)report;
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCStatisticsReport.h b/sdk/objc/api/peerconnection/RTCStatisticsReport.h
new file mode 100644
index 0000000..6fbd59b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCStatisticsReport.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class RTCStatistics;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** A statistics report. Encapsulates a number of RTCStatistics objects. */
+@interface RTCStatisticsReport : NSObject
+
+/** The timestamp of the report in microseconds since 1970-01-01T00:00:00Z. */
+@property(nonatomic, readonly) CFTimeInterval timestamp_us;
+
+/** RTCStatistics objects by id. */
+@property(nonatomic, readonly) NSDictionary<NSString *, RTCStatistics *> *statistics;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+/** A part of a report (a subreport) covering a certain area. */
+@interface RTCStatistics : NSObject
+
+/** The id of this subreport, e.g. "RTCMediaStreamTrack_receiver_2". */
+@property(nonatomic, readonly) NSString *id;
+
+/** The timestamp of the subreport in microseconds since 1970-01-01T00:00:00Z. */
+@property(nonatomic, readonly) CFTimeInterval timestamp_us;
+
+/** The type of the subreport, e.g. "track", "codec". */
+@property(nonatomic, readonly) NSString *type;
+
+/** The keys and values of the subreport, e.g. "totalFramesDuration = 5.551".
+ The values are either NSNumbers or NSStrings, or NSArrays encapsulating NSNumbers
+ or NSStrings. */
+@property(nonatomic, readonly) NSDictionary<NSString *, NSObject *> *values;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCStatisticsReport.mm b/sdk/objc/api/peerconnection/RTCStatisticsReport.mm
new file mode 100644
index 0000000..5269767
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCStatisticsReport.mm
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCStatisticsReport+Private.h"
+
+#include "helpers/NSString+StdString.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+/** Converts a single value to a suitable NSNumber, NSString or NSArray containing NSNumbers
+ or NSStrings.*/
+NSObject *ValueFromStatsMember(const RTCStatsMemberInterface *member) {
+ if (member->is_defined()) {
+ switch (member->type()) {
+ case RTCStatsMemberInterface::kBool:
+ return [NSNumber numberWithBool:*member->cast_to<RTCStatsMember<bool>>()];
+ case RTCStatsMemberInterface::kInt32:
+ return [NSNumber numberWithInt:*member->cast_to<RTCStatsMember<int32_t>>()];
+ case RTCStatsMemberInterface::kUint32:
+ return [NSNumber numberWithUnsignedInt:*member->cast_to<RTCStatsMember<uint32_t>>()];
+ case RTCStatsMemberInterface::kInt64:
+ return [NSNumber numberWithLong:*member->cast_to<RTCStatsMember<int64_t>>()];
+ case RTCStatsMemberInterface::kUint64:
+ return [NSNumber numberWithUnsignedLong:*member->cast_to<RTCStatsMember<uint64_t>>()];
+ case RTCStatsMemberInterface::kDouble:
+ return [NSNumber numberWithDouble:*member->cast_to<RTCStatsMember<double>>()];
+ case RTCStatsMemberInterface::kString:
+ return [NSString stringForStdString:*member->cast_to<RTCStatsMember<std::string>>()];
+ case RTCStatsMemberInterface::kSequenceBool: {
+ std::vector<bool> sequence = *member->cast_to<RTCStatsMember<std::vector<bool>>>();
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:sequence.size()];
+ for (const auto &item : sequence) {
+ [array addObject:[NSNumber numberWithBool:item]];
+ }
+ return [array copy];
+ }
+ case RTCStatsMemberInterface::kSequenceInt32: {
+ std::vector<int32_t> sequence = *member->cast_to<RTCStatsMember<std::vector<int32_t>>>();
+ NSMutableArray<NSNumber *> *array = [NSMutableArray arrayWithCapacity:sequence.size()];
+ for (const auto &item : sequence) {
+ [array addObject:[NSNumber numberWithInt:item]];
+ }
+ return [array copy];
+ }
+ case RTCStatsMemberInterface::kSequenceUint32: {
+ std::vector<uint32_t> sequence = *member->cast_to<RTCStatsMember<std::vector<uint32_t>>>();
+ NSMutableArray<NSNumber *> *array = [NSMutableArray arrayWithCapacity:sequence.size()];
+ for (const auto &item : sequence) {
+ [array addObject:[NSNumber numberWithUnsignedInt:item]];
+ }
+ return [array copy];
+ }
+ case RTCStatsMemberInterface::kSequenceInt64: {
+ std::vector<int64_t> sequence = *member->cast_to<RTCStatsMember<std::vector<int64_t>>>();
+ NSMutableArray<NSNumber *> *array = [NSMutableArray arrayWithCapacity:sequence.size()];
+ for (const auto &item : sequence) {
+ [array addObject:[NSNumber numberWithLong:item]];
+ }
+ return [array copy];
+ }
+ case RTCStatsMemberInterface::kSequenceUint64: {
+ std::vector<uint64_t> sequence = *member->cast_to<RTCStatsMember<std::vector<uint64_t>>>();
+ NSMutableArray<NSNumber *> *array = [NSMutableArray arrayWithCapacity:sequence.size()];
+ for (const auto &item : sequence) {
+ [array addObject:[NSNumber numberWithUnsignedLong:item]];
+ }
+ return [array copy];
+ }
+ case RTCStatsMemberInterface::kSequenceDouble: {
+ std::vector<double> sequence = *member->cast_to<RTCStatsMember<std::vector<double>>>();
+ NSMutableArray<NSNumber *> *array = [NSMutableArray arrayWithCapacity:sequence.size()];
+ for (const auto &item : sequence) {
+ [array addObject:[NSNumber numberWithDouble:item]];
+ }
+ return [array copy];
+ }
+ case RTCStatsMemberInterface::kSequenceString: {
+ std::vector<std::string> sequence =
+ *member->cast_to<RTCStatsMember<std::vector<std::string>>>();
+ NSMutableArray<NSString *> *array = [NSMutableArray arrayWithCapacity:sequence.size()];
+ for (const auto &item : sequence) {
+ [array addObject:[NSString stringForStdString:item]];
+ }
+ return [array copy];
+ }
+ default:
+ RTC_NOTREACHED();
+ }
+ }
+
+ return nil;
+}
+} // namespace webrtc
+
+@implementation RTCStatistics
+
+@synthesize id = _id;
+@synthesize timestamp_us = _timestamp_us;
+@synthesize type = _type;
+@synthesize values = _values;
+
+- (instancetype)initWithStatistics:(const webrtc::RTCStats &)statistics {
+ if (self = [super init]) {
+ _id = [NSString stringForStdString:statistics.id()];
+ _timestamp_us = statistics.timestamp_us();
+ _type = [NSString stringWithCString:statistics.type() encoding:NSUTF8StringEncoding];
+
+ NSMutableDictionary<NSString *, NSObject *> *values = [NSMutableDictionary dictionary];
+ for (const webrtc::RTCStatsMemberInterface *member : statistics.Members()) {
+ NSObject *value = ValueFromStatsMember(member);
+ if (value) {
+ NSString *name = [NSString stringWithCString:member->name() encoding:NSUTF8StringEncoding];
+ RTC_DCHECK(name.length > 0);
+ RTC_DCHECK(!values[name]);
+ values[name] = value;
+ }
+ }
+ _values = [values copy];
+ }
+
+ return self;
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"id = %@, type = %@, timestamp = %.0f, values = %@",
+ self.id,
+ self.type,
+ self.timestamp_us,
+ self.values];
+}
+
+@end
+
+@implementation RTCStatisticsReport
+
+@synthesize timestamp_us = _timestamp_us;
+@synthesize statistics = _statistics;
+
+- (NSString *)description {
+ return [NSString
+ stringWithFormat:@"timestamp = %.0f, statistics = %@", self.timestamp_us, self.statistics];
+}
+
+@end
+
+@implementation RTCStatisticsReport (Private)
+
+- (instancetype)initWithReport:(const webrtc::RTCStatsReport &)report {
+ if (self = [super init]) {
+ _timestamp_us = report.timestamp_us();
+
+ NSMutableDictionary *statisticsById =
+ [NSMutableDictionary dictionaryWithCapacity:report.size()];
+ for (const auto &stat : report) {
+ RTCStatistics *statistics = [[RTCStatistics alloc] initWithStatistics:stat];
+ statisticsById[statistics.id] = statistics;
+ }
+ _statistics = [statisticsById copy];
+ }
+
+ return self;
+}
+
+@end