blob: 370b72e8677e4a3b4aecb58d62a9886ba925750b [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
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
hbosbd3dda62016-09-09 01:36:28 -0700170- (void)parseBweStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700171 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
172 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700173 if ([key isEqualToString:@"googAvailableSendBandwidth"]) {
174 _availableSendBw =
175 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
176 } else if ([key isEqualToString:@"googAvailableReceiveBandwidth"]) {
177 _availableRecvBw =
178 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
179 } else if ([key isEqualToString:@"googActualEncBitrate"]) {
180 _actualEncBitrate =
181 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
182 } else if ([key isEqualToString:@"googTargetEncBitrate"]) {
183 _targetEncBitrate =
184 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue];
185 }
hjon79858f82016-03-13 22:08:26 -0700186 }];
Zeke Chind3325802015-08-14 11:00:02 -0700187}
188
hbosbd3dda62016-09-09 01:36:28 -0700189- (void)parseConnectionStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700190 NSString *activeConnection = statsReport.values[@"googActiveConnection"];
Zeke Chind3325802015-08-14 11:00:02 -0700191 if (![activeConnection isEqualToString:@"true"]) {
192 return;
193 }
hjon79858f82016-03-13 22:08:26 -0700194 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
195 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700196 if ([key isEqualToString:@"googRtt"]) {
197 _connRtt = value;
198 } else if ([key isEqualToString:@"googLocalCandidateType"]) {
199 _localCandType = value;
200 } else if ([key isEqualToString:@"googRemoteCandidateType"]) {
201 _remoteCandType = value;
202 } else if ([key isEqualToString:@"googTransportType"]) {
203 _transportType = value;
204 } else if ([key isEqualToString:@"bytesReceived"]) {
205 NSInteger byteCount = value.integerValue;
206 [_connRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
207 _connRecvBitrate = _connRecvBitrateTracker.bitrateString;
208 } else if ([key isEqualToString:@"bytesSent"]) {
209 NSInteger byteCount = value.integerValue;
210 [_connSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
211 _connSendBitrate = _connSendBitrateTracker.bitrateString;
212 }
hjon79858f82016-03-13 22:08:26 -0700213 }];
Zeke Chind3325802015-08-14 11:00:02 -0700214}
215
hbosbd3dda62016-09-09 01:36:28 -0700216- (void)parseSendSsrcStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700217 NSDictionary *values = statsReport.values;
stefanff4def72016-06-26 12:08:39 -0700218 if ([values objectForKey:@"googFrameRateSent"]) {
Zeke Chind3325802015-08-14 11:00:02 -0700219 // Video track.
220 [self parseVideoSendStatsReport:statsReport];
stefanff4def72016-06-26 12:08:39 -0700221 } else if ([values objectForKey:@"audioInputLevel"]) {
Zeke Chind3325802015-08-14 11:00:02 -0700222 // Audio track.
223 [self parseAudioSendStatsReport:statsReport];
224 }
225}
226
hbosbd3dda62016-09-09 01:36:28 -0700227- (void)parseAudioSendStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700228 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
229 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700230 if ([key isEqualToString:@"googCodecName"]) {
231 _audioSendCodec = value;
232 } else if ([key isEqualToString:@"bytesSent"]) {
233 NSInteger byteCount = value.integerValue;
234 [_audioSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
235 _audioSendBitrate = _audioSendBitrateTracker.bitrateString;
236 }
hjon79858f82016-03-13 22:08:26 -0700237 }];
Zeke Chind3325802015-08-14 11:00:02 -0700238}
239
hbosbd3dda62016-09-09 01:36:28 -0700240- (void)parseVideoSendStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700241 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
242 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700243 if ([key isEqualToString:@"googCodecName"]) {
244 _videoSendCodec = value;
245 } else if ([key isEqualToString:@"googFrameHeightInput"]) {
246 _videoInputHeight = value;
247 } else if ([key isEqualToString:@"googFrameWidthInput"]) {
248 _videoInputWidth = value;
249 } else if ([key isEqualToString:@"googFrameRateInput"]) {
250 _videoInputFps = value;
251 } else if ([key isEqualToString:@"googFrameHeightSent"]) {
252 _videoSendHeight = value;
253 } else if ([key isEqualToString:@"googFrameWidthSent"]) {
254 _videoSendWidth = value;
255 } else if ([key isEqualToString:@"googFrameRateSent"]) {
256 _videoSendFps = value;
257 } else if ([key isEqualToString:@"googAvgEncodeMs"]) {
258 _videoEncodeMs = value;
259 } else if ([key isEqualToString:@"bytesSent"]) {
260 NSInteger byteCount = value.integerValue;
261 [_videoSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
262 _videoSendBitrate = _videoSendBitrateTracker.bitrateString;
denicijab6c456b2016-12-19 02:14:08 -0800263 } else if ([key isEqualToString:@"qpSum"]) {
264 _oldVideoQPSum = _videoQPSum;
265 _videoQPSum = value.integerValue;
266 } else if ([key isEqualToString:@"framesEncoded"]) {
267 _oldFramesEncoded = _framesEncoded;
268 _framesEncoded = value.integerValue;
Zeke Chind3325802015-08-14 11:00:02 -0700269 }
hjon79858f82016-03-13 22:08:26 -0700270 }];
Zeke Chind3325802015-08-14 11:00:02 -0700271}
272
hbosbd3dda62016-09-09 01:36:28 -0700273- (void)parseRecvSsrcStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700274 NSDictionary *values = statsReport.values;
stefanff4def72016-06-26 12:08:39 -0700275 if ([values objectForKey:@"googFrameWidthReceived"]) {
276 // Video track.
Zeke Chind3325802015-08-14 11:00:02 -0700277 [self parseVideoRecvStatsReport:statsReport];
stefanff4def72016-06-26 12:08:39 -0700278 } else if ([values objectForKey:@"audioOutputLevel"]) {
279 // Audio track.
Zeke Chind3325802015-08-14 11:00:02 -0700280 [self parseAudioRecvStatsReport:statsReport];
281 }
282}
283
hbosbd3dda62016-09-09 01:36:28 -0700284- (void)parseAudioRecvStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700285 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
286 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700287 if ([key isEqualToString:@"googCodecName"]) {
288 _audioRecvCodec = value;
289 } else if ([key isEqualToString:@"bytesReceived"]) {
290 NSInteger byteCount = value.integerValue;
291 [_audioRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
292 _audioRecvBitrate = _audioRecvBitrateTracker.bitrateString;
293 } else if ([key isEqualToString:@"googSpeechExpandRate"]) {
294 _audioExpandRate = value;
295 } else if ([key isEqualToString:@"googCurrentDelayMs"]) {
296 _audioCurrentDelay = value;
297 }
hjon79858f82016-03-13 22:08:26 -0700298 }];
Zeke Chind3325802015-08-14 11:00:02 -0700299}
300
hbosbd3dda62016-09-09 01:36:28 -0700301- (void)parseVideoRecvStatsReport:(RTCLegacyStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700302 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
303 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700304 if ([key isEqualToString:@"googFrameHeightReceived"]) {
305 _videoRecvHeight = value;
306 } else if ([key isEqualToString:@"googFrameWidthReceived"]) {
307 _videoRecvWidth = value;
308 } else if ([key isEqualToString:@"googFrameRateReceived"]) {
309 _videoRecvFps = value;
310 } else if ([key isEqualToString:@"googFrameRateDecoded"]) {
311 _videoDecodedFps = value;
312 } else if ([key isEqualToString:@"googFrameRateOutput"]) {
313 _videoOutputFps = value;
314 } else if ([key isEqualToString:@"googDecodeMs"]) {
315 _videoDecodeMs = value;
316 } else if ([key isEqualToString:@"bytesReceived"]) {
317 NSInteger byteCount = value.integerValue;
318 [_videoRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
319 _videoRecvBitrate = _videoRecvBitrateTracker.bitrateString;
320 }
hjon79858f82016-03-13 22:08:26 -0700321 }];
Zeke Chind3325802015-08-14 11:00:02 -0700322}
323
324@end
325