| 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 |