blob: 013e83f2528b5ffe5e5aeb9a47ac8b7f28b2e100 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2012, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/app/webrtc/statscollector.h"
29
30#include <utility>
31#include <vector>
32
wu@webrtc.org4551b792013-10-09 15:37:36 +000033#include "talk/base/base64.h"
34#include "talk/base/scoped_ptr.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035#include "talk/session/media/channel.h"
36
37namespace webrtc {
38
39// The items below are in alphabetical order.
40const char StatsReport::kStatsValueNameActiveConnection[] =
41 "googActiveConnection";
42const char StatsReport::kStatsValueNameActualEncBitrate[] =
43 "googActualEncBitrate";
44const char StatsReport::kStatsValueNameAudioOutputLevel[] = "audioOutputLevel";
45const char StatsReport::kStatsValueNameAudioInputLevel[] = "audioInputLevel";
46const char StatsReport::kStatsValueNameAvailableReceiveBandwidth[] =
47 "googAvailableReceiveBandwidth";
48const char StatsReport::kStatsValueNameAvailableSendBandwidth[] =
49 "googAvailableSendBandwidth";
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +000050const char StatsReport::kStatsValueNameAvgEncodeMs[] = "googAvgEncodeMs";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051const char StatsReport::kStatsValueNameBucketDelay[] = "googBucketDelay";
52const char StatsReport::kStatsValueNameBytesReceived[] = "bytesReceived";
53const char StatsReport::kStatsValueNameBytesSent[] = "bytesSent";
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +000054const char StatsReport::kStatsValueNameBandwidthLimitedResolution[] =
55 "googBandwidthLimitedResolution";
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +000056const char StatsReport::kStatsValueNameCaptureJitterMs[] =
57 "googCaptureJitterMs";
wu@webrtc.org9caf2762013-12-11 18:25:07 +000058const char StatsReport::kStatsValueNameCaptureQueueDelayMsPerS[] =
59 "googCaptureQueueDelayMsPerS";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060const char StatsReport::kStatsValueNameChannelId[] = "googChannelId";
61const char StatsReport::kStatsValueNameCodecName[] = "googCodecName";
62const char StatsReport::kStatsValueNameComponent[] = "googComponent";
63const char StatsReport::kStatsValueNameContentName[] = "googContentName";
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +000064const char StatsReport::kStatsValueNameCpuLimitedResolution[] =
65 "googCpuLimitedResolution";
wu@webrtc.org4551b792013-10-09 15:37:36 +000066const char StatsReport::kStatsValueNameDer[] = "googDerBase64";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067// Echo metrics from the audio processing module.
68const char StatsReport::kStatsValueNameEchoCancellationQualityMin[] =
69 "googEchoCancellationQualityMin";
70const char StatsReport::kStatsValueNameEchoDelayMedian[] =
71 "googEchoCancellationEchoDelayMedian";
72const char StatsReport::kStatsValueNameEchoDelayStdDev[] =
73 "googEchoCancellationEchoDelayStdDev";
74const char StatsReport::kStatsValueNameEchoReturnLoss[] =
75 "googEchoCancellationReturnLoss";
76const char StatsReport::kStatsValueNameEchoReturnLossEnhancement[] =
77 "googEchoCancellationReturnLossEnhancement";
78
wu@webrtc.org9caf2762013-12-11 18:25:07 +000079const char StatsReport::kStatsValueNameEncodeUsagePercent[] =
80 "googEncodeUsagePercent";
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +000081const char StatsReport::kStatsValueNameExpandRate[] = "googExpandRate";
wu@webrtc.org4551b792013-10-09 15:37:36 +000082const char StatsReport::kStatsValueNameFingerprint[] = "googFingerprint";
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +000083const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
84 "googFingerprintAlgorithm";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
86const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
wu@webrtc.org987f2c92014-03-28 16:22:19 +000087const char StatsReport::kStatsValueNameFrameHeightInput[] =
88 "googFrameHeightInput";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089const char StatsReport::kStatsValueNameFrameHeightReceived[] =
90 "googFrameHeightReceived";
91const char StatsReport::kStatsValueNameFrameHeightSent[] =
92 "googFrameHeightSent";
93const char StatsReport::kStatsValueNameFrameRateReceived[] =
94 "googFrameRateReceived";
95const char StatsReport::kStatsValueNameFrameRateDecoded[] =
96 "googFrameRateDecoded";
97const char StatsReport::kStatsValueNameFrameRateOutput[] =
98 "googFrameRateOutput";
wu@webrtc.org97077a32013-10-25 21:18:33 +000099const char StatsReport::kStatsValueNameDecodeMs[] = "googDecodeMs";
100const char StatsReport::kStatsValueNameMaxDecodeMs[] = "googMaxDecodeMs";
101const char StatsReport::kStatsValueNameCurrentDelayMs[] = "googCurrentDelayMs";
102const char StatsReport::kStatsValueNameTargetDelayMs[] = "googTargetDelayMs";
103const char StatsReport::kStatsValueNameJitterBufferMs[] = "googJitterBufferMs";
104const char StatsReport::kStatsValueNameMinPlayoutDelayMs[] =
105 "googMinPlayoutDelayMs";
106const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
107
buildbot@webrtc.org0581f0b2014-05-06 21:36:31 +0000108const char StatsReport::kStatsValueNameCaptureStartNtpTimeMs[] =
109 "googCaptureStartNtpTimeMs";
110
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
112const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000113const char StatsReport::kStatsValueNameFrameWidthInput[] =
114 "googFrameWidthInput";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115const char StatsReport::kStatsValueNameFrameWidthReceived[] =
116 "googFrameWidthReceived";
117const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
118const char StatsReport::kStatsValueNameInitiator[] = "googInitiator";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000119const char StatsReport::kStatsValueNameIssuerId[] = "googIssuerId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120const char StatsReport::kStatsValueNameJitterReceived[] = "googJitterReceived";
121const char StatsReport::kStatsValueNameLocalAddress[] = "googLocalAddress";
wu@webrtc.org364f2042013-11-20 21:49:41 +0000122const char StatsReport::kStatsValueNameLocalCandidateType[] =
123 "googLocalCandidateType";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000124const char StatsReport::kStatsValueNameLocalCertificateId[] =
125 "googLocalCertificateId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
127const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000128const char StatsReport::kStatsValueNamePlisReceived[] = "googPlisReceived";
129const char StatsReport::kStatsValueNamePlisSent[] = "googPlisSent";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
131const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
132const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000133const char StatsReport::kStatsValueNamePreferredJitterBufferMs[] =
134 "googPreferredJitterBufferMs";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135const char StatsReport::kStatsValueNameReadable[] = "googReadable";
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000136const char StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug[] =
137 "googReceivedPacketGroupArrivalTimeDebug";
138const char StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug[] =
139 "googReceivedPacketGroupPropagationDeltaDebug";
140const char
141StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[] =
142 "googReceivedPacketGroupPropagationDeltaSumDebug";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
wu@webrtc.org364f2042013-11-20 21:49:41 +0000144const char StatsReport::kStatsValueNameRemoteCandidateType[] =
145 "googRemoteCandidateType";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000146const char StatsReport::kStatsValueNameRemoteCertificateId[] =
147 "googRemoteCertificateId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148const char StatsReport::kStatsValueNameRetransmitBitrate[] =
149 "googRetransmitBitrate";
150const char StatsReport::kStatsValueNameRtt[] = "googRtt";
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000151const char StatsReport::kStatsValueNameSsrc[] = "ssrc";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000152const char StatsReport::kStatsValueNameTargetEncBitrate[] =
153 "googTargetEncBitrate";
154const char StatsReport::kStatsValueNameTransmitBitrate[] =
155 "googTransmitBitrate";
156const char StatsReport::kStatsValueNameTransportId[] = "transportId";
157const char StatsReport::kStatsValueNameTransportType[] = "googTransportType";
158const char StatsReport::kStatsValueNameTrackId[] = "googTrackId";
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000159const char StatsReport::kStatsValueNameTypingNoiseState[] =
160 "googTypingNoiseState";
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000161const char StatsReport::kStatsValueNameViewLimitedResolution[] =
162 "googViewLimitedResolution";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163const char StatsReport::kStatsValueNameWritable[] = "googWritable";
164
165const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
166const char StatsReport::kStatsReportTypeBwe[] = "VideoBwe";
wu@webrtc.org97077a32013-10-25 21:18:33 +0000167const char StatsReport::kStatsReportTypeRemoteSsrc[] = "remoteSsrc";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000168const char StatsReport::kStatsReportTypeSsrc[] = "ssrc";
169const char StatsReport::kStatsReportTypeTrack[] = "googTrack";
170const char StatsReport::kStatsReportTypeIceCandidate[] = "iceCandidate";
171const char StatsReport::kStatsReportTypeTransport[] = "googTransport";
172const char StatsReport::kStatsReportTypeComponent[] = "googComponent";
173const char StatsReport::kStatsReportTypeCandidatePair[] = "googCandidatePair";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000174const char StatsReport::kStatsReportTypeCertificate[] = "googCertificate";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175
176const char StatsReport::kStatsReportVideoBweId[] = "bweforvideo";
177
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000178
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179// Implementations of functions in statstypes.h
180void StatsReport::AddValue(const std::string& name, const std::string& value) {
181 Value temp;
182 temp.name = name;
183 temp.value = value;
184 values.push_back(temp);
185}
186
187void StatsReport::AddValue(const std::string& name, int64 value) {
188 AddValue(name, talk_base::ToString<int64>(value));
189}
190
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000191template <typename T>
192void StatsReport::AddValue(const std::string& name,
193 const std::vector<T>& value) {
194 std::ostringstream oss;
195 oss << "[";
196 for (size_t i = 0; i < value.size(); ++i) {
197 oss << talk_base::ToString<T>(value[i]);
198 if (i != value.size() - 1)
199 oss << ", ";
200 }
201 oss << "]";
202 AddValue(name, oss.str());
203}
204
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000205void StatsReport::AddBoolean(const std::string& name, bool value) {
206 AddValue(name, value ? "true" : "false");
207}
208
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000209void StatsReport::ReplaceValue(const std::string& name,
210 const std::string& value) {
211 for (Values::iterator it = values.begin(); it != values.end(); ++it) {
212 if ((*it).name == name) {
213 it->value = value;
214 return;
215 }
216 }
217 // It is not reachable here, add an ASSERT to make sure the overwriting is
218 // always a success.
219 ASSERT(false);
220}
221
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000222namespace {
223typedef std::map<std::string, StatsReport> StatsMap;
224
225std::string StatsId(const std::string& type, const std::string& id) {
226 return type + "_" + id;
227}
228
229bool ExtractValueFromReport(
230 const StatsReport& report,
231 const std::string& name,
232 std::string* value) {
233 StatsReport::Values::const_iterator it = report.values.begin();
234 for (; it != report.values.end(); ++it) {
235 if (it->name == name) {
236 *value = it->value;
237 return true;
238 }
239 }
240 return false;
241}
242
243template <class TrackVector>
244void CreateTrackReports(const TrackVector& tracks, StatsMap* reports) {
245 for (size_t j = 0; j < tracks.size(); ++j) {
246 webrtc::MediaStreamTrackInterface* track = tracks[j];
247 // Adds an empty track report.
248 StatsReport report;
249 report.type = StatsReport::kStatsReportTypeTrack;
250 report.id = StatsId(StatsReport::kStatsReportTypeTrack, track->id());
251 report.AddValue(StatsReport::kStatsValueNameTrackId,
252 track->id());
253 (*reports)[report.id] = report;
254 }
255}
256
257void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
258 report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
259 info.audio_level);
260 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
261 info.bytes_rcvd);
262 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
263 info.jitter_ms);
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000264 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
265 info.jitter_buffer_ms);
266 report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
267 info.jitter_buffer_preferred_ms);
268 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
269 info.delay_estimate_ms);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000270 report->AddValue(StatsReport::kStatsValueNameExpandRate,
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000271 talk_base::ToString<float>(info.expand_rate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
273 info.packets_rcvd);
274 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
275 info.packets_lost);
276}
277
278void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
279 report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
280 info.audio_level);
281 report->AddValue(StatsReport::kStatsValueNameBytesSent,
282 info.bytes_sent);
283 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
284 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000285 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
286 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000287 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
288 info.jitter_ms);
289 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
290 report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
291 talk_base::ToString<float>(info.aec_quality_min));
292 report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
293 info.echo_delay_median_ms);
294 report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
295 info.echo_delay_std_ms);
296 report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
297 info.echo_return_loss);
298 report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
299 info.echo_return_loss_enhancement);
300 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000301 report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
302 info.typing_noise_detected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000303}
304
305void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
306 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
307 info.bytes_rcvd);
308 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
309 info.packets_rcvd);
310 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
311 info.packets_lost);
312
313 report->AddValue(StatsReport::kStatsValueNameFirsSent,
314 info.firs_sent);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000315 report->AddValue(StatsReport::kStatsValueNamePlisSent,
316 info.plis_sent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000317 report->AddValue(StatsReport::kStatsValueNameNacksSent,
318 info.nacks_sent);
319 report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
320 info.frame_width);
321 report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
322 info.frame_height);
323 report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
324 info.framerate_rcvd);
325 report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
326 info.framerate_decoded);
327 report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
328 info.framerate_output);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000329
330 report->AddValue(StatsReport::kStatsValueNameDecodeMs,
331 info.decode_ms);
332 report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
333 info.max_decode_ms);
334 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
335 info.current_delay_ms);
336 report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
337 info.target_delay_ms);
338 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
339 info.jitter_buffer_ms);
340 report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
341 info.min_playout_delay_ms);
342 report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
343 info.render_delay_ms);
buildbot@webrtc.org0581f0b2014-05-06 21:36:31 +0000344
345 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
346 info.capture_start_ntp_time_ms);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347}
348
349void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
350 report->AddValue(StatsReport::kStatsValueNameBytesSent,
351 info.bytes_sent);
352 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
353 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000354 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
355 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356
357 report->AddValue(StatsReport::kStatsValueNameFirsReceived,
358 info.firs_rcvd);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000359 report->AddValue(StatsReport::kStatsValueNamePlisReceived,
360 info.plis_rcvd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 report->AddValue(StatsReport::kStatsValueNameNacksReceived,
362 info.nacks_rcvd);
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000363 report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
364 info.input_frame_width);
365 report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
366 info.input_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000368 info.send_frame_width);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369 report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000370 info.send_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371 report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
372 info.framerate_input);
373 report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
374 info.framerate_sent);
375 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
376 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000377 report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
378 (info.adapt_reason & 0x1) > 0);
379 report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
380 (info.adapt_reason & 0x2) > 0);
381 report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
382 (info.adapt_reason & 0x4) > 0);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000383 report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
384 report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
385 info.capture_jitter_ms);
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000386 report->AddValue(StatsReport::kStatsValueNameCaptureQueueDelayMsPerS,
387 info.capture_queue_delay_ms_per_s);
388 report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
389 info.encode_usage_percent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390}
391
392void ExtractStats(const cricket::BandwidthEstimationInfo& info,
393 double stats_gathering_started,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000394 PeerConnectionInterface::StatsOutputLevel level,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395 StatsReport* report) {
396 report->id = StatsReport::kStatsReportVideoBweId;
397 report->type = StatsReport::kStatsReportTypeBwe;
398
399 // Clear out stats from previous GatherStats calls if any.
400 if (report->timestamp != stats_gathering_started) {
401 report->values.clear();
402 report->timestamp = stats_gathering_started;
403 }
404
405 report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
406 info.available_send_bandwidth);
407 report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
408 info.available_recv_bandwidth);
409 report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
410 info.target_enc_bitrate);
411 report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
412 info.actual_enc_bitrate);
413 report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
414 info.retransmit_bitrate);
415 report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
416 info.transmit_bitrate);
417 report->AddValue(StatsReport::kStatsValueNameBucketDelay,
418 info.bucket_delay);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000419 if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
420 report->AddValue(
421 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
422 info.total_received_propagation_delta_ms);
423 if (info.recent_received_propagation_delta_ms.size() > 0) {
424 report->AddValue(
425 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
426 info.recent_received_propagation_delta_ms);
427 report->AddValue(
428 StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
429 info.recent_received_packet_group_arrival_time_ms);
430 }
431 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432}
433
wu@webrtc.org97077a32013-10-25 21:18:33 +0000434void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
435 StatsReport* report) {
436 report->timestamp = info.remote_stats[0].timestamp;
437 // TODO(hta): Extract some stats here.
438}
439
440void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
441 StatsReport* report) {
442 report->timestamp = info.remote_stats[0].timestamp;
443 // TODO(hta): Extract some stats here.
444}
445
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446// Template to extract stats from a data vector.
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000447// In order to use the template, the functions that are called from it,
448// ExtractStats and ExtractRemoteStats, must be defined and overloaded
449// for each type.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450template<typename T>
451void ExtractStatsFromList(const std::vector<T>& data,
452 const std::string& transport_id,
453 StatsCollector* collector) {
454 typename std::vector<T>::const_iterator it = data.begin();
455 for (; it != data.end(); ++it) {
456 std::string id;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000457 uint32 ssrc = it->ssrc();
wu@webrtc.org97077a32013-10-25 21:18:33 +0000458 // Each object can result in 2 objects, a local and a remote object.
459 // TODO(hta): Handle the case of multiple SSRCs per object.
460 StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461 if (!report) {
462 continue;
463 }
464 ExtractStats(*it, report);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000465 if (it->remote_stats.size() > 0) {
466 report = collector->PrepareRemoteReport(ssrc, transport_id);
467 if (!report) {
468 continue;
469 }
470 ExtractRemoteStats(*it, report);
471 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000473}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474
475} // namespace
476
477StatsCollector::StatsCollector()
478 : session_(NULL), stats_gathering_started_(0) {
479}
480
481// Adds a MediaStream with tracks that can be used as a |selector| in a call
482// to GetStats.
483void StatsCollector::AddStream(MediaStreamInterface* stream) {
484 ASSERT(stream != NULL);
485
486 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
487 &reports_);
488 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
489 &reports_);
490}
491
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000492void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
493 uint32 ssrc) {
494 ASSERT(audio_track != NULL);
495#ifdef _DEBUG
496 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
497 it != local_audio_tracks_.end(); ++it) {
498 ASSERT(it->first != audio_track || it->second != ssrc);
499 }
500#endif
501 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
502}
503
504void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
505 uint32 ssrc) {
506 ASSERT(audio_track != NULL);
507 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
508 it != local_audio_tracks_.end(); ++it) {
509 if (it->first == audio_track && it->second == ssrc) {
510 local_audio_tracks_.erase(it);
511 return;
512 }
513 }
514
515 ASSERT(false);
516}
517
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
519 StatsReports* reports) {
520 ASSERT(reports != NULL);
521 reports->clear();
522
523 StatsMap::iterator it;
524 if (!track) {
525 for (it = reports_.begin(); it != reports_.end(); ++it) {
526 reports->push_back(it->second);
527 }
528 return true;
529 }
530
531 it = reports_.find(StatsId(StatsReport::kStatsReportTypeSession,
532 session_->id()));
533 if (it != reports_.end()) {
534 reports->push_back(it->second);
535 }
536
537 it = reports_.find(StatsId(StatsReport::kStatsReportTypeTrack, track->id()));
538
539 if (it == reports_.end()) {
540 LOG(LS_WARNING) << "No StatsReport is available for "<< track->id();
541 return false;
542 }
543
544 reports->push_back(it->second);
545
546 std::string track_id;
547 for (it = reports_.begin(); it != reports_.end(); ++it) {
548 if (it->second.type != StatsReport::kStatsReportTypeSsrc) {
549 continue;
550 }
551 if (ExtractValueFromReport(it->second,
552 StatsReport::kStatsValueNameTrackId,
553 &track_id)) {
554 if (track_id == track->id()) {
555 reports->push_back(it->second);
556 }
557 }
558 }
559
560 return true;
561}
562
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000563void
564StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 double time_now = GetTimeNow();
566 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
567 // ms apart will be ignored.
568 const double kMinGatherStatsPeriod = 50;
569 if (stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
570 return;
571 }
572 stats_gathering_started_ = time_now;
573
574 if (session_) {
575 ExtractSessionInfo();
576 ExtractVoiceInfo();
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000577 ExtractVideoInfo(level);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578 }
579}
580
wu@webrtc.org97077a32013-10-25 21:18:33 +0000581StatsReport* StatsCollector::PrepareLocalReport(
582 uint32 ssrc,
583 const std::string& transport_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
585 StatsMap::iterator it = reports_.find(StatsId(
586 StatsReport::kStatsReportTypeSsrc, ssrc_id));
587
588 std::string track_id;
589 if (it == reports_.end()) {
590 if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000591 LOG(LS_WARNING) << "The SSRC " << ssrc
592 << " is not associated with a track";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 return NULL;
594 }
595 } else {
596 // Keeps the old track id since we want to report the stats for inactive
597 // tracks.
598 ExtractValueFromReport(it->second,
599 StatsReport::kStatsValueNameTrackId,
600 &track_id);
601 }
602
wu@webrtc.org97077a32013-10-25 21:18:33 +0000603 StatsReport* report = GetOrCreateReport(StatsReport::kStatsReportTypeSsrc,
604 ssrc_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605
606 // Clear out stats from previous GatherStats calls if any.
607 if (report->timestamp != stats_gathering_started_) {
608 report->values.clear();
609 report->timestamp = stats_gathering_started_;
610 }
611
612 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
613 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
614 // Add the mapping of SSRC to transport.
615 report->AddValue(StatsReport::kStatsValueNameTransportId,
616 transport_id);
617 return report;
618}
619
wu@webrtc.org97077a32013-10-25 21:18:33 +0000620StatsReport* StatsCollector::PrepareRemoteReport(
621 uint32 ssrc,
622 const std::string& transport_id) {
623 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
624 StatsMap::iterator it = reports_.find(StatsId(
625 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id));
626
627 std::string track_id;
628 if (it == reports_.end()) {
629 if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
630 LOG(LS_WARNING) << "The SSRC " << ssrc
631 << " is not associated with a track";
632 return NULL;
633 }
634 } else {
635 // Keeps the old track id since we want to report the stats for inactive
636 // tracks.
637 ExtractValueFromReport(it->second,
638 StatsReport::kStatsValueNameTrackId,
639 &track_id);
640 }
641
642 StatsReport* report = GetOrCreateReport(
643 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id);
644
645 // Clear out stats from previous GatherStats calls if any.
646 // The timestamp will be added later. Zero it for debugging.
647 report->values.clear();
648 report->timestamp = 0;
649
650 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
651 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
652 // Add the mapping of SSRC to transport.
653 report->AddValue(StatsReport::kStatsValueNameTransportId,
654 transport_id);
655 return report;
656}
657
wu@webrtc.org4551b792013-10-09 15:37:36 +0000658std::string StatsCollector::AddOneCertificateReport(
659 const talk_base::SSLCertificate* cert, const std::string& issuer_id) {
660 // TODO(bemasc): Move this computation to a helper class that caches these
661 // values to reduce CPU use in GetStats. This will require adding a fast
662 // SSLCertificate::Equals() method to detect certificate changes.
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000663
664 std::string digest_algorithm;
665 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
666 return std::string();
667
wu@webrtc.org4551b792013-10-09 15:37:36 +0000668 talk_base::scoped_ptr<talk_base::SSLFingerprint> ssl_fingerprint(
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000669 talk_base::SSLFingerprint::Create(digest_algorithm, cert));
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000670
671 // SSLFingerprint::Create can fail if the algorithm returned by
672 // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
673 // implementation of SSLCertificate::ComputeDigest. This currently happens
674 // with MD5- and SHA-224-signed certificates when linked to libNSS.
675 if (!ssl_fingerprint)
676 return std::string();
677
wu@webrtc.org4551b792013-10-09 15:37:36 +0000678 std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
679
680 talk_base::Buffer der_buffer;
681 cert->ToDER(&der_buffer);
682 std::string der_base64;
683 talk_base::Base64::EncodeFromArray(
684 der_buffer.data(), der_buffer.length(), &der_base64);
685
686 StatsReport report;
687 report.type = StatsReport::kStatsReportTypeCertificate;
688 report.id = StatsId(report.type, fingerprint);
689 report.timestamp = stats_gathering_started_;
690 report.AddValue(StatsReport::kStatsValueNameFingerprint, fingerprint);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000691 report.AddValue(StatsReport::kStatsValueNameFingerprintAlgorithm,
692 digest_algorithm);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000693 report.AddValue(StatsReport::kStatsValueNameDer, der_base64);
694 if (!issuer_id.empty())
695 report.AddValue(StatsReport::kStatsValueNameIssuerId, issuer_id);
696 reports_[report.id] = report;
697 return report.id;
698}
699
700std::string StatsCollector::AddCertificateReports(
701 const talk_base::SSLCertificate* cert) {
702 // Produces a chain of StatsReports representing this certificate and the rest
703 // of its chain, and adds those reports to |reports_|. The return value is
704 // the id of the leaf report. The provided cert must be non-null, so at least
705 // one report will always be provided and the returned string will never be
706 // empty.
707 ASSERT(cert != NULL);
708
709 std::string issuer_id;
710 talk_base::scoped_ptr<talk_base::SSLCertChain> chain;
711 if (cert->GetChain(chain.accept())) {
712 // This loop runs in reverse, i.e. from root to leaf, so that each
713 // certificate's issuer's report ID is known before the child certificate's
714 // report is generated. The root certificate does not have an issuer ID
715 // value.
716 for (ptrdiff_t i = chain->GetSize() - 1; i >= 0; --i) {
717 const talk_base::SSLCertificate& cert_i = chain->Get(i);
718 issuer_id = AddOneCertificateReport(&cert_i, issuer_id);
719 }
720 }
721 // Add the leaf certificate.
722 return AddOneCertificateReport(cert, issuer_id);
723}
724
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000725void StatsCollector::ExtractSessionInfo() {
726 // Extract information from the base session.
727 StatsReport report;
728 report.id = StatsId(StatsReport::kStatsReportTypeSession, session_->id());
729 report.type = StatsReport::kStatsReportTypeSession;
730 report.timestamp = stats_gathering_started_;
731 report.values.clear();
732 report.AddBoolean(StatsReport::kStatsValueNameInitiator,
733 session_->initiator());
734
735 reports_[report.id] = report;
736
737 cricket::SessionStats stats;
738 if (session_->GetStats(&stats)) {
739 // Store the proxy map away for use in SSRC reporting.
740 proxy_to_transport_ = stats.proxy_to_transport;
741
742 for (cricket::TransportStatsMap::iterator transport_iter
743 = stats.transport_stats.begin();
744 transport_iter != stats.transport_stats.end(); ++transport_iter) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000745 // Attempt to get a copy of the certificates from the transport and
746 // expose them in stats reports. All channels in a transport share the
747 // same local and remote certificates.
748 std::string local_cert_report_id, remote_cert_report_id;
749 cricket::Transport* transport =
750 session_->GetTransport(transport_iter->second.content_name);
751 if (transport) {
752 talk_base::scoped_ptr<talk_base::SSLIdentity> identity;
753 if (transport->GetIdentity(identity.accept()))
754 local_cert_report_id = AddCertificateReports(
755 &(identity->certificate()));
756
757 talk_base::scoped_ptr<talk_base::SSLCertificate> cert;
758 if (transport->GetRemoteCertificate(cert.accept()))
759 remote_cert_report_id = AddCertificateReports(cert.get());
760 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 for (cricket::TransportChannelStatsList::iterator channel_iter
762 = transport_iter->second.channel_stats.begin();
763 channel_iter != transport_iter->second.channel_stats.end();
764 ++channel_iter) {
765 StatsReport channel_report;
766 std::ostringstream ostc;
767 ostc << "Channel-" << transport_iter->second.content_name
768 << "-" << channel_iter->component;
769 channel_report.id = ostc.str();
770 channel_report.type = StatsReport::kStatsReportTypeComponent;
771 channel_report.timestamp = stats_gathering_started_;
772 channel_report.AddValue(StatsReport::kStatsValueNameComponent,
773 channel_iter->component);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000774 if (!local_cert_report_id.empty())
775 channel_report.AddValue(
776 StatsReport::kStatsValueNameLocalCertificateId,
777 local_cert_report_id);
778 if (!remote_cert_report_id.empty())
779 channel_report.AddValue(
780 StatsReport::kStatsValueNameRemoteCertificateId,
781 remote_cert_report_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 reports_[channel_report.id] = channel_report;
783 for (size_t i = 0;
784 i < channel_iter->connection_infos.size();
785 ++i) {
786 StatsReport report;
787 const cricket::ConnectionInfo& info
788 = channel_iter->connection_infos[i];
789 std::ostringstream ost;
790 ost << "Conn-" << transport_iter->first << "-"
791 << channel_iter->component << "-" << i;
792 report.id = ost.str();
793 report.type = StatsReport::kStatsReportTypeCandidatePair;
794 report.timestamp = stats_gathering_started_;
795 // Link from connection to its containing channel.
796 report.AddValue(StatsReport::kStatsValueNameChannelId,
797 channel_report.id);
798 report.AddValue(StatsReport::kStatsValueNameBytesSent,
799 info.sent_total_bytes);
800 report.AddValue(StatsReport::kStatsValueNameBytesReceived,
801 info.recv_total_bytes);
802 report.AddBoolean(StatsReport::kStatsValueNameWritable,
803 info.writable);
804 report.AddBoolean(StatsReport::kStatsValueNameReadable,
805 info.readable);
806 report.AddBoolean(StatsReport::kStatsValueNameActiveConnection,
807 info.best_connection);
808 report.AddValue(StatsReport::kStatsValueNameLocalAddress,
809 info.local_candidate.address().ToString());
810 report.AddValue(StatsReport::kStatsValueNameRemoteAddress,
811 info.remote_candidate.address().ToString());
wu@webrtc.org97077a32013-10-25 21:18:33 +0000812 report.AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
813 report.AddValue(StatsReport::kStatsValueNameTransportType,
814 info.local_candidate.protocol());
wu@webrtc.org364f2042013-11-20 21:49:41 +0000815 report.AddValue(StatsReport::kStatsValueNameLocalCandidateType,
816 info.local_candidate.type());
817 report.AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
818 info.remote_candidate.type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 reports_[report.id] = report;
820 }
821 }
822 }
823 }
824}
825
826void StatsCollector::ExtractVoiceInfo() {
827 if (!session_->voice_channel()) {
828 return;
829 }
830 cricket::VoiceMediaInfo voice_info;
831 if (!session_->voice_channel()->GetStats(&voice_info)) {
832 LOG(LS_ERROR) << "Failed to get voice channel stats.";
833 return;
834 }
835 std::string transport_id;
836 if (!GetTransportIdFromProxy(session_->voice_channel()->content_name(),
837 &transport_id)) {
838 LOG(LS_ERROR) << "Failed to get transport name for proxy "
839 << session_->voice_channel()->content_name();
840 return;
841 }
842 ExtractStatsFromList(voice_info.receivers, transport_id, this);
843 ExtractStatsFromList(voice_info.senders, transport_id, this);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000844
845 UpdateStatsFromExistingLocalAudioTracks();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846}
847
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000848void StatsCollector::ExtractVideoInfo(
849 PeerConnectionInterface::StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 if (!session_->video_channel()) {
851 return;
852 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000853 cricket::StatsOptions options;
854 options.include_received_propagation_stats =
855 (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
856 true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857 cricket::VideoMediaInfo video_info;
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000858 if (!session_->video_channel()->GetStats(options, &video_info)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 LOG(LS_ERROR) << "Failed to get video channel stats.";
860 return;
861 }
862 std::string transport_id;
863 if (!GetTransportIdFromProxy(session_->video_channel()->content_name(),
864 &transport_id)) {
865 LOG(LS_ERROR) << "Failed to get transport name for proxy "
866 << session_->video_channel()->content_name();
867 return;
868 }
869 ExtractStatsFromList(video_info.receivers, transport_id, this);
870 ExtractStatsFromList(video_info.senders, transport_id, this);
871 if (video_info.bw_estimations.size() != 1) {
872 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
873 } else {
874 StatsReport* report = &reports_[StatsReport::kStatsReportVideoBweId];
875 ExtractStats(
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000876 video_info.bw_estimations[0], stats_gathering_started_, level, report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 }
878}
879
880double StatsCollector::GetTimeNow() {
881 return timing_.WallTimeNow() * talk_base::kNumMillisecsPerSec;
882}
883
884bool StatsCollector::GetTransportIdFromProxy(const std::string& proxy,
885 std::string* transport) {
886 // TODO(hta): Remove handling of empty proxy name once tests do not use it.
887 if (proxy.empty()) {
888 transport->clear();
889 return true;
890 }
891 if (proxy_to_transport_.find(proxy) == proxy_to_transport_.end()) {
892 LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
893 return false;
894 }
895 std::ostringstream ost;
896 // Component 1 is always used for RTP.
897 ost << "Channel-" << proxy_to_transport_[proxy] << "-1";
898 *transport = ost.str();
899 return true;
900}
901
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000902StatsReport* StatsCollector::GetReport(const std::string& type,
903 const std::string& id) {
wu@webrtc.org97077a32013-10-25 21:18:33 +0000904 std::string statsid = StatsId(type, id);
905 StatsReport* report = NULL;
906 std::map<std::string, StatsReport>::iterator it = reports_.find(statsid);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000907 if (it != reports_.end())
908 report = &(it->second);
909
910 return report;
911}
912
913StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
914 const std::string& id) {
915 StatsReport* report = GetReport(type, id);
916 if (report == NULL) {
917 std::string statsid = StatsId(type, id);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000918 report = &reports_[statsid]; // Create new element.
919 report->id = statsid;
920 report->type = type;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000921 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000922
wu@webrtc.org97077a32013-10-25 21:18:33 +0000923 return report;
924}
925
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000926void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
927 // Loop through the existing local audio tracks.
928 for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
929 it != local_audio_tracks_.end(); ++it) {
930 AudioTrackInterface* track = it->first;
931 uint32 ssrc = it->second;
932 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
933 StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
934 ssrc_id);
henrike@webrtc.orgd3d6bce2014-03-10 20:41:22 +0000935 if (report == NULL) {
936 // This can happen if a local audio track is added to a stream on the
937 // fly and the report has not been set up yet. Do nothing in this case.
938 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
939 continue;
940 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000941
942 // The same ssrc can be used by both local and remote audio tracks.
943 std::string track_id;
944 if (!ExtractValueFromReport(*report,
945 StatsReport::kStatsValueNameTrackId,
946 &track_id) ||
947 track_id != track->id()) {
948 continue;
949 }
950
951 UpdateReportFromAudioTrack(track, report);
952 }
953}
954
955void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
956 StatsReport* report) {
957 ASSERT(track != NULL);
958 if (report == NULL)
959 return;
960
961 int signal_level = 0;
962 if (track->GetSignalLevel(&signal_level)) {
963 report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
964 talk_base::ToString<int>(signal_level));
965 }
966
967 talk_base::scoped_refptr<AudioProcessorInterface> audio_processor(
968 track->GetAudioProcessor());
969 if (audio_processor.get() == NULL)
970 return;
971
972 AudioProcessorInterface::AudioProcessorStats stats;
973 audio_processor->GetStats(&stats);
974 report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
975 stats.typing_noise_detected ? "true" : "false");
976 report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
977 talk_base::ToString<int>(stats.echo_return_loss));
978 report->ReplaceValue(
979 StatsReport::kStatsValueNameEchoReturnLossEnhancement,
980 talk_base::ToString<int>(stats.echo_return_loss_enhancement));
981 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
982 talk_base::ToString<int>(stats.echo_delay_median_ms));
983 report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
984 talk_base::ToString<float>(stats.aec_quality_min));
985 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
986 talk_base::ToString<int>(stats.echo_delay_std_ms));
987}
988
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000989} // namespace webrtc