blob: 60cf5516488e6d0456fcbc7a8c4e5f06258c918e [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
hjon79858f82016-03-13 22:08:26 -070013#import "webrtc/api/objc/RTCStatsReport.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
132- (void)parseStatsReport:(RTCStatsReport *)statsReport {
133 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
151- (void)parseBweStatsReport:(RTCStatsReport *)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
170- (void)parseConnectionStatsReport:(RTCStatsReport *)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
197- (void)parseSendSsrcStatsReport:(RTCStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700198 NSDictionary *values = statsReport.values;
199 NSString *trackId = values[@"googTrackId"];
Zeke Chind3325802015-08-14 11:00:02 -0700200 if (trackId.length && [trackId hasPrefix:@"ARDAMSv0"]) {
201 // Video track.
202 [self parseVideoSendStatsReport:statsReport];
203 } else {
204 // Audio track.
205 [self parseAudioSendStatsReport:statsReport];
206 }
207}
208
209- (void)parseAudioSendStatsReport:(RTCStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700210 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
211 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700212 if ([key isEqualToString:@"googCodecName"]) {
213 _audioSendCodec = value;
214 } else if ([key isEqualToString:@"bytesSent"]) {
215 NSInteger byteCount = value.integerValue;
216 [_audioSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
217 _audioSendBitrate = _audioSendBitrateTracker.bitrateString;
218 }
hjon79858f82016-03-13 22:08:26 -0700219 }];
Zeke Chind3325802015-08-14 11:00:02 -0700220}
221
222- (void)parseVideoSendStatsReport:(RTCStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700223 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
224 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700225 if ([key isEqualToString:@"googCodecName"]) {
226 _videoSendCodec = value;
227 } else if ([key isEqualToString:@"googFrameHeightInput"]) {
228 _videoInputHeight = value;
229 } else if ([key isEqualToString:@"googFrameWidthInput"]) {
230 _videoInputWidth = value;
231 } else if ([key isEqualToString:@"googFrameRateInput"]) {
232 _videoInputFps = value;
233 } else if ([key isEqualToString:@"googFrameHeightSent"]) {
234 _videoSendHeight = value;
235 } else if ([key isEqualToString:@"googFrameWidthSent"]) {
236 _videoSendWidth = value;
237 } else if ([key isEqualToString:@"googFrameRateSent"]) {
238 _videoSendFps = value;
239 } else if ([key isEqualToString:@"googAvgEncodeMs"]) {
240 _videoEncodeMs = value;
241 } else if ([key isEqualToString:@"bytesSent"]) {
242 NSInteger byteCount = value.integerValue;
243 [_videoSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
244 _videoSendBitrate = _videoSendBitrateTracker.bitrateString;
245 }
hjon79858f82016-03-13 22:08:26 -0700246 }];
Zeke Chind3325802015-08-14 11:00:02 -0700247}
248
249- (void)parseRecvSsrcStatsReport:(RTCStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700250 NSDictionary *values = statsReport.values;
251 if (values[@"googFrameWidthReceived"]) {
Zeke Chind3325802015-08-14 11:00:02 -0700252 [self parseVideoRecvStatsReport:statsReport];
253 } else {
254 [self parseAudioRecvStatsReport:statsReport];
255 }
256}
257
258- (void)parseAudioRecvStatsReport:(RTCStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700259 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
260 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700261 if ([key isEqualToString:@"googCodecName"]) {
262 _audioRecvCodec = value;
263 } else if ([key isEqualToString:@"bytesReceived"]) {
264 NSInteger byteCount = value.integerValue;
265 [_audioRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
266 _audioRecvBitrate = _audioRecvBitrateTracker.bitrateString;
267 } else if ([key isEqualToString:@"googSpeechExpandRate"]) {
268 _audioExpandRate = value;
269 } else if ([key isEqualToString:@"googCurrentDelayMs"]) {
270 _audioCurrentDelay = value;
271 }
hjon79858f82016-03-13 22:08:26 -0700272 }];
Zeke Chind3325802015-08-14 11:00:02 -0700273}
274
275- (void)parseVideoRecvStatsReport:(RTCStatsReport *)statsReport {
hjon79858f82016-03-13 22:08:26 -0700276 [statsReport.values enumerateKeysAndObjectsUsingBlock:^(
277 NSString *key, NSString *value, BOOL *stop) {
Zeke Chind3325802015-08-14 11:00:02 -0700278 if ([key isEqualToString:@"googFrameHeightReceived"]) {
279 _videoRecvHeight = value;
280 } else if ([key isEqualToString:@"googFrameWidthReceived"]) {
281 _videoRecvWidth = value;
282 } else if ([key isEqualToString:@"googFrameRateReceived"]) {
283 _videoRecvFps = value;
284 } else if ([key isEqualToString:@"googFrameRateDecoded"]) {
285 _videoDecodedFps = value;
286 } else if ([key isEqualToString:@"googFrameRateOutput"]) {
287 _videoOutputFps = value;
288 } else if ([key isEqualToString:@"googDecodeMs"]) {
289 _videoDecodeMs = value;
290 } else if ([key isEqualToString:@"bytesReceived"]) {
291 NSInteger byteCount = value.integerValue;
292 [_videoRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount];
293 _videoRecvBitrate = _videoRecvBitrateTracker.bitrateString;
294 }
hjon79858f82016-03-13 22:08:26 -0700295 }];
Zeke Chind3325802015-08-14 11:00:02 -0700296}
297
298@end
299