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