blob: 0643b428273cc89c3d661d11423577fac07105a5 [file] [log] [blame]
Zeke Chind3325802015-08-14 11:00:02 -07001/*
2 * Copyright 2015 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
11#import "ARDStatsBuilder.h"
12
hbosbd3dda62016-09-09 01:36:28 -070013#import "WebRTC/RTCLegacyStatsReport.h"
Zeke Chind3325802015-08-14 11:00:02 -070014
15#import "ARDBitrateTracker.h"
16#import "ARDUtilities.h"
17
18@implementation ARDStatsBuilder {
19 // Connection stats.
20 NSString *_connRecvBitrate;
21 NSString *_connRtt;
22 NSString *_connSendBitrate;
23 NSString *_localCandType;
24 NSString *_remoteCandType;
25 NSString *_transportType;
26
27 // BWE stats.
28 NSString *_actualEncBitrate;
29 NSString *_availableRecvBw;
30 NSString *_availableSendBw;
31 NSString *_targetEncBitrate;
32
33 // Video send stats.
34 NSString *_videoEncodeMs;
35 NSString *_videoInputFps;
36 NSString *_videoInputHeight;
37 NSString *_videoInputWidth;
38 NSString *_videoSendCodec;
39 NSString *_videoSendBitrate;
40 NSString *_videoSendFps;
41 NSString *_videoSendHeight;
42 NSString *_videoSendWidth;
43
44 // Video receive stats.
45 NSString *_videoDecodeMs;
46 NSString *_videoDecodedFps;
47 NSString *_videoOutputFps;
48 NSString *_videoRecvBitrate;
49 NSString *_videoRecvFps;
50 NSString *_videoRecvHeight;
51 NSString *_videoRecvWidth;
52
53 // Audio send stats.
54 NSString *_audioSendBitrate;
55 NSString *_audioSendCodec;
56
57 // Audio receive stats.
58 NSString *_audioCurrentDelay;
59 NSString *_audioExpandRate;
60 NSString *_audioRecvBitrate;
61 NSString *_audioRecvCodec;
62
63 // Bitrate trackers.
64 ARDBitrateTracker *_audioRecvBitrateTracker;
65 ARDBitrateTracker *_audioSendBitrateTracker;
66 ARDBitrateTracker *_connRecvBitrateTracker;
67 ARDBitrateTracker *_connSendBitrateTracker;
68 ARDBitrateTracker *_videoRecvBitrateTracker;
69 ARDBitrateTracker *_videoSendBitrateTracker;
70}
71
72- (instancetype)init {
73 if (self = [super init]) {
74 _audioSendBitrateTracker = [[ARDBitrateTracker alloc] init];
75 _audioRecvBitrateTracker = [[ARDBitrateTracker alloc] init];
76 _connSendBitrateTracker = [[ARDBitrateTracker alloc] init];
77 _connRecvBitrateTracker = [[ARDBitrateTracker alloc] init];
78 _videoSendBitrateTracker = [[ARDBitrateTracker alloc] init];
79 _videoRecvBitrateTracker = [[ARDBitrateTracker alloc] init];
80 }
81 return self;
82}
83
84- (NSString *)statsString {
85 NSMutableString *result = [NSMutableString string];
86 NSString *systemStatsFormat = @"(cpu)%ld%%\n";
87 [result appendString:[NSString stringWithFormat:systemStatsFormat,
88 (long)ARDGetCpuUsagePercentage()]];
89
90 // Connection stats.
91 NSString *connStatsFormat = @"CN %@ms | %@->%@/%@ | (s)%@ | (r)%@\n";
92 [result appendString:[NSString stringWithFormat:connStatsFormat,
93 _connRtt,
94 _localCandType, _remoteCandType, _transportType,
95 _connSendBitrate, _connRecvBitrate]];
96
97 // Video send stats.
98 NSString *videoSendFormat = @"VS (input) %@x%@@%@fps | (sent) %@x%@@%@fps\n"
99 "VS (enc) %@/%@ | (sent) %@/%@ | %@ms | %@\n";
100 [result appendString:[NSString stringWithFormat:videoSendFormat,
101 _videoInputWidth, _videoInputHeight, _videoInputFps,
102 _videoSendWidth, _videoSendHeight, _videoSendFps,
103 _actualEncBitrate, _targetEncBitrate,
104 _videoSendBitrate, _availableSendBw,
105 _videoEncodeMs,
106 _videoSendCodec]];
107
108 // Video receive stats.
109 NSString *videoReceiveFormat =
110 @"VR (recv) %@x%@@%@fps | (decoded)%@ | (output)%@fps | %@/%@ | %@ms\n";
111 [result appendString:[NSString stringWithFormat:videoReceiveFormat,
112 _videoRecvWidth, _videoRecvHeight, _videoRecvFps,
113 _videoDecodedFps,
114 _videoOutputFps,
115 _videoRecvBitrate, _availableRecvBw,
116 _videoDecodeMs]];
117
118 // Audio send stats.
119 NSString *audioSendFormat = @"AS %@ | %@\n";
120 [result appendString:[NSString stringWithFormat:audioSendFormat,
121 _audioSendBitrate, _audioSendCodec]];
122
123 // Audio receive stats.
124 NSString *audioReceiveFormat = @"AR %@ | %@ | %@ms | (expandrate)%@";
125 [result appendString:[NSString stringWithFormat:audioReceiveFormat,
126 _audioRecvBitrate, _audioRecvCodec, _audioCurrentDelay,
127 _audioExpandRate]];
128
129 return result;
130}
131
hbosbd3dda62016-09-09 01:36:28 -0700132- (void)parseStatsReport:(RTCLegacyStatsReport *)statsReport {
Zeke Chind3325802015-08-14 11:00:02 -0700133 NSString *reportType = statsReport.type;
134 if ([reportType isEqualToString:@"ssrc"] &&
135 [statsReport.reportId rangeOfString:@"ssrc"].location != NSNotFound) {
136 if ([statsReport.reportId rangeOfString:@"send"].location != NSNotFound) {
137 [self parseSendSsrcStatsReport:statsReport];
138 }
139 if ([statsReport.reportId rangeOfString:@"recv"].location != NSNotFound) {
140 [self parseRecvSsrcStatsReport:statsReport];
141 }
142 } else if ([reportType isEqualToString:@"VideoBwe"]) {
143 [self parseBweStatsReport:statsReport];
144 } else if ([reportType isEqualToString:@"googCandidatePair"]) {
145 [self parseConnectionStatsReport:statsReport];
146 }
147}
148
149#pragma mark - Private
150
hbosbd3dda62016-09-09 01:36:28 -0700151- (void)parseBweStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700152 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
153 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700154 if ([key isEqualToString:@"googAvailableSendBandwidth"]) {
155 _availableSendBw =
156 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
157 } else if ([key isEqualToString:@"googAvailableReceiveBandwidth"]) {
158 _availableRecvBw =
159 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
160 } else if ([key isEqualToString:@"googActualEncBitrate"]) {
161 _actualEncBitrate =
162 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
163 } else if ([key isEqualToString:@"googTargetEncBitrate"]) {
164 _targetEncBitrate =
165 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
166 }
hjon79858f82016-03-13 22:08:26 -0700167 }];
Zeke Chind3325802015-08-14 11:00:02 -0700168}
169
hbosbd3dda62016-09-09 01:36:28 -0700170- (void)parseConnectionStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700171 NSString *activeConnection = statsReport.values[@"googActiveConnection"];
Zeke Chind3325802015-08-14 11:00:02 -0700172 if (![activeConnection isEqualToString:@"true"]) {
173 return;
174 }
hjon79858f82016-03-13 22:08:26 -0700175 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
176 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700177 if ([key isEqualToString:@"googRtt"]) {
178 _connRtt = value;
179 } else if ([key isEqualToString:@"googLocalCandidateType"]) {
180 _localCandType = value;
181 } else if ([key isEqualToString:@"googRemoteCandidateType"]) {
182 _remoteCandType = value;
183 } else if ([key isEqualToString:@"googTransportType"]) {
184 _transportType = value;
185 } else if ([key isEqualToString:@"bytesReceived"]) {
186 NSInteger byteCount = value.integerValue;
187 [_connRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
188 _connRecvBitrate = _connRecvBitrateTracker.bitrateString;
189 } else if ([key isEqualToString:@"bytesSent"]) {
190 NSInteger byteCount = value.integerValue;
191 [_connSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
192 _connSendBitrate = _connSendBitrateTracker.bitrateString;
193 }
hjon79858f82016-03-13 22:08:26 -0700194 }];
Zeke Chind3325802015-08-14 11:00:02 -0700195}
196
hbosbd3dda62016-09-09 01:36:28 -0700197- (void)parseSendSsrcStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700198 NSDictionary *values = statsReport.values;
stefanff4def72016-06-26 12:08:39 -0700199 if ([values objectForKey:@"googFrameRateSent"]) {
Zeke Chind3325802015-08-14 11:00:02 -0700200 // Video track.
201 [self parseVideoSendStatsReport:statsReport];
stefanff4def72016-06-26 12:08:39 -0700202 } else if ([values objectForKey:@"audioInputLevel"]) {
Zeke Chind3325802015-08-14 11:00:02 -0700203 // Audio track.
204 [self parseAudioSendStatsReport:statsReport];
205 }
206}
207
hbosbd3dda62016-09-09 01:36:28 -0700208- (void)parseAudioSendStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700209 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
210 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700211 if ([key isEqualToString:@"googCodecName"]) {
212 _audioSendCodec = value;
213 } else if ([key isEqualToString:@"bytesSent"]) {
214 NSInteger byteCount = value.integerValue;
215 [_audioSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
216 _audioSendBitrate = _audioSendBitrateTracker.bitrateString;
217 }
hjon79858f82016-03-13 22:08:26 -0700218 }];
Zeke Chind3325802015-08-14 11:00:02 -0700219}
220
hbosbd3dda62016-09-09 01:36:28 -0700221- (void)parseVideoSendStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700222 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
223 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700224 if ([key isEqualToString:@"googCodecName"]) {
225 _videoSendCodec = value;
226 } else if ([key isEqualToString:@"googFrameHeightInput"]) {
227 _videoInputHeight = value;
228 } else if ([key isEqualToString:@"googFrameWidthInput"]) {
229 _videoInputWidth = value;
230 } else if ([key isEqualToString:@"googFrameRateInput"]) {
231 _videoInputFps = value;
232 } else if ([key isEqualToString:@"googFrameHeightSent"]) {
233 _videoSendHeight = value;
234 } else if ([key isEqualToString:@"googFrameWidthSent"]) {
235 _videoSendWidth = value;
236 } else if ([key isEqualToString:@"googFrameRateSent"]) {
237 _videoSendFps = value;
238 } else if ([key isEqualToString:@"googAvgEncodeMs"]) {
239 _videoEncodeMs = value;
240 } else if ([key isEqualToString:@"bytesSent"]) {
241 NSInteger byteCount = value.integerValue;
242 [_videoSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
243 _videoSendBitrate = _videoSendBitrateTracker.bitrateString;
244 }
hjon79858f82016-03-13 22:08:26 -0700245 }];
Zeke Chind3325802015-08-14 11:00:02 -0700246}
247
hbosbd3dda62016-09-09 01:36:28 -0700248- (void)parseRecvSsrcStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700249 NSDictionary *values = statsReport.values;
stefanff4def72016-06-26 12:08:39 -0700250 if ([values objectForKey:@"googFrameWidthReceived"]) {
251 // Video track.
Zeke Chind3325802015-08-14 11:00:02 -0700252 [self parseVideoRecvStatsReport:statsReport];
stefanff4def72016-06-26 12:08:39 -0700253 } else if ([values objectForKey:@"audioOutputLevel"]) {
254 // Audio track.
Zeke Chind3325802015-08-14 11:00:02 -0700255 [self parseAudioRecvStatsReport:statsReport];
256 }
257}
258
hbosbd3dda62016-09-09 01:36:28 -0700259- (void)parseAudioRecvStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700260 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
261 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700262 if ([key isEqualToString:@"googCodecName"]) {
263 _audioRecvCodec = value;
264 } else if ([key isEqualToString:@"bytesReceived"]) {
265 NSInteger byteCount = value.integerValue;
266 [_audioRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
267 _audioRecvBitrate = _audioRecvBitrateTracker.bitrateString;
268 } else if ([key isEqualToString:@"googSpeechExpandRate"]) {
269 _audioExpandRate = value;
270 } else if ([key isEqualToString:@"googCurrentDelayMs"]) {
271 _audioCurrentDelay = value;
272 }
hjon79858f82016-03-13 22:08:26 -0700273 }];
Zeke Chind3325802015-08-14 11:00:02 -0700274}
275
hbosbd3dda62016-09-09 01:36:28 -0700276- (void)parseVideoRecvStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700277 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
278 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700279 if ([key isEqualToString:@"googFrameHeightReceived"]) {
280 _videoRecvHeight = value;
281 } else if ([key isEqualToString:@"googFrameWidthReceived"]) {
282 _videoRecvWidth = value;
283 } else if ([key isEqualToString:@"googFrameRateReceived"]) {
284 _videoRecvFps = value;
285 } else if ([key isEqualToString:@"googFrameRateDecoded"]) {
286 _videoDecodedFps = value;
287 } else if ([key isEqualToString:@"googFrameRateOutput"]) {
288 _videoOutputFps = value;
289 } else if ([key isEqualToString:@"googDecodeMs"]) {
290 _videoDecodeMs = value;
291 } else if ([key isEqualToString:@"bytesReceived"]) {
292 NSInteger byteCount = value.integerValue;
293 [_videoRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
294 _videoRecvBitrate = _videoRecvBitrateTracker.bitrateString;
295 }
hjon79858f82016-03-13 22:08:26 -0700296 }];
Zeke Chind3325802015-08-14 11:00:02 -0700297}
298
299@end
300