diff --git a/examples/BUILD.gn b/examples/BUILD.gn index 704afc5467..2f1277c744 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn @@ -253,8 +253,6 @@ if (is_ios || (is_mac && target_cpu != "x86")) { "objc/AppRTCMobile/ARDAppClient.m", "objc/AppRTCMobile/ARDAppEngineClient.h", "objc/AppRTCMobile/ARDAppEngineClient.m", - "objc/AppRTCMobile/ARDBitrateTracker.h", - "objc/AppRTCMobile/ARDBitrateTracker.m", "objc/AppRTCMobile/ARDCaptureController.h", "objc/AppRTCMobile/ARDCaptureController.m", "objc/AppRTCMobile/ARDExternalSampleCapturer.h", diff --git a/examples/objc/AppRTCMobile/ARDAppClient.h b/examples/objc/AppRTCMobile/ARDAppClient.h index 1fed247060..8e124ed925 100644 --- a/examples/objc/AppRTCMobile/ARDAppClient.h +++ b/examples/objc/AppRTCMobile/ARDAppClient.h @@ -48,7 +48,7 @@ typedef NS_ENUM(NSInteger, ARDAppClientState) { - (void)appClient:(ARDAppClient *)client didError:(NSError *)error; -- (void)appClient:(ARDAppClient *)client didGetStats:(NSArray *)stats; +- (void)appClient:(ARDAppClient *)client didGetStats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats; @optional - (void)appClient:(ARDAppClient *)client diff --git a/examples/objc/AppRTCMobile/ARDAppClient.m b/examples/objc/AppRTCMobile/ARDAppClient.m index ccd5bb0662..fa6a960a54 100644 --- a/examples/objc/AppRTCMobile/ARDAppClient.m +++ b/examples/objc/AppRTCMobile/ARDAppClient.m @@ -191,9 +191,8 @@ static int const kKbpsMultiplier = 1000; repeats:YES timerHandler:^{ ARDAppClient *strongSelf = weakSelf; - [strongSelf.peerConnection statsForTrack:nil - statsOutputLevel:RTCStatsOutputLevelDebug - completionHandler:^(NSArray *stats) { + [strongSelf.peerConnection statisticsWithCompletionHandler:^( + RTC_OBJC_TYPE(RTCStatisticsReport) * stats) { dispatch_async(dispatch_get_main_queue(), ^{ ARDAppClient *strongSelf = weakSelf; [strongSelf.delegate appClient:strongSelf didGetStats:stats]; diff --git a/examples/objc/AppRTCMobile/ARDBitrateTracker.h b/examples/objc/AppRTCMobile/ARDBitrateTracker.h deleted file mode 100644 index 81ac4b4bd5..0000000000 --- a/examples/objc/AppRTCMobile/ARDBitrateTracker.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 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 - -/** Class used to estimate bitrate based on byte count. It is expected that - * byte count is monotonocially increasing. This class tracks the times that - * byte count is updated, and measures the bitrate based on the byte difference - * over the interval between updates. - */ -@interface ARDBitrateTracker : NSObject - -/** The bitrate in bits per second. */ -@property(nonatomic, readonly) double bitrate; -/** The bitrate as a formatted string in bps, Kbps or Mbps. */ -@property(nonatomic, readonly) NSString *bitrateString; - -/** Converts the bitrate to a readable format in bps, Kbps or Mbps. */ -+ (NSString *)bitrateStringForBitrate:(double)bitrate; -/** Updates the tracked bitrate with the new byte count. */ -- (void)updateBitrateWithCurrentByteCount:(NSInteger)byteCount; - -@end diff --git a/examples/objc/AppRTCMobile/ARDBitrateTracker.m b/examples/objc/AppRTCMobile/ARDBitrateTracker.m deleted file mode 100644 index 8158229187..0000000000 --- a/examples/objc/AppRTCMobile/ARDBitrateTracker.m +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 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 "ARDBitrateTracker.h" - -#import - -@implementation ARDBitrateTracker { - CFTimeInterval _prevTime; - NSInteger _prevByteCount; -} - -@synthesize bitrate = _bitrate; - -+ (NSString *)bitrateStringForBitrate:(double)bitrate { - if (bitrate > 1e6) { - return [NSString stringWithFormat:@"%.2fMbps", bitrate * 1e-6]; - } else if (bitrate > 1e3) { - return [NSString stringWithFormat:@"%.0fKbps", bitrate * 1e-3]; - } else { - return [NSString stringWithFormat:@"%.0fbps", bitrate]; - } -} - -- (NSString *)bitrateString { - return [[self class] bitrateStringForBitrate:_bitrate]; -} - -- (void)updateBitrateWithCurrentByteCount:(NSInteger)byteCount { - CFTimeInterval currentTime = CACurrentMediaTime(); - if (_prevTime && (byteCount > _prevByteCount)) { - _bitrate = (byteCount - _prevByteCount) * 8 / (currentTime - _prevTime); - } - _prevByteCount = byteCount; - _prevTime = currentTime; -} - -@end diff --git a/examples/objc/AppRTCMobile/ARDStatsBuilder.h b/examples/objc/AppRTCMobile/ARDStatsBuilder.h index e8224dd707..eaffa67049 100644 --- a/examples/objc/AppRTCMobile/ARDStatsBuilder.h +++ b/examples/objc/AppRTCMobile/ARDStatsBuilder.h @@ -10,10 +10,9 @@ #import +#import "sdk/objc/api/peerconnection/RTCStatisticsReport.h" #import "sdk/objc/base/RTCMacros.h" -@class RTC_OBJC_TYPE(RTCLegacyStatsReport); - /** Class used to accumulate stats information into a single displayable string. */ @interface ARDStatsBuilder : NSObject @@ -22,10 +21,6 @@ * class. */ @property(nonatomic, readonly) NSString *statsString; - -/** Parses the information in the stats report into an appropriate internal - * format used to generate the stats string. - */ -- (void)parseStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport; +@property(nonatomic) RTC_OBJC_TYPE(RTCStatisticsReport) * stats; @end diff --git a/examples/objc/AppRTCMobile/ARDStatsBuilder.m b/examples/objc/AppRTCMobile/ARDStatsBuilder.m index a74e351d51..7ebf9fb1c7 100644 --- a/examples/objc/AppRTCMobile/ARDStatsBuilder.m +++ b/examples/objc/AppRTCMobile/ARDStatsBuilder.m @@ -13,334 +13,24 @@ #import "sdk/objc/api/peerconnection/RTCLegacyStatsReport.h" #import "sdk/objc/base/RTCMacros.h" -#import "ARDBitrateTracker.h" #import "ARDUtilities.h" -@implementation ARDStatsBuilder { - // Connection stats. - NSString *_connRecvBitrate; - NSString *_connRtt; - NSString *_connSendBitrate; - NSString *_localCandType; - NSString *_remoteCandType; - NSString *_transportType; +@implementation ARDStatsBuilder - // BWE stats. - NSString *_actualEncBitrate; - NSString *_availableRecvBw; - NSString *_availableSendBw; - NSString *_targetEncBitrate; - - // Video send stats. - NSString *_videoEncodeMs; - NSString *_videoInputFps; - NSString *_videoInputHeight; - NSString *_videoInputWidth; - NSString *_videoSendCodec; - NSString *_videoSendBitrate; - NSString *_videoSendFps; - NSString *_videoSendHeight; - NSString *_videoSendWidth; - - // QP stats. - int _videoQPSum; - int _framesEncoded; - int _oldVideoQPSum; - int _oldFramesEncoded; - - // Video receive stats. - NSString *_videoDecodeMs; - NSString *_videoDecodedFps; - NSString *_videoOutputFps; - NSString *_videoRecvBitrate; - NSString *_videoRecvFps; - NSString *_videoRecvHeight; - NSString *_videoRecvWidth; - - // Audio send stats. - NSString *_audioSendBitrate; - NSString *_audioSendCodec; - - // Audio receive stats. - NSString *_audioCurrentDelay; - NSString *_audioExpandRate; - NSString *_audioRecvBitrate; - NSString *_audioRecvCodec; - - // Bitrate trackers. - ARDBitrateTracker *_audioRecvBitrateTracker; - ARDBitrateTracker *_audioSendBitrateTracker; - ARDBitrateTracker *_connRecvBitrateTracker; - ARDBitrateTracker *_connSendBitrateTracker; - ARDBitrateTracker *_videoRecvBitrateTracker; - ARDBitrateTracker *_videoSendBitrateTracker; -} - -- (instancetype)init { - if (self = [super init]) { - _audioSendBitrateTracker = [[ARDBitrateTracker alloc] init]; - _audioRecvBitrateTracker = [[ARDBitrateTracker alloc] init]; - _connSendBitrateTracker = [[ARDBitrateTracker alloc] init]; - _connRecvBitrateTracker = [[ARDBitrateTracker alloc] init]; - _videoSendBitrateTracker = [[ARDBitrateTracker alloc] init]; - _videoRecvBitrateTracker = [[ARDBitrateTracker alloc] init]; - _videoQPSum = 0; - _framesEncoded = 0; - } - return self; -} +@synthesize stats = _stats; - (NSString *)statsString { NSMutableString *result = [NSMutableString string]; - NSString *systemStatsFormat = @"(cpu)%ld%%\n"; - [result appendString:[NSString stringWithFormat:systemStatsFormat, - (long)ARDGetCpuUsagePercentage()]]; - // Connection stats. - NSString *connStatsFormat = @"CN %@ms | %@->%@/%@ | (s)%@ | (r)%@\n"; - [result appendString:[NSString stringWithFormat:connStatsFormat, - _connRtt, - _localCandType, _remoteCandType, _transportType, - _connSendBitrate, _connRecvBitrate]]; + [result appendFormat:@"(cpu)%ld%%\n", (long)ARDGetCpuUsagePercentage()]; - // Video send stats. - NSString *videoSendFormat = @"VS (input) %@x%@@%@fps | (sent) %@x%@@%@fps\n" - "VS (enc) %@/%@ | (sent) %@/%@ | %@ms | %@\n" - "AvgQP (past %d encoded frames) = %d\n "; - int avgqp = [self calculateAvgQP]; - - [result appendString:[NSString stringWithFormat:videoSendFormat, - _videoInputWidth, _videoInputHeight, _videoInputFps, - _videoSendWidth, _videoSendHeight, _videoSendFps, - _actualEncBitrate, _targetEncBitrate, - _videoSendBitrate, _availableSendBw, - _videoEncodeMs, - _videoSendCodec, - _framesEncoded - _oldFramesEncoded, avgqp]]; - - // Video receive stats. - NSString *videoReceiveFormat = - @"VR (recv) %@x%@@%@fps | (decoded)%@ | (output)%@fps | %@/%@ | %@ms\n"; - [result appendString:[NSString stringWithFormat:videoReceiveFormat, - _videoRecvWidth, _videoRecvHeight, _videoRecvFps, - _videoDecodedFps, - _videoOutputFps, - _videoRecvBitrate, _availableRecvBw, - _videoDecodeMs]]; - - // Audio send stats. - NSString *audioSendFormat = @"AS %@ | %@\n"; - [result appendString:[NSString stringWithFormat:audioSendFormat, - _audioSendBitrate, _audioSendCodec]]; - - // Audio receive stats. - NSString *audioReceiveFormat = @"AR %@ | %@ | %@ms | (expandrate)%@"; - [result appendString:[NSString stringWithFormat:audioReceiveFormat, - _audioRecvBitrate, _audioRecvCodec, _audioCurrentDelay, - _audioExpandRate]]; + for (NSString *key in _stats.statistics) { + RTC_OBJC_TYPE(RTCStatistics) *stat = _stats.statistics[key]; + [result appendFormat:@"%@\n", stat.description]; + } return result; } -- (void)parseStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - NSString *reportType = statsReport.type; - if ([reportType isEqualToString:@"ssrc"] && - [statsReport.reportId rangeOfString:@"ssrc"].location != NSNotFound) { - if ([statsReport.reportId rangeOfString:@"send"].location != NSNotFound) { - [self parseSendSsrcStatsReport:statsReport]; - } - if ([statsReport.reportId rangeOfString:@"recv"].location != NSNotFound) { - [self parseRecvSsrcStatsReport:statsReport]; - } - } else if ([reportType isEqualToString:@"VideoBwe"]) { - [self parseBweStatsReport:statsReport]; - } else if ([reportType isEqualToString:@"googCandidatePair"]) { - [self parseConnectionStatsReport:statsReport]; - } -} - -#pragma mark - Private - -- (int)calculateAvgQP { - int deltaFramesEncoded = _framesEncoded - _oldFramesEncoded; - int deltaQPSum = _videoQPSum - _oldVideoQPSum; - - return deltaFramesEncoded != 0 ? deltaQPSum / deltaFramesEncoded : 0; -} - -- (void)updateBweStatOfKey:(NSString *)key value:(NSString *)value { - if ([key isEqualToString:@"googAvailableSendBandwidth"]) { - _availableSendBw = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; - } else if ([key isEqualToString:@"googAvailableReceiveBandwidth"]) { - _availableRecvBw = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; - } else if ([key isEqualToString:@"googActualEncBitrate"]) { - _actualEncBitrate = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; - } else if ([key isEqualToString:@"googTargetEncBitrate"]) { - _targetEncBitrate = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; - } -} - -- (void)parseBweStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - [statsReport.values - enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { - [self updateBweStatOfKey:key value:value]; - }]; -} - -- (void)updateConnectionStatOfKey:(NSString *)key value:(NSString *)value { - if ([key isEqualToString:@"googRtt"]) { - _connRtt = value; - } else if ([key isEqualToString:@"googLocalCandidateType"]) { - _localCandType = value; - } else if ([key isEqualToString:@"googRemoteCandidateType"]) { - _remoteCandType = value; - } else if ([key isEqualToString:@"googTransportType"]) { - _transportType = value; - } else if ([key isEqualToString:@"bytesReceived"]) { - NSInteger byteCount = value.integerValue; - [_connRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; - _connRecvBitrate = _connRecvBitrateTracker.bitrateString; - } else if ([key isEqualToString:@"bytesSent"]) { - NSInteger byteCount = value.integerValue; - [_connSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; - _connSendBitrate = _connSendBitrateTracker.bitrateString; - } -} - -- (void)parseConnectionStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - NSString *activeConnection = statsReport.values[@"googActiveConnection"]; - if (![activeConnection isEqualToString:@"true"]) { - return; - } - [statsReport.values - enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { - [self updateConnectionStatOfKey:key value:value]; - }]; -} - -- (void)parseSendSsrcStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - NSDictionary *values = statsReport.values; - if ([values objectForKey:@"googFrameRateSent"]) { - // Video track. - [self parseVideoSendStatsReport:statsReport]; - } else if ([values objectForKey:@"audioInputLevel"]) { - // Audio track. - [self parseAudioSendStatsReport:statsReport]; - } -} - -- (void)updateAudioSendStatOfKey:(NSString *)key value:(NSString *)value { - if ([key isEqualToString:@"googCodecName"]) { - _audioSendCodec = value; - } else if ([key isEqualToString:@"bytesSent"]) { - NSInteger byteCount = value.integerValue; - [_audioSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; - _audioSendBitrate = _audioSendBitrateTracker.bitrateString; - } -} - -- (void)parseAudioSendStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - [statsReport.values - enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { - [self updateAudioSendStatOfKey:key value:value]; - }]; -} - -- (void)updateVideoSendStatOfKey:(NSString *)key value:(NSString *)value { - if ([key isEqualToString:@"googCodecName"]) { - _videoSendCodec = value; - } else if ([key isEqualToString:@"googFrameHeightInput"]) { - _videoInputHeight = value; - } else if ([key isEqualToString:@"googFrameWidthInput"]) { - _videoInputWidth = value; - } else if ([key isEqualToString:@"googFrameRateInput"]) { - _videoInputFps = value; - } else if ([key isEqualToString:@"googFrameHeightSent"]) { - _videoSendHeight = value; - } else if ([key isEqualToString:@"googFrameWidthSent"]) { - _videoSendWidth = value; - } else if ([key isEqualToString:@"googFrameRateSent"]) { - _videoSendFps = value; - } else if ([key isEqualToString:@"googAvgEncodeMs"]) { - _videoEncodeMs = value; - } else if ([key isEqualToString:@"bytesSent"]) { - NSInteger byteCount = value.integerValue; - [_videoSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; - _videoSendBitrate = _videoSendBitrateTracker.bitrateString; - } else if ([key isEqualToString:@"qpSum"]) { - _oldVideoQPSum = _videoQPSum; - _videoQPSum = value.integerValue; - } else if ([key isEqualToString:@"framesEncoded"]) { - _oldFramesEncoded = _framesEncoded; - _framesEncoded = value.integerValue; - } -} - -- (void)parseVideoSendStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - [statsReport.values - enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { - [self updateVideoSendStatOfKey:key value:value]; - }]; -} - -- (void)parseRecvSsrcStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - NSDictionary *values = statsReport.values; - if ([values objectForKey:@"googFrameWidthReceived"]) { - // Video track. - [self parseVideoRecvStatsReport:statsReport]; - } else if ([values objectForKey:@"audioOutputLevel"]) { - // Audio track. - [self parseAudioRecvStatsReport:statsReport]; - } -} - -- (void)updateAudioRecvStatOfKey:(NSString *)key value:(NSString *)value { - if ([key isEqualToString:@"googCodecName"]) { - _audioRecvCodec = value; - } else if ([key isEqualToString:@"bytesReceived"]) { - NSInteger byteCount = value.integerValue; - [_audioRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; - _audioRecvBitrate = _audioRecvBitrateTracker.bitrateString; - } else if ([key isEqualToString:@"googSpeechExpandRate"]) { - _audioExpandRate = value; - } else if ([key isEqualToString:@"googCurrentDelayMs"]) { - _audioCurrentDelay = value; - } -} - -- (void)parseAudioRecvStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - [statsReport.values - enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { - [self updateAudioRecvStatOfKey:key value:value]; - }]; -} - -- (void)updateVideoRecvStatOfKey:(NSString *)key value:(NSString *)value { - if ([key isEqualToString:@"googFrameHeightReceived"]) { - _videoRecvHeight = value; - } else if ([key isEqualToString:@"googFrameWidthReceived"]) { - _videoRecvWidth = value; - } else if ([key isEqualToString:@"googFrameRateReceived"]) { - _videoRecvFps = value; - } else if ([key isEqualToString:@"googFrameRateDecoded"]) { - _videoDecodedFps = value; - } else if ([key isEqualToString:@"googFrameRateOutput"]) { - _videoOutputFps = value; - } else if ([key isEqualToString:@"googDecodeMs"]) { - _videoDecodeMs = value; - } else if ([key isEqualToString:@"bytesReceived"]) { - NSInteger byteCount = value.integerValue; - [_videoRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; - _videoRecvBitrate = _videoRecvBitrateTracker.bitrateString; - } -} - -- (void)parseVideoRecvStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport { - [statsReport.values - enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { - [self updateVideoRecvStatOfKey:key value:value]; - }]; -} - @end diff --git a/examples/objc/AppRTCMobile/ios/ARDStatsView.h b/examples/objc/AppRTCMobile/ios/ARDStatsView.h index 9c8636476c..72207de64e 100644 --- a/examples/objc/AppRTCMobile/ios/ARDStatsView.h +++ b/examples/objc/AppRTCMobile/ios/ARDStatsView.h @@ -10,8 +10,12 @@ #import +#import "sdk/objc/base/RTCMacros.h" + +@class RTC_OBJC_TYPE(RTCStatisticsReport); + @interface ARDStatsView : UIView -- (void)setStats:(NSArray *)stats; +- (void)setStats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats; @end diff --git a/examples/objc/AppRTCMobile/ios/ARDStatsView.m b/examples/objc/AppRTCMobile/ios/ARDStatsView.m index bd97d30fbe..867ba5b09e 100644 --- a/examples/objc/AppRTCMobile/ios/ARDStatsView.m +++ b/examples/objc/AppRTCMobile/ios/ARDStatsView.m @@ -34,10 +34,8 @@ return self; } -- (void)setStats:(NSArray *)stats { - for (RTC_OBJC_TYPE(RTCLegacyStatsReport) * report in stats) { - [_statsBuilder parseStatsReport:report]; - } +- (void)setStats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats { + _statsBuilder.stats = stats; _statsLabel.text = _statsBuilder.statsString; } diff --git a/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m b/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m index cd26829713..a82d90b290 100644 --- a/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m +++ b/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m @@ -132,8 +132,7 @@ }); } -- (void)appClient:(ARDAppClient *)client - didGetStats:(NSArray *)stats { +- (void)appClient:(ARDAppClient *)client didGetStats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats { _videoCallView.statsView.stats = stats; [_videoCallView setNeedsLayout]; } diff --git a/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m b/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m index d9c816d573..1c276d965f 100644 --- a/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m +++ b/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m @@ -120,7 +120,7 @@ didReceiveRemoteVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)remoteVideoTrack { } -- (void)appClient:(ARDAppClient *)client didGetStats:(NSArray *)stats { +- (void)appClient:(ARDAppClient *)client didGetStats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats { } - (void)appClient:(ARDAppClient *)client didError:(NSError *)error {