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 "RTCPair.h" | |
14 #import "RTCStatsReport.h" | |
15 | |
16 #import "ARDBitrateTracker.h" | |
17 #import "ARDUtilities.h" | |
18 | |
19 @implementation ARDStatsBuilder { | |
20 // Connection stats. | |
21 NSString *_connRecvBitrate; | |
22 NSString *_connRtt; | |
23 NSString *_connSendBitrate; | |
24 NSString *_localCandType; | |
25 NSString *_remoteCandType; | |
26 NSString *_transportType; | |
27 | |
28 // BWE stats. | |
29 NSString *_actualEncBitrate; | |
30 NSString *_availableRecvBw; | |
31 NSString *_availableSendBw; | |
32 NSString *_targetEncBitrate; | |
33 | |
34 // Video send stats. | |
35 NSString *_videoEncodeMs; | |
36 NSString *_videoInputFps; | |
37 NSString *_videoInputHeight; | |
38 NSString *_videoInputWidth; | |
39 NSString *_videoSendCodec; | |
40 NSString *_videoSendBitrate; | |
41 NSString *_videoSendFps; | |
42 NSString *_videoSendHeight; | |
43 NSString *_videoSendWidth; | |
44 | |
45 // Video receive stats. | |
46 NSString *_videoDecodeMs; | |
47 NSString *_videoDecodedFps; | |
48 NSString *_videoOutputFps; | |
49 NSString *_videoRecvBitrate; | |
50 NSString *_videoRecvFps; | |
51 NSString *_videoRecvHeight; | |
52 NSString *_videoRecvWidth; | |
53 | |
54 // Audio send stats. | |
55 NSString *_audioSendBitrate; | |
56 NSString *_audioSendCodec; | |
57 | |
58 // Audio receive stats. | |
59 NSString *_audioCurrentDelay; | |
60 NSString *_audioExpandRate; | |
61 NSString *_audioRecvBitrate; | |
62 NSString *_audioRecvCodec; | |
63 | |
64 // Bitrate trackers. | |
65 ARDBitrateTracker *_audioRecvBitrateTracker; | |
66 ARDBitrateTracker *_audioSendBitrateTracker; | |
67 ARDBitrateTracker *_connRecvBitrateTracker; | |
68 ARDBitrateTracker *_connSendBitrateTracker; | |
69 ARDBitrateTracker *_videoRecvBitrateTracker; | |
70 ARDBitrateTracker *_videoSendBitrateTracker; | |
71 } | |
72 | |
73 - (instancetype)init { | |
74 if (self = [super init]) { | |
75 _audioSendBitrateTracker = [[ARDBitrateTracker alloc] init]; | |
76 _audioRecvBitrateTracker = [[ARDBitrateTracker alloc] init]; | |
77 _connSendBitrateTracker = [[ARDBitrateTracker alloc] init]; | |
78 _connRecvBitrateTracker = [[ARDBitrateTracker alloc] init]; | |
79 _videoSendBitrateTracker = [[ARDBitrateTracker alloc] init]; | |
80 _videoRecvBitrateTracker = [[ARDBitrateTracker alloc] init]; | |
81 } | |
82 return self; | |
83 } | |
84 | |
85 - (NSString *)statsString { | |
86 NSMutableString *result = [NSMutableString string]; | |
87 // TODO(tkchin): CPU utilization. | |
jiayl2
2015/08/13 22:21:50
nit: make the TODO more clear about what's needed
tkchin_webrtc
2015/08/13 23:55:31
Nothing left, that was a TODO for myself in this C
| |
88 NSString *systemStatsFormat = @"(cpu)%ld%%\n"; | |
89 [result appendString:[NSString stringWithFormat:systemStatsFormat, | |
90 (long)ARDGetCpuUsagePercentage()]]; | |
91 | |
92 // Connection stats. | |
93 NSString *connStatsFormat = @"CN %@ms | %@->%@/%@ | (s)%@ | (r)%@\n"; | |
94 [result appendString:[NSString stringWithFormat:connStatsFormat, | |
95 _connRtt, | |
96 _localCandType, _remoteCandType, _transportType, | |
97 _connSendBitrate, _connRecvBitrate]]; | |
98 | |
99 // Video send stats. | |
100 NSString *videoSendFormat = @"VS (input) %@x%@@%@fps | (sent) %@x%@@%@fps\n" | |
101 "VS (enc) %@/%@ | (sent) %@/%@ | %@ms | %@\n"; | |
102 [result appendString:[NSString stringWithFormat:videoSendFormat, | |
103 _videoInputWidth, _videoInputHeight, _videoInputFps, | |
104 _videoSendWidth, _videoSendHeight, _videoSendFps, | |
105 _actualEncBitrate, _targetEncBitrate, | |
106 _videoSendBitrate, _availableSendBw, | |
107 _videoEncodeMs, | |
108 _videoSendCodec]]; | |
109 | |
110 // Video receive stats. | |
111 NSString *videoReceiveFormat = | |
112 @"VR (recv) %@x%@@%@fps | (decoded)%@ | (output)%@fps | %@/%@ | %@ms\n"; | |
113 [result appendString:[NSString stringWithFormat:videoReceiveFormat, | |
114 _videoRecvWidth, _videoRecvHeight, _videoRecvFps, | |
115 _videoDecodedFps, | |
116 _videoOutputFps, | |
117 _videoRecvBitrate, _availableRecvBw, | |
118 _videoDecodeMs]]; | |
119 | |
120 // Audio send stats. | |
121 NSString *audioSendFormat = @"AS %@ | %@\n"; | |
122 [result appendString:[NSString stringWithFormat:audioSendFormat, | |
123 _audioSendBitrate, _audioSendCodec]]; | |
124 | |
125 // Audio receive stats. | |
126 NSString *audioReceiveFormat = @"AR %@ | %@ | %@ms | (expandrate)%@"; | |
127 [result appendString:[NSString stringWithFormat:audioReceiveFormat, | |
128 _audioRecvBitrate, _audioRecvCodec, _audioCurrentDelay, | |
129 _audioExpandRate]]; | |
130 | |
131 return result; | |
132 } | |
133 | |
134 - (void)parseStatsReport:(RTCStatsReport *)statsReport { | |
135 NSString *reportType = statsReport.type; | |
136 if ([reportType isEqualToString:@"ssrc"] && | |
137 [statsReport.reportId rangeOfString:@"ssrc"].location != NSNotFound) { | |
138 if ([statsReport.reportId rangeOfString:@"send"].location != NSNotFound) { | |
139 [self parseSendSsrcStatsReport:statsReport]; | |
140 } | |
141 if ([statsReport.reportId rangeOfString:@"recv"].location != NSNotFound) { | |
142 [self parseRecvSsrcStatsReport:statsReport]; | |
143 } | |
144 } else if ([reportType isEqualToString:@"VideoBwe"]) { | |
145 [self parseBweStatsReport:statsReport]; | |
146 } else if ([reportType isEqualToString:@"googCandidatePair"]) { | |
147 [self parseConnectionStatsReport:statsReport]; | |
148 } | |
149 } | |
150 | |
151 #pragma mark - Private | |
152 | |
153 - (void)parseBweStatsReport:(RTCStatsReport *)statsReport { | |
154 for (RTCPair *pair in statsReport.values) { | |
155 NSString *key = pair.key; | |
156 NSString *value = pair.value; | |
157 if ([key isEqualToString:@"googAvailableSendBandwidth"]) { | |
158 _availableSendBw = | |
159 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; | |
160 } else if ([key isEqualToString:@"googAvailableReceiveBandwidth"]) { | |
161 _availableRecvBw = | |
162 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; | |
163 } else if ([key isEqualToString:@"googActualEncBitrate"]) { | |
164 _actualEncBitrate = | |
165 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; | |
166 } else if ([key isEqualToString:@"googTargetEncBitrate"]) { | |
167 _targetEncBitrate = | |
168 [ARDBitrateTracker bitrateStringForBitrate:value.doubleValue]; | |
169 } | |
170 } | |
171 } | |
172 | |
173 - (void)parseConnectionStatsReport:(RTCStatsReport *)statsReport { | |
174 for (RTCPair *pair in statsReport.values) { | |
175 NSString *key = pair.key; | |
176 NSString *value = pair.value; | |
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:(RTCStatsReport *)statsReport { | |
198 NSDictionary *values = [self dictionaryForReport:statsReport]; | |
199 NSString *trackId = [values[@"googTrackId"] firstObject]; | |
200 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 { | |
210 for (RTCPair *pair in statsReport.values) { | |
211 NSString *key = pair.key; | |
212 NSString *value = pair.value; | |
213 if ([key isEqualToString:@"googCodecName"]) { | |
214 _audioSendCodec = value; | |
215 } else if ([key isEqualToString:@"bytesSent"]) { | |
216 NSInteger byteCount = value.integerValue; | |
217 [_audioSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; | |
218 _audioSendBitrate = _audioSendBitrateTracker.bitrateString; | |
219 } | |
220 } | |
221 } | |
222 | |
223 - (void)parseVideoSendStatsReport:(RTCStatsReport *)statsReport { | |
224 for (RTCPair *pair in statsReport.values) { | |
225 NSString *key = pair.key; | |
226 NSString *value = pair.value; | |
227 if ([key isEqualToString:@"googCodecName"]) { | |
228 _videoSendCodec = value; | |
229 } else if ([key isEqualToString:@"googFrameHeightInput"]) { | |
230 _videoInputHeight = value; | |
231 } else if ([key isEqualToString:@"googFrameWidthInput"]) { | |
232 _videoInputWidth = value; | |
233 } else if ([key isEqualToString:@"googFrameRateInput"]) { | |
234 _videoInputFps = value; | |
235 } else if ([key isEqualToString:@"googFrameHeightSent"]) { | |
236 _videoSendHeight = value; | |
237 } else if ([key isEqualToString:@"googFrameWidthSent"]) { | |
238 _videoSendWidth = value; | |
239 } else if ([key isEqualToString:@"googFrameRateSent"]) { | |
240 _videoSendFps = value; | |
241 } else if ([key isEqualToString:@"googAvgEncodeMs"]) { | |
242 _videoEncodeMs = value; | |
243 } else if ([key isEqualToString:@"bytesSent"]) { | |
244 NSInteger byteCount = value.integerValue; | |
245 [_videoSendBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; | |
246 _videoSendBitrate = _videoSendBitrateTracker.bitrateString; | |
247 } | |
248 } | |
249 } | |
250 | |
251 - (void)parseRecvSsrcStatsReport:(RTCStatsReport *)statsReport { | |
252 NSDictionary *values = [self dictionaryForReport:statsReport]; | |
253 NSString *transportId = [values[@"transportId"] firstObject]; | |
254 if ([values[@"googFrameWidthReceived"] firstObject]) { | |
255 [self parseVideoRecvStatsReport:statsReport]; | |
256 } else { | |
257 [self parseAudioRecvStatsReport:statsReport]; | |
258 } | |
259 } | |
260 | |
261 - (void)parseAudioRecvStatsReport:(RTCStatsReport *)statsReport { | |
262 for (RTCPair *pair in statsReport.values) { | |
263 NSString *key = pair.key; | |
264 NSString *value = pair.value; | |
265 if ([key isEqualToString:@"googCodecName"]) { | |
266 _audioRecvCodec = value; | |
267 } else if ([key isEqualToString:@"bytesReceived"]) { | |
268 NSInteger byteCount = value.integerValue; | |
269 [_audioRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; | |
270 _audioRecvBitrate = _audioRecvBitrateTracker.bitrateString; | |
271 } else if ([key isEqualToString:@"googSpeechExpandRate"]) { | |
272 _audioExpandRate = value; | |
273 } else if ([key isEqualToString:@"googCurrentDelayMs"]) { | |
274 _audioCurrentDelay = value; | |
275 } | |
276 } | |
277 } | |
278 | |
279 - (void)parseVideoRecvStatsReport:(RTCStatsReport *)statsReport { | |
280 for (RTCPair *pair in statsReport.values) { | |
281 NSString *key = pair.key; | |
282 NSString *value = pair.value; | |
283 if ([key isEqualToString:@"googFrameHeightReceived"]) { | |
284 _videoRecvHeight = value; | |
285 } else if ([key isEqualToString:@"googFrameWidthReceived"]) { | |
286 _videoRecvWidth = value; | |
287 } else if ([key isEqualToString:@"googFrameRateReceived"]) { | |
288 _videoRecvFps = value; | |
289 } else if ([key isEqualToString:@"googFrameRateDecoded"]) { | |
290 _videoDecodedFps = value; | |
291 } else if ([key isEqualToString:@"googFrameRateOutput"]) { | |
292 _videoOutputFps = value; | |
293 } else if ([key isEqualToString:@"googDecodeMs"]) { | |
294 _videoDecodeMs = value; | |
295 } else if ([key isEqualToString:@"bytesReceived"]) { | |
296 NSInteger byteCount = value.integerValue; | |
297 [_videoRecvBitrateTracker updateBitrateWithCurrentByteCount:byteCount]; | |
298 _videoRecvBitrate = _videoRecvBitrateTracker.bitrateString; | |
299 } | |
300 } | |
301 } | |
302 | |
303 - (NSDictionary *)dictionaryForReport:(RTCStatsReport *)statsReport { | |
304 NSMutableDictionary *dict = [NSMutableDictionary dictionary]; | |
305 for (RTCPair *pair in statsReport.values) { | |
306 NSMutableArray *values = dict[pair.key]; | |
307 if (!values) { | |
308 values = [NSMutableArray arrayWithCapacity:1]; | |
309 dict[pair.key] = values; | |
310 } | |
311 [values addObject:pair.value]; | |
312 } | |
313 return dict; | |
314 } | |
315 | |
316 @end | |
317 | |
OLD | NEW |