blob: f9a1920399211bf7a63c0adfa77f321c7eda4393 [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
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020013#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
denicijab6c456b2016-12-19 02:14:08 -080044 // QP stats.
45 int _videoQPSum;
46 int _framesEncoded;
47 int _oldVideoQPSum;
48 int _oldFramesEncoded;
49
Zeke Chind3325802015-08-14 11:00:02 -070050 // Video receive stats.
51 NSString *_videoDecodeMs;
52 NSString *_videoDecodedFps;
53 NSString *_videoOutputFps;
54 NSString *_videoRecvBitrate;
55 NSString *_videoRecvFps;
56 NSString *_videoRecvHeight;
57 NSString *_videoRecvWidth;
58
59 // Audio send stats.
60 NSString *_audioSendBitrate;
61 NSString *_audioSendCodec;
62
63 // Audio receive stats.
64 NSString *_audioCurrentDelay;
65 NSString *_audioExpandRate;
66 NSString *_audioRecvBitrate;
67 NSString *_audioRecvCodec;
68
69 // Bitrate trackers.
70 ARDBitrateTracker *_audioRecvBitrateTracker;
71 ARDBitrateTracker *_audioSendBitrateTracker;
72 ARDBitrateTracker *_connRecvBitrateTracker;
73 ARDBitrateTracker *_connSendBitrateTracker;
74 ARDBitrateTracker *_videoRecvBitrateTracker;
75 ARDBitrateTracker *_videoSendBitrateTracker;
76}
77
78- (instancetype)init {
79 if (self = [super init]) {
80 _audioSendBitrateTracker = [[ARDBitrateTracker alloc] init];
81 _audioRecvBitrateTracker = [[ARDBitrateTracker alloc] init];
82 _connSendBitrateTracker = [[ARDBitrateTracker alloc] init];
83 _connRecvBitrateTracker = [[ARDBitrateTracker alloc] init];
84 _videoSendBitrateTracker = [[ARDBitrateTracker alloc] init];
85 _videoRecvBitrateTracker = [[ARDBitrateTracker alloc] init];
denicijab6c456b2016-12-19 02:14:08 -080086 _videoQPSum = 0;
87 _framesEncoded = 0;
Zeke Chind3325802015-08-14 11:00:02 -070088 }
89 return self;
90}
91
92- (NSString *)statsString {
93 NSMutableString *result = [NSMutableString string];
94 NSString *systemStatsFormat = @"(cpu)%ld%%\n";
95 [result appendString:[NSString stringWithFormat:systemStatsFormat,
96 (long)ARDGetCpuUsagePercentage()]];
97
98 // Connection stats.
99 NSString *connStatsFormat = @"CN %@ms | %@->%@/%@ | (s)%@ | (r)%@\n";
100 [result appendString:[NSString stringWithFormat:connStatsFormat,
101 _connRtt,
102 _localCandType, _remoteCandType, _transportType,
103 _connSendBitrate, _connRecvBitrate]];
104
105 // Video send stats.
106 NSString *videoSendFormat = @"VS (input) %@x%@@%@fps | (sent) %@x%@@%@fps\n"
denicijab6c456b2016-12-19 02:14:08 -0800107 "VS (enc) %@/%@ | (sent) %@/%@ | %@ms | %@\n"
108 "AvgQP (past %d encoded frames) = %d\n ";
109 int avgqp = [self calculateAvgQP];
110
Zeke Chind3325802015-08-14 11:00:02 -0700111 [result appendString:[NSString stringWithFormat:videoSendFormat,
112 _videoInputWidth, _videoInputHeight, _videoInputFps,
113 _videoSendWidth, _videoSendHeight, _videoSendFps,
114 _actualEncBitrate, _targetEncBitrate,
115 _videoSendBitrate, _availableSendBw,
116 _videoEncodeMs,
denicijab6c456b2016-12-19 02:14:08 -0800117 _videoSendCodec,
118 _framesEncoded - _oldFramesEncoded, avgqp]];
Zeke Chind3325802015-08-14 11:00:02 -0700119
120 // Video receive stats.
121 NSString *videoReceiveFormat =
122 @"VR (recv) %@x%@@%@fps | (decoded)%@ | (output)%@fps | %@/%@ | %@ms\n";
123 [result appendString:[NSString stringWithFormat:videoReceiveFormat,
124 _videoRecvWidth, _videoRecvHeight, _videoRecvFps,
125 _videoDecodedFps,
126 _videoOutputFps,
127 _videoRecvBitrate, _availableRecvBw,
128 _videoDecodeMs]];
129
130 // Audio send stats.
131 NSString *audioSendFormat = @"AS %@ | %@\n";
132 [result appendString:[NSString stringWithFormat:audioSendFormat,
133 _audioSendBitrate, _audioSendCodec]];
134
135 // Audio receive stats.
136 NSString *audioReceiveFormat = @"AR %@ | %@ | %@ms | (expandrate)%@";
137 [result appendString:[NSString stringWithFormat:audioReceiveFormat,
138 _audioRecvBitrate, _audioRecvCodec, _audioCurrentDelay,
139 _audioExpandRate]];
140
141 return result;
142}
143
hbosbd3dda62016-09-09 01:36:28 -0700144- (void)parseStatsReport:(RTCLegacyStatsReport *)statsReport {
Zeke Chind3325802015-08-14 11:00:02 -0700145 NSString *reportType = statsReport.type;
146 if ([reportType isEqualToString:@"ssrc"] &&
147 [statsReport.reportId rangeOfString:@"ssrc"].location != NSNotFound) {
148 if ([statsReport.reportId rangeOfString:@"send"].location != NSNotFound) {
149 [self parseSendSsrcStatsReport:statsReport];
150 }
151 if ([statsReport.reportId rangeOfString:@"recv"].location != NSNotFound) {
152 [self parseRecvSsrcStatsReport:statsReport];
153 }
154 } else if ([reportType isEqualToString:@"VideoBwe"]) {
155 [self parseBweStatsReport:statsReport];
156 } else if ([reportType isEqualToString:@"googCandidatePair"]) {
157 [self parseConnectionStatsReport:statsReport];
158 }
159}
160
161#pragma mark - Private
162
denicijab6c456b2016-12-19 02:14:08 -0800163- (int)calculateAvgQP {
164 int deltaFramesEncoded = _framesEncoded - _oldFramesEncoded;
165 int deltaQPSum = _videoQPSum - _oldVideoQPSum;
166
167 return deltaFramesEncoded != 0 ? deltaQPSum / deltaFramesEncoded : 0;
168}
169
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800170- (void)updateBweStatOfKey:(NSString *)key value:(NSString *)value {
171 if ([key isEqualToString:@"googAvailableSendBandwidth"]) {
172 _availableSendBw = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
173 } else if ([key isEqualToString:@"googAvailableReceiveBandwidth"]) {
174 _availableRecvBw = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
175 } else if ([key isEqualToString:@"googActualEncBitrate"]) {
176 _actualEncBitrate = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
177 } else if ([key isEqualToString:@"googTargetEncBitrate"]) {
178 _targetEncBitrate = [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
179 }
180}
181
hbosbd3dda62016-09-09 01:36:28 -0700182- (void)parseBweStatsReport:(RTCLegacyStatsReport *)statsReport {
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800183 [statsReport.values
184 enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
185 [self updateBweStatOfKey:key value:value];
186 }];
187}
188
189- (void)updateConnectionStatOfKey:(NSString *)key value:(NSString *)value {
190 if ([key isEqualToString:@"googRtt"]) {
191 _connRtt = value;
192 } else if ([key isEqualToString:@"googLocalCandidateType"]) {
193 _localCandType = value;
194 } else if ([key isEqualToString:@"googRemoteCandidateType"]) {
195 _remoteCandType = value;
196 } else if ([key isEqualToString:@"googTransportType"]) {
197 _transportType = value;
198 } else if ([key isEqualToString:@"bytesReceived"]) {
199 NSInteger byteCount = value.integerValue;
200 [_connRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
201 _connRecvBitrate = _connRecvBitrateTracker.bitrateString;
202 } else if ([key isEqualToString:@"bytesSent"]) {
203 NSInteger byteCount = value.integerValue;
204 [_connSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
205 _connSendBitrate = _connSendBitrateTracker.bitrateString;
206 }
Zeke Chind3325802015-08-14 11:00:02 -0700207}
208
hbosbd3dda62016-09-09 01:36:28 -0700209- (void)parseConnectionStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700210 NSString *activeConnection = statsReport.values[@"googActiveConnection"];
Zeke Chind3325802015-08-14 11:00:02 -0700211 if (![activeConnection isEqualToString:@"true"]) {
212 return;
213 }
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800214 [statsReport.values
215 enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
216 [self updateConnectionStatOfKey:key value:value];
217 }];
Zeke Chind3325802015-08-14 11:00:02 -0700218}
219
hbosbd3dda62016-09-09 01:36:28 -0700220- (void)parseSendSsrcStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700221 NSDictionary *values = statsReport.values;
stefanff4def72016-06-26 12:08:39 -0700222 if ([values objectForKey:@"googFrameRateSent"]) {
Zeke Chind3325802015-08-14 11:00:02 -0700223 // Video track.
224 [self parseVideoSendStatsReport:statsReport];
stefanff4def72016-06-26 12:08:39 -0700225 } else if ([values objectForKey:@"audioInputLevel"]) {
Zeke Chind3325802015-08-14 11:00:02 -0700226 // Audio track.
227 [self parseAudioSendStatsReport:statsReport];
228 }
229}
230
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800231- (void)updateAudioSendStatOfKey:(NSString *)key value:(NSString *)value {
232 if ([key isEqualToString:@"googCodecName"]) {
233 _audioSendCodec = value;
234 } else if ([key isEqualToString:@"bytesSent"]) {
235 NSInteger byteCount = value.integerValue;
236 [_audioSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
237 _audioSendBitrate = _audioSendBitrateTracker.bitrateString;
238 }
239}
240
hbosbd3dda62016-09-09 01:36:28 -0700241- (void)parseAudioSendStatsReport:(RTCLegacyStatsReport *)statsReport {
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800242 [statsReport.values
243 enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
244 [self updateAudioSendStatOfKey:key value:value];
245 }];
246}
247
248- (void)updateVideoSendStatOfKey:(NSString *)key value:(NSString *)value {
249 if ([key isEqualToString:@"googCodecName"]) {
250 _videoSendCodec = value;
251 } else if ([key isEqualToString:@"googFrameHeightInput"]) {
252 _videoInputHeight = value;
253 } else if ([key isEqualToString:@"googFrameWidthInput"]) {
254 _videoInputWidth = value;
255 } else if ([key isEqualToString:@"googFrameRateInput"]) {
256 _videoInputFps = value;
257 } else if ([key isEqualToString:@"googFrameHeightSent"]) {
258 _videoSendHeight = value;
259 } else if ([key isEqualToString:@"googFrameWidthSent"]) {
260 _videoSendWidth = value;
261 } else if ([key isEqualToString:@"googFrameRateSent"]) {
262 _videoSendFps = value;
263 } else if ([key isEqualToString:@"googAvgEncodeMs"]) {
264 _videoEncodeMs = value;
265 } else if ([key isEqualToString:@"bytesSent"]) {
266 NSInteger byteCount = value.integerValue;
267 [_videoSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
268 _videoSendBitrate = _videoSendBitrateTracker.bitrateString;
269 } else if ([key isEqualToString:@"qpSum"]) {
270 _oldVideoQPSum = _videoQPSum;
271 _videoQPSum = value.integerValue;
272 } else if ([key isEqualToString:@"framesEncoded"]) {
273 _oldFramesEncoded = _framesEncoded;
274 _framesEncoded = value.integerValue;
275 }
Zeke Chind3325802015-08-14 11:00:02 -0700276}
277
hbosbd3dda62016-09-09 01:36:28 -0700278- (void)parseVideoSendStatsReport:(RTCLegacyStatsReport *)statsReport {
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800279 [statsReport.values
280 enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
281 [self updateVideoSendStatOfKey:key value:value];
282 }];
Zeke Chind3325802015-08-14 11:00:02 -0700283}
284
hbosbd3dda62016-09-09 01:36:28 -0700285- (void)parseRecvSsrcStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700286 NSDictionary *values = statsReport.values;
stefanff4def72016-06-26 12:08:39 -0700287 if ([values objectForKey:@"googFrameWidthReceived"]) {
288 // Video track.
Zeke Chind3325802015-08-14 11:00:02 -0700289 [self parseVideoRecvStatsReport:statsReport];
stefanff4def72016-06-26 12:08:39 -0700290 } else if ([values objectForKey:@"audioOutputLevel"]) {
291 // Audio track.
Zeke Chind3325802015-08-14 11:00:02 -0700292 [self parseAudioRecvStatsReport:statsReport];
293 }
294}
295
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800296- (void)updateAudioRecvStatOfKey:(NSString *)key value:(NSString *)value {
297 if ([key isEqualToString:@"googCodecName"]) {
298 _audioRecvCodec = value;
299 } else if ([key isEqualToString:@"bytesReceived"]) {
300 NSInteger byteCount = value.integerValue;
301 [_audioRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
302 _audioRecvBitrate = _audioRecvBitrateTracker.bitrateString;
303 } else if ([key isEqualToString:@"googSpeechExpandRate"]) {
304 _audioExpandRate = value;
305 } else if ([key isEqualToString:@"googCurrentDelayMs"]) {
306 _audioCurrentDelay = value;
307 }
308}
309
hbosbd3dda62016-09-09 01:36:28 -0700310- (void)parseAudioRecvStatsReport:(RTCLegacyStatsReport *)statsReport {
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800311 [statsReport.values
312 enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
313 [self updateAudioRecvStatOfKey:key value:value];
314 }];
315}
316
317- (void)updateVideoRecvStatOfKey:(NSString *)key value:(NSString *)value {
318 if ([key isEqualToString:@"googFrameHeightReceived"]) {
319 _videoRecvHeight = value;
320 } else if ([key isEqualToString:@"googFrameWidthReceived"]) {
321 _videoRecvWidth = value;
322 } else if ([key isEqualToString:@"googFrameRateReceived"]) {
323 _videoRecvFps = value;
324 } else if ([key isEqualToString:@"googFrameRateDecoded"]) {
325 _videoDecodedFps = value;
326 } else if ([key isEqualToString:@"googFrameRateOutput"]) {
327 _videoOutputFps = value;
328 } else if ([key isEqualToString:@"googDecodeMs"]) {
329 _videoDecodeMs = value;
330 } else if ([key isEqualToString:@"bytesReceived"]) {
331 NSInteger byteCount = value.integerValue;
332 [_videoRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
333 _videoRecvBitrate = _videoRecvBitrateTracker.bitrateString;
334 }
Zeke Chind3325802015-08-14 11:00:02 -0700335}
336
hbosbd3dda62016-09-09 01:36:28 -0700337- (void)parseVideoRecvStatsReport:(RTCLegacyStatsReport *)statsReport {
Jiawei Ou4aeb35b2018-11-09 13:55:45 -0800338 [statsReport.values
339 enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
340 [self updateVideoRecvStatOfKey:key value:value];
341 }];
Zeke Chind3325802015-08-14 11:00:02 -0700342}
343
344@end
345