OLD | NEW |
| (Empty) |
1 /* | |
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 | |
13 #import "WebRTC/RTCLegacyStatsReport.h" | |
14 | |
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:(RTCLegacyStatsReport *)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:(RTCLegacyStatsReport *)statsReport { | |
152 [statsReport.values enumerateKeysAndObjectsUsingBlock:^( | |
153 NSString *key, NSString *value, BOOL *stop) { | |
154 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 } | |
167 }]; | |
168 } | |
169 | |
170 - (void)parseConnectionStatsReport:(RTCLegacyStatsReport *)statsReport { | |
171 NSString *activeConnection = statsReport.values[@"googActiveConnection"]; | |
172 if (![activeConnection isEqualToString:@"true"]) { | |
173 return; | |
174 } | |
175 [statsReport.values enumerateKeysAndObjectsUsingBlock:^( | |
176 NSString *key, NSString *value, BOOL *stop) { | |
177 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 } | |
194 }]; | |
195 } | |
196 | |
197 - (void)parseSendSsrcStatsReport:(RTCLegacyStatsReport *)statsReport { | |
198 NSDictionary *values = statsReport.values; | |
199 if ([values objectForKey:@"googFrameRateSent"]) { | |
200 // Video track. | |
201 [self parseVideoSendStatsReport:statsReport]; | |
202 } else if ([values objectForKey:@"audioInputLevel"]) { | |
203 // Audio track. | |
204 [self parseAudioSendStatsReport:statsReport]; | |
205 } | |
206 } | |
207 | |
208 - (void)parseAudioSendStatsReport:(RTCLegacyStatsReport *)statsReport { | |
209 [statsReport.values enumerateKeysAndObjectsUsingBlock:^( | |
210 NSString *key, NSString *value, BOOL *stop) { | |
211 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 } | |
218 }]; | |
219 } | |
220 | |
221 - (void)parseVideoSendStatsReport:(RTCLegacyStatsReport *)statsReport { | |
222 [statsReport.values enumerateKeysAndObjectsUsingBlock:^( | |
223 NSString *key, NSString *value, BOOL *stop) { | |
224 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 } | |
245 }]; | |
246 } | |
247 | |
248 - (void)parseRecvSsrcStatsReport:(RTCLegacyStatsReport *)statsReport { | |
249 NSDictionary *values = statsReport.values; | |
250 if ([values objectForKey:@"googFrameWidthReceived"]) { | |
251 // Video track. | |
252 [self parseVideoRecvStatsReport:statsReport]; | |
253 } else if ([values objectForKey:@"audioOutputLevel"]) { | |
254 // Audio track. | |
255 [self parseAudioRecvStatsReport:statsReport]; | |
256 } | |
257 } | |
258 | |
259 - (void)parseAudioRecvStatsReport:(RTCLegacyStatsReport *)statsReport { | |
260 [statsReport.values enumerateKeysAndObjectsUsingBlock:^( | |
261 NSString *key, NSString *value, BOOL *stop) { | |
262 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 } | |
273 }]; | |
274 } | |
275 | |
276 - (void)parseVideoRecvStatsReport:(RTCLegacyStatsReport *)statsReport { | |
277 [statsReport.values enumerateKeysAndObjectsUsingBlock:^( | |
278 NSString *key, NSString *value, BOOL *stop) { | |
279 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 } | |
296 }]; | |
297 } | |
298 | |
299 @end | |
300 | |
OLD | NEW |