blob: 86a88c159fa851f18bbf1b79e0f3ac0a29559700 [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";
buildbot@webrtc.org3e01e0b2014-05-13 17:54:10 +000066const char StatsReport::kStatsValueNameDecodingCTSG[] =
67 "googDecodingCTSG";
68const char StatsReport::kStatsValueNameDecodingCTN[] =
69 "googDecodingCTN";
70const char StatsReport::kStatsValueNameDecodingNormal[] =
71 "googDecodingNormal";
72const char StatsReport::kStatsValueNameDecodingPLC[] =
73 "googDecodingPLC";
74const char StatsReport::kStatsValueNameDecodingCNG[] =
75 "googDecodingCNG";
76const char StatsReport::kStatsValueNameDecodingPLCCNG[] =
77 "googDecodingPLCCNG";
wu@webrtc.org4551b792013-10-09 15:37:36 +000078const char StatsReport::kStatsValueNameDer[] = "googDerBase64";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079// Echo metrics from the audio processing module.
80const char StatsReport::kStatsValueNameEchoCancellationQualityMin[] =
81 "googEchoCancellationQualityMin";
82const char StatsReport::kStatsValueNameEchoDelayMedian[] =
83 "googEchoCancellationEchoDelayMedian";
84const char StatsReport::kStatsValueNameEchoDelayStdDev[] =
85 "googEchoCancellationEchoDelayStdDev";
86const char StatsReport::kStatsValueNameEchoReturnLoss[] =
87 "googEchoCancellationReturnLoss";
88const char StatsReport::kStatsValueNameEchoReturnLossEnhancement[] =
89 "googEchoCancellationReturnLossEnhancement";
90
buildbot@webrtc.orgc800c1c2014-06-13 07:56:17 +000091const char StatsReport::kStatsValueNameEncodeRelStdDev[] =
92 "googEncodeRelStdDev";
wu@webrtc.org9caf2762013-12-11 18:25:07 +000093const char StatsReport::kStatsValueNameEncodeUsagePercent[] =
94 "googEncodeUsagePercent";
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +000095const char StatsReport::kStatsValueNameExpandRate[] = "googExpandRate";
wu@webrtc.org4551b792013-10-09 15:37:36 +000096const char StatsReport::kStatsValueNameFingerprint[] = "googFingerprint";
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +000097const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
98 "googFingerprintAlgorithm";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
100const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000101const char StatsReport::kStatsValueNameFrameHeightInput[] =
102 "googFrameHeightInput";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103const char StatsReport::kStatsValueNameFrameHeightReceived[] =
104 "googFrameHeightReceived";
105const char StatsReport::kStatsValueNameFrameHeightSent[] =
106 "googFrameHeightSent";
107const char StatsReport::kStatsValueNameFrameRateReceived[] =
108 "googFrameRateReceived";
109const char StatsReport::kStatsValueNameFrameRateDecoded[] =
110 "googFrameRateDecoded";
111const char StatsReport::kStatsValueNameFrameRateOutput[] =
112 "googFrameRateOutput";
wu@webrtc.org97077a32013-10-25 21:18:33 +0000113const char StatsReport::kStatsValueNameDecodeMs[] = "googDecodeMs";
114const char StatsReport::kStatsValueNameMaxDecodeMs[] = "googMaxDecodeMs";
115const char StatsReport::kStatsValueNameCurrentDelayMs[] = "googCurrentDelayMs";
116const char StatsReport::kStatsValueNameTargetDelayMs[] = "googTargetDelayMs";
117const char StatsReport::kStatsValueNameJitterBufferMs[] = "googJitterBufferMs";
118const char StatsReport::kStatsValueNameMinPlayoutDelayMs[] =
119 "googMinPlayoutDelayMs";
120const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
121
buildbot@webrtc.org0581f0b2014-05-06 21:36:31 +0000122const char StatsReport::kStatsValueNameCaptureStartNtpTimeMs[] =
123 "googCaptureStartNtpTimeMs";
124
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
126const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000127const char StatsReport::kStatsValueNameFrameWidthInput[] =
128 "googFrameWidthInput";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000129const char StatsReport::kStatsValueNameFrameWidthReceived[] =
130 "googFrameWidthReceived";
131const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
132const char StatsReport::kStatsValueNameInitiator[] = "googInitiator";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000133const char StatsReport::kStatsValueNameIssuerId[] = "googIssuerId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134const char StatsReport::kStatsValueNameJitterReceived[] = "googJitterReceived";
135const char StatsReport::kStatsValueNameLocalAddress[] = "googLocalAddress";
wu@webrtc.org364f2042013-11-20 21:49:41 +0000136const char StatsReport::kStatsValueNameLocalCandidateType[] =
137 "googLocalCandidateType";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000138const char StatsReport::kStatsValueNameLocalCertificateId[] =
139 "googLocalCertificateId";
buildbot@webrtc.org71dffb72014-06-24 07:24:49 +0000140const char StatsReport::kStatsValueNameAdaptationChanges[] =
141 "googAdaptationChanges";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
143const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000144const char StatsReport::kStatsValueNamePlisReceived[] = "googPlisReceived";
145const char StatsReport::kStatsValueNamePlisSent[] = "googPlisSent";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
147const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
148const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000149const char StatsReport::kStatsValueNamePreferredJitterBufferMs[] =
150 "googPreferredJitterBufferMs";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151const char StatsReport::kStatsValueNameReadable[] = "googReadable";
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000152const char StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug[] =
153 "googReceivedPacketGroupArrivalTimeDebug";
154const char StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug[] =
155 "googReceivedPacketGroupPropagationDeltaDebug";
156const char
157StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[] =
158 "googReceivedPacketGroupPropagationDeltaSumDebug";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
wu@webrtc.org364f2042013-11-20 21:49:41 +0000160const char StatsReport::kStatsValueNameRemoteCandidateType[] =
161 "googRemoteCandidateType";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000162const char StatsReport::kStatsValueNameRemoteCertificateId[] =
163 "googRemoteCertificateId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164const char StatsReport::kStatsValueNameRetransmitBitrate[] =
165 "googRetransmitBitrate";
166const char StatsReport::kStatsValueNameRtt[] = "googRtt";
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000167const char StatsReport::kStatsValueNameSsrc[] = "ssrc";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000168const char StatsReport::kStatsValueNameTargetEncBitrate[] =
169 "googTargetEncBitrate";
170const char StatsReport::kStatsValueNameTransmitBitrate[] =
171 "googTransmitBitrate";
172const char StatsReport::kStatsValueNameTransportId[] = "transportId";
173const char StatsReport::kStatsValueNameTransportType[] = "googTransportType";
174const char StatsReport::kStatsValueNameTrackId[] = "googTrackId";
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000175const char StatsReport::kStatsValueNameTypingNoiseState[] =
176 "googTypingNoiseState";
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000177const char StatsReport::kStatsValueNameViewLimitedResolution[] =
178 "googViewLimitedResolution";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179const char StatsReport::kStatsValueNameWritable[] = "googWritable";
180
181const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
182const char StatsReport::kStatsReportTypeBwe[] = "VideoBwe";
wu@webrtc.org97077a32013-10-25 21:18:33 +0000183const char StatsReport::kStatsReportTypeRemoteSsrc[] = "remoteSsrc";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184const char StatsReport::kStatsReportTypeSsrc[] = "ssrc";
185const char StatsReport::kStatsReportTypeTrack[] = "googTrack";
186const char StatsReport::kStatsReportTypeIceCandidate[] = "iceCandidate";
187const char StatsReport::kStatsReportTypeTransport[] = "googTransport";
188const char StatsReport::kStatsReportTypeComponent[] = "googComponent";
189const char StatsReport::kStatsReportTypeCandidatePair[] = "googCandidatePair";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000190const char StatsReport::kStatsReportTypeCertificate[] = "googCertificate";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000191
192const char StatsReport::kStatsReportVideoBweId[] = "bweforvideo";
193
194// Implementations of functions in statstypes.h
195void StatsReport::AddValue(const std::string& name, const std::string& value) {
196 Value temp;
197 temp.name = name;
198 temp.value = value;
199 values.push_back(temp);
200}
201
202void StatsReport::AddValue(const std::string& name, int64 value) {
203 AddValue(name, talk_base::ToString<int64>(value));
204}
205
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000206template <typename T>
207void StatsReport::AddValue(const std::string& name,
208 const std::vector<T>& value) {
209 std::ostringstream oss;
210 oss << "[";
211 for (size_t i = 0; i < value.size(); ++i) {
212 oss << talk_base::ToString<T>(value[i]);
213 if (i != value.size() - 1)
214 oss << ", ";
215 }
216 oss << "]";
217 AddValue(name, oss.str());
218}
219
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220void StatsReport::AddBoolean(const std::string& name, bool value) {
221 AddValue(name, value ? "true" : "false");
222}
223
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000224void StatsReport::ReplaceValue(const std::string& name,
225 const std::string& value) {
226 for (Values::iterator it = values.begin(); it != values.end(); ++it) {
227 if ((*it).name == name) {
228 it->value = value;
229 return;
230 }
231 }
232 // It is not reachable here, add an ASSERT to make sure the overwriting is
233 // always a success.
234 ASSERT(false);
235}
236
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000237namespace {
238typedef std::map<std::string, StatsReport> StatsMap;
239
240std::string StatsId(const std::string& type, const std::string& id) {
241 return type + "_" + id;
242}
243
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000244std::string StatsId(const std::string& type, const std::string& id,
245 StatsCollector::TrackDirection direction) {
246 ASSERT(direction == StatsCollector::kSending ||
247 direction == StatsCollector::kReceiving);
248
249 // Strings for the direction of the track.
250 const char kSendDirection[] = "send";
251 const char kRecvDirection[] = "recv";
252
253 const std::string direction_id = (direction == StatsCollector::kSending) ?
254 kSendDirection : kRecvDirection;
255 return type + "_" + id + "_" + direction_id;
256}
257
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258bool ExtractValueFromReport(
259 const StatsReport& report,
260 const std::string& name,
261 std::string* value) {
262 StatsReport::Values::const_iterator it = report.values.begin();
263 for (; it != report.values.end(); ++it) {
264 if (it->name == name) {
265 *value = it->value;
266 return true;
267 }
268 }
269 return false;
270}
271
272template <class TrackVector>
273void CreateTrackReports(const TrackVector& tracks, StatsMap* reports) {
274 for (size_t j = 0; j < tracks.size(); ++j) {
275 webrtc::MediaStreamTrackInterface* track = tracks[j];
276 // Adds an empty track report.
277 StatsReport report;
278 report.type = StatsReport::kStatsReportTypeTrack;
279 report.id = StatsId(StatsReport::kStatsReportTypeTrack, track->id());
280 report.AddValue(StatsReport::kStatsValueNameTrackId,
281 track->id());
282 (*reports)[report.id] = report;
283 }
284}
285
286void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
287 report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
288 info.audio_level);
289 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
290 info.bytes_rcvd);
291 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
292 info.jitter_ms);
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000293 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
294 info.jitter_buffer_ms);
295 report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
296 info.jitter_buffer_preferred_ms);
297 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
298 info.delay_estimate_ms);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000299 report->AddValue(StatsReport::kStatsValueNameExpandRate,
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000300 talk_base::ToString<float>(info.expand_rate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
302 info.packets_rcvd);
303 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
304 info.packets_lost);
buildbot@webrtc.org3e01e0b2014-05-13 17:54:10 +0000305 report->AddValue(StatsReport::kStatsValueNameDecodingCTSG,
306 info.decoding_calls_to_silence_generator);
307 report->AddValue(StatsReport::kStatsValueNameDecodingCTN,
308 info.decoding_calls_to_neteq);
309 report->AddValue(StatsReport::kStatsValueNameDecodingNormal,
310 info.decoding_normal);
311 report->AddValue(StatsReport::kStatsValueNameDecodingPLC,
312 info.decoding_plc);
313 report->AddValue(StatsReport::kStatsValueNameDecodingCNG,
314 info.decoding_cng);
315 report->AddValue(StatsReport::kStatsValueNameDecodingPLCCNG,
316 info.decoding_plc_cng);
buildbot@webrtc.orgb525a9d2014-06-03 09:42:15 +0000317 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
318 info.capture_start_ntp_time_ms);
buildbot@webrtc.org7e71b772014-06-13 01:14:01 +0000319 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320}
321
322void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
323 report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
324 info.audio_level);
325 report->AddValue(StatsReport::kStatsValueNameBytesSent,
326 info.bytes_sent);
327 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
328 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000329 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
330 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
332 info.jitter_ms);
333 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
334 report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
335 talk_base::ToString<float>(info.aec_quality_min));
336 report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
337 info.echo_delay_median_ms);
338 report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
339 info.echo_delay_std_ms);
340 report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
341 info.echo_return_loss);
342 report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
343 info.echo_return_loss_enhancement);
344 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000345 report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
346 info.typing_noise_detected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347}
348
349void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
350 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
351 info.bytes_rcvd);
352 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
353 info.packets_rcvd);
354 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
355 info.packets_lost);
356
357 report->AddValue(StatsReport::kStatsValueNameFirsSent,
358 info.firs_sent);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000359 report->AddValue(StatsReport::kStatsValueNamePlisSent,
360 info.plis_sent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 report->AddValue(StatsReport::kStatsValueNameNacksSent,
362 info.nacks_sent);
363 report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
364 info.frame_width);
365 report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
366 info.frame_height);
367 report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
368 info.framerate_rcvd);
369 report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
370 info.framerate_decoded);
371 report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
372 info.framerate_output);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000373
374 report->AddValue(StatsReport::kStatsValueNameDecodeMs,
375 info.decode_ms);
376 report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
377 info.max_decode_ms);
378 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
379 info.current_delay_ms);
380 report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
381 info.target_delay_ms);
382 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
383 info.jitter_buffer_ms);
384 report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
385 info.min_playout_delay_ms);
386 report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
387 info.render_delay_ms);
buildbot@webrtc.org0581f0b2014-05-06 21:36:31 +0000388
389 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
390 info.capture_start_ntp_time_ms);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391}
392
393void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
394 report->AddValue(StatsReport::kStatsValueNameBytesSent,
395 info.bytes_sent);
396 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
397 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000398 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
399 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000400
401 report->AddValue(StatsReport::kStatsValueNameFirsReceived,
402 info.firs_rcvd);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000403 report->AddValue(StatsReport::kStatsValueNamePlisReceived,
404 info.plis_rcvd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000405 report->AddValue(StatsReport::kStatsValueNameNacksReceived,
406 info.nacks_rcvd);
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000407 report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
408 info.input_frame_width);
409 report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
410 info.input_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000412 info.send_frame_width);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413 report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000414 info.send_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
416 info.framerate_input);
417 report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
418 info.framerate_sent);
419 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
420 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000421 report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
422 (info.adapt_reason & 0x1) > 0);
423 report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
424 (info.adapt_reason & 0x2) > 0);
425 report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
426 (info.adapt_reason & 0x4) > 0);
buildbot@webrtc.org71dffb72014-06-24 07:24:49 +0000427 report->AddValue(StatsReport::kStatsValueNameAdaptationChanges,
428 info.adapt_changes);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000429 report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
430 report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
431 info.capture_jitter_ms);
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000432 report->AddValue(StatsReport::kStatsValueNameCaptureQueueDelayMsPerS,
433 info.capture_queue_delay_ms_per_s);
434 report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
435 info.encode_usage_percent);
buildbot@webrtc.orgc800c1c2014-06-13 07:56:17 +0000436 report->AddValue(StatsReport::kStatsValueNameEncodeRelStdDev,
437 info.encode_rsd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438}
439
440void ExtractStats(const cricket::BandwidthEstimationInfo& info,
441 double stats_gathering_started,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000442 PeerConnectionInterface::StatsOutputLevel level,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443 StatsReport* report) {
444 report->id = StatsReport::kStatsReportVideoBweId;
445 report->type = StatsReport::kStatsReportTypeBwe;
446
447 // Clear out stats from previous GatherStats calls if any.
448 if (report->timestamp != stats_gathering_started) {
449 report->values.clear();
450 report->timestamp = stats_gathering_started;
451 }
452
453 report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
454 info.available_send_bandwidth);
455 report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
456 info.available_recv_bandwidth);
457 report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
458 info.target_enc_bitrate);
459 report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
460 info.actual_enc_bitrate);
461 report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
462 info.retransmit_bitrate);
463 report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
464 info.transmit_bitrate);
465 report->AddValue(StatsReport::kStatsValueNameBucketDelay,
466 info.bucket_delay);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000467 if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
468 report->AddValue(
469 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
470 info.total_received_propagation_delta_ms);
471 if (info.recent_received_propagation_delta_ms.size() > 0) {
472 report->AddValue(
473 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
474 info.recent_received_propagation_delta_ms);
475 report->AddValue(
476 StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
477 info.recent_received_packet_group_arrival_time_ms);
478 }
479 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480}
481
wu@webrtc.org97077a32013-10-25 21:18:33 +0000482void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
483 StatsReport* report) {
484 report->timestamp = info.remote_stats[0].timestamp;
485 // TODO(hta): Extract some stats here.
486}
487
488void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
489 StatsReport* report) {
490 report->timestamp = info.remote_stats[0].timestamp;
491 // TODO(hta): Extract some stats here.
492}
493
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494// Template to extract stats from a data vector.
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000495// In order to use the template, the functions that are called from it,
496// ExtractStats and ExtractRemoteStats, must be defined and overloaded
497// for each type.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498template<typename T>
499void ExtractStatsFromList(const std::vector<T>& data,
500 const std::string& transport_id,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000501 StatsCollector* collector,
502 StatsCollector::TrackDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503 typename std::vector<T>::const_iterator it = data.begin();
504 for (; it != data.end(); ++it) {
505 std::string id;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000506 uint32 ssrc = it->ssrc();
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000507 // Each track can have stats for both local and remote objects.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000508 // TODO(hta): Handle the case of multiple SSRCs per object.
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000509 StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id,
510 direction);
511 if (report)
512 ExtractStats(*it, report);
513
wu@webrtc.org97077a32013-10-25 21:18:33 +0000514 if (it->remote_stats.size() > 0) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000515 report = collector->PrepareRemoteReport(ssrc, transport_id,
516 direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000517 if (!report) {
518 continue;
519 }
520 ExtractRemoteStats(*it, report);
521 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000523}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000524
525} // namespace
526
527StatsCollector::StatsCollector()
528 : session_(NULL), stats_gathering_started_(0) {
529}
530
531// Adds a MediaStream with tracks that can be used as a |selector| in a call
532// to GetStats.
533void StatsCollector::AddStream(MediaStreamInterface* stream) {
534 ASSERT(stream != NULL);
535
536 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
537 &reports_);
538 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
539 &reports_);
540}
541
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000542void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
543 uint32 ssrc) {
544 ASSERT(audio_track != NULL);
545#ifdef _DEBUG
546 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
547 it != local_audio_tracks_.end(); ++it) {
548 ASSERT(it->first != audio_track || it->second != ssrc);
549 }
550#endif
551 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
552}
553
554void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
555 uint32 ssrc) {
556 ASSERT(audio_track != NULL);
557 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
558 it != local_audio_tracks_.end(); ++it) {
559 if (it->first == audio_track && it->second == ssrc) {
560 local_audio_tracks_.erase(it);
561 return;
562 }
563 }
564
565 ASSERT(false);
566}
567
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
569 StatsReports* reports) {
570 ASSERT(reports != NULL);
571 reports->clear();
572
573 StatsMap::iterator it;
574 if (!track) {
575 for (it = reports_.begin(); it != reports_.end(); ++it) {
576 reports->push_back(it->second);
577 }
578 return true;
579 }
580
581 it = reports_.find(StatsId(StatsReport::kStatsReportTypeSession,
582 session_->id()));
583 if (it != reports_.end()) {
584 reports->push_back(it->second);
585 }
586
587 it = reports_.find(StatsId(StatsReport::kStatsReportTypeTrack, track->id()));
588
589 if (it == reports_.end()) {
590 LOG(LS_WARNING) << "No StatsReport is available for "<< track->id();
591 return false;
592 }
593
594 reports->push_back(it->second);
595
596 std::string track_id;
597 for (it = reports_.begin(); it != reports_.end(); ++it) {
598 if (it->second.type != StatsReport::kStatsReportTypeSsrc) {
599 continue;
600 }
601 if (ExtractValueFromReport(it->second,
602 StatsReport::kStatsValueNameTrackId,
603 &track_id)) {
604 if (track_id == track->id()) {
605 reports->push_back(it->second);
606 }
607 }
608 }
609
610 return true;
611}
612
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000613void
614StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 double time_now = GetTimeNow();
616 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
617 // ms apart will be ignored.
618 const double kMinGatherStatsPeriod = 50;
619 if (stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
620 return;
621 }
622 stats_gathering_started_ = time_now;
623
624 if (session_) {
625 ExtractSessionInfo();
626 ExtractVoiceInfo();
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000627 ExtractVideoInfo(level);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 }
629}
630
wu@webrtc.org97077a32013-10-25 21:18:33 +0000631StatsReport* StatsCollector::PrepareLocalReport(
632 uint32 ssrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000633 const std::string& transport_id,
634 TrackDirection direction) {
635 const std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 StatsMap::iterator it = reports_.find(StatsId(
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000637 StatsReport::kStatsReportTypeSsrc, ssrc_id, direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638
639 std::string track_id;
640 if (it == reports_.end()) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000641 if (!GetTrackIdBySsrc(ssrc, &track_id, direction))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 return NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 } else {
644 // Keeps the old track id since we want to report the stats for inactive
645 // tracks.
646 ExtractValueFromReport(it->second,
647 StatsReport::kStatsValueNameTrackId,
648 &track_id);
649 }
650
wu@webrtc.org97077a32013-10-25 21:18:33 +0000651 StatsReport* report = GetOrCreateReport(StatsReport::kStatsReportTypeSsrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000652 ssrc_id, direction);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653
654 // Clear out stats from previous GatherStats calls if any.
655 if (report->timestamp != stats_gathering_started_) {
656 report->values.clear();
657 report->timestamp = stats_gathering_started_;
658 }
659
660 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
661 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
662 // Add the mapping of SSRC to transport.
663 report->AddValue(StatsReport::kStatsValueNameTransportId,
664 transport_id);
665 return report;
666}
667
wu@webrtc.org97077a32013-10-25 21:18:33 +0000668StatsReport* StatsCollector::PrepareRemoteReport(
669 uint32 ssrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000670 const std::string& transport_id,
671 TrackDirection direction) {
672 const std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000673 StatsMap::iterator it = reports_.find(StatsId(
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000674 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction));
wu@webrtc.org97077a32013-10-25 21:18:33 +0000675
676 std::string track_id;
677 if (it == reports_.end()) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000678 if (!GetTrackIdBySsrc(ssrc, &track_id, direction))
wu@webrtc.org97077a32013-10-25 21:18:33 +0000679 return NULL;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000680 } else {
681 // Keeps the old track id since we want to report the stats for inactive
682 // tracks.
683 ExtractValueFromReport(it->second,
684 StatsReport::kStatsValueNameTrackId,
685 &track_id);
686 }
687
688 StatsReport* report = GetOrCreateReport(
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000689 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000690
691 // Clear out stats from previous GatherStats calls if any.
692 // The timestamp will be added later. Zero it for debugging.
693 report->values.clear();
694 report->timestamp = 0;
695
696 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
697 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
698 // Add the mapping of SSRC to transport.
699 report->AddValue(StatsReport::kStatsValueNameTransportId,
700 transport_id);
701 return report;
702}
703
wu@webrtc.org4551b792013-10-09 15:37:36 +0000704std::string StatsCollector::AddOneCertificateReport(
705 const talk_base::SSLCertificate* cert, const std::string& issuer_id) {
706 // TODO(bemasc): Move this computation to a helper class that caches these
707 // values to reduce CPU use in GetStats. This will require adding a fast
708 // SSLCertificate::Equals() method to detect certificate changes.
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000709
710 std::string digest_algorithm;
711 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
712 return std::string();
713
wu@webrtc.org4551b792013-10-09 15:37:36 +0000714 talk_base::scoped_ptr<talk_base::SSLFingerprint> ssl_fingerprint(
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000715 talk_base::SSLFingerprint::Create(digest_algorithm, cert));
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000716
717 // SSLFingerprint::Create can fail if the algorithm returned by
718 // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
719 // implementation of SSLCertificate::ComputeDigest. This currently happens
720 // with MD5- and SHA-224-signed certificates when linked to libNSS.
721 if (!ssl_fingerprint)
722 return std::string();
723
wu@webrtc.org4551b792013-10-09 15:37:36 +0000724 std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
725
726 talk_base::Buffer der_buffer;
727 cert->ToDER(&der_buffer);
728 std::string der_base64;
729 talk_base::Base64::EncodeFromArray(
730 der_buffer.data(), der_buffer.length(), &der_base64);
731
732 StatsReport report;
733 report.type = StatsReport::kStatsReportTypeCertificate;
734 report.id = StatsId(report.type, fingerprint);
735 report.timestamp = stats_gathering_started_;
736 report.AddValue(StatsReport::kStatsValueNameFingerprint, fingerprint);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000737 report.AddValue(StatsReport::kStatsValueNameFingerprintAlgorithm,
738 digest_algorithm);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000739 report.AddValue(StatsReport::kStatsValueNameDer, der_base64);
740 if (!issuer_id.empty())
741 report.AddValue(StatsReport::kStatsValueNameIssuerId, issuer_id);
742 reports_[report.id] = report;
743 return report.id;
744}
745
746std::string StatsCollector::AddCertificateReports(
747 const talk_base::SSLCertificate* cert) {
748 // Produces a chain of StatsReports representing this certificate and the rest
749 // of its chain, and adds those reports to |reports_|. The return value is
750 // the id of the leaf report. The provided cert must be non-null, so at least
751 // one report will always be provided and the returned string will never be
752 // empty.
753 ASSERT(cert != NULL);
754
755 std::string issuer_id;
756 talk_base::scoped_ptr<talk_base::SSLCertChain> chain;
757 if (cert->GetChain(chain.accept())) {
758 // This loop runs in reverse, i.e. from root to leaf, so that each
759 // certificate's issuer's report ID is known before the child certificate's
760 // report is generated. The root certificate does not have an issuer ID
761 // value.
762 for (ptrdiff_t i = chain->GetSize() - 1; i >= 0; --i) {
763 const talk_base::SSLCertificate& cert_i = chain->Get(i);
764 issuer_id = AddOneCertificateReport(&cert_i, issuer_id);
765 }
766 }
767 // Add the leaf certificate.
768 return AddOneCertificateReport(cert, issuer_id);
769}
770
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771void StatsCollector::ExtractSessionInfo() {
772 // Extract information from the base session.
773 StatsReport report;
774 report.id = StatsId(StatsReport::kStatsReportTypeSession, session_->id());
775 report.type = StatsReport::kStatsReportTypeSession;
776 report.timestamp = stats_gathering_started_;
777 report.values.clear();
778 report.AddBoolean(StatsReport::kStatsValueNameInitiator,
779 session_->initiator());
780
781 reports_[report.id] = report;
782
783 cricket::SessionStats stats;
784 if (session_->GetStats(&stats)) {
785 // Store the proxy map away for use in SSRC reporting.
786 proxy_to_transport_ = stats.proxy_to_transport;
787
788 for (cricket::TransportStatsMap::iterator transport_iter
789 = stats.transport_stats.begin();
790 transport_iter != stats.transport_stats.end(); ++transport_iter) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000791 // Attempt to get a copy of the certificates from the transport and
792 // expose them in stats reports. All channels in a transport share the
793 // same local and remote certificates.
794 std::string local_cert_report_id, remote_cert_report_id;
795 cricket::Transport* transport =
796 session_->GetTransport(transport_iter->second.content_name);
797 if (transport) {
798 talk_base::scoped_ptr<talk_base::SSLIdentity> identity;
799 if (transport->GetIdentity(identity.accept()))
800 local_cert_report_id = AddCertificateReports(
801 &(identity->certificate()));
802
803 talk_base::scoped_ptr<talk_base::SSLCertificate> cert;
804 if (transport->GetRemoteCertificate(cert.accept()))
805 remote_cert_report_id = AddCertificateReports(cert.get());
806 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 for (cricket::TransportChannelStatsList::iterator channel_iter
808 = transport_iter->second.channel_stats.begin();
809 channel_iter != transport_iter->second.channel_stats.end();
810 ++channel_iter) {
811 StatsReport channel_report;
812 std::ostringstream ostc;
813 ostc << "Channel-" << transport_iter->second.content_name
814 << "-" << channel_iter->component;
815 channel_report.id = ostc.str();
816 channel_report.type = StatsReport::kStatsReportTypeComponent;
817 channel_report.timestamp = stats_gathering_started_;
818 channel_report.AddValue(StatsReport::kStatsValueNameComponent,
819 channel_iter->component);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000820 if (!local_cert_report_id.empty())
821 channel_report.AddValue(
822 StatsReport::kStatsValueNameLocalCertificateId,
823 local_cert_report_id);
824 if (!remote_cert_report_id.empty())
825 channel_report.AddValue(
826 StatsReport::kStatsValueNameRemoteCertificateId,
827 remote_cert_report_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 reports_[channel_report.id] = channel_report;
829 for (size_t i = 0;
830 i < channel_iter->connection_infos.size();
831 ++i) {
832 StatsReport report;
833 const cricket::ConnectionInfo& info
834 = channel_iter->connection_infos[i];
835 std::ostringstream ost;
836 ost << "Conn-" << transport_iter->first << "-"
837 << channel_iter->component << "-" << i;
838 report.id = ost.str();
839 report.type = StatsReport::kStatsReportTypeCandidatePair;
840 report.timestamp = stats_gathering_started_;
841 // Link from connection to its containing channel.
842 report.AddValue(StatsReport::kStatsValueNameChannelId,
843 channel_report.id);
844 report.AddValue(StatsReport::kStatsValueNameBytesSent,
845 info.sent_total_bytes);
846 report.AddValue(StatsReport::kStatsValueNameBytesReceived,
847 info.recv_total_bytes);
848 report.AddBoolean(StatsReport::kStatsValueNameWritable,
849 info.writable);
850 report.AddBoolean(StatsReport::kStatsValueNameReadable,
851 info.readable);
852 report.AddBoolean(StatsReport::kStatsValueNameActiveConnection,
853 info.best_connection);
854 report.AddValue(StatsReport::kStatsValueNameLocalAddress,
855 info.local_candidate.address().ToString());
856 report.AddValue(StatsReport::kStatsValueNameRemoteAddress,
857 info.remote_candidate.address().ToString());
wu@webrtc.org97077a32013-10-25 21:18:33 +0000858 report.AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
859 report.AddValue(StatsReport::kStatsValueNameTransportType,
860 info.local_candidate.protocol());
wu@webrtc.org364f2042013-11-20 21:49:41 +0000861 report.AddValue(StatsReport::kStatsValueNameLocalCandidateType,
862 info.local_candidate.type());
863 report.AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
864 info.remote_candidate.type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 reports_[report.id] = report;
866 }
867 }
868 }
869 }
870}
871
872void StatsCollector::ExtractVoiceInfo() {
873 if (!session_->voice_channel()) {
874 return;
875 }
876 cricket::VoiceMediaInfo voice_info;
877 if (!session_->voice_channel()->GetStats(&voice_info)) {
878 LOG(LS_ERROR) << "Failed to get voice channel stats.";
879 return;
880 }
881 std::string transport_id;
882 if (!GetTransportIdFromProxy(session_->voice_channel()->content_name(),
883 &transport_id)) {
884 LOG(LS_ERROR) << "Failed to get transport name for proxy "
885 << session_->voice_channel()->content_name();
886 return;
887 }
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000888 ExtractStatsFromList(voice_info.receivers, transport_id, this, kReceiving);
889 ExtractStatsFromList(voice_info.senders, transport_id, this, kSending);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000890
891 UpdateStatsFromExistingLocalAudioTracks();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892}
893
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000894void StatsCollector::ExtractVideoInfo(
895 PeerConnectionInterface::StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896 if (!session_->video_channel()) {
897 return;
898 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000899 cricket::StatsOptions options;
900 options.include_received_propagation_stats =
901 (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
902 true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 cricket::VideoMediaInfo video_info;
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000904 if (!session_->video_channel()->GetStats(options, &video_info)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 LOG(LS_ERROR) << "Failed to get video channel stats.";
906 return;
907 }
908 std::string transport_id;
909 if (!GetTransportIdFromProxy(session_->video_channel()->content_name(),
910 &transport_id)) {
911 LOG(LS_ERROR) << "Failed to get transport name for proxy "
912 << session_->video_channel()->content_name();
913 return;
914 }
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000915 ExtractStatsFromList(video_info.receivers, transport_id, this, kReceiving);
916 ExtractStatsFromList(video_info.senders, transport_id, this, kSending);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917 if (video_info.bw_estimations.size() != 1) {
918 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
919 } else {
920 StatsReport* report = &reports_[StatsReport::kStatsReportVideoBweId];
921 ExtractStats(
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000922 video_info.bw_estimations[0], stats_gathering_started_, level, report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 }
924}
925
926double StatsCollector::GetTimeNow() {
927 return timing_.WallTimeNow() * talk_base::kNumMillisecsPerSec;
928}
929
930bool StatsCollector::GetTransportIdFromProxy(const std::string& proxy,
931 std::string* transport) {
932 // TODO(hta): Remove handling of empty proxy name once tests do not use it.
933 if (proxy.empty()) {
934 transport->clear();
935 return true;
936 }
937 if (proxy_to_transport_.find(proxy) == proxy_to_transport_.end()) {
938 LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
939 return false;
940 }
941 std::ostringstream ost;
942 // Component 1 is always used for RTP.
943 ost << "Channel-" << proxy_to_transport_[proxy] << "-1";
944 *transport = ost.str();
945 return true;
946}
947
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000948StatsReport* StatsCollector::GetReport(const std::string& type,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000949 const std::string& id,
950 TrackDirection direction) {
951 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
952 type == StatsReport::kStatsReportTypeRemoteSsrc);
953 std::string statsid = StatsId(type, id, direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000954 StatsReport* report = NULL;
955 std::map<std::string, StatsReport>::iterator it = reports_.find(statsid);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000956 if (it != reports_.end())
957 report = &(it->second);
958
959 return report;
960}
961
962StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000963 const std::string& id,
964 TrackDirection direction) {
965 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
966 type == StatsReport::kStatsReportTypeRemoteSsrc);
967 StatsReport* report = GetReport(type, id, direction);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000968 if (report == NULL) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000969 std::string statsid = StatsId(type, id, direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000970 report = &reports_[statsid]; // Create new element.
971 report->id = statsid;
972 report->type = type;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000973 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000974
wu@webrtc.org97077a32013-10-25 21:18:33 +0000975 return report;
976}
977
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000978void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
979 // Loop through the existing local audio tracks.
980 for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
981 it != local_audio_tracks_.end(); ++it) {
982 AudioTrackInterface* track = it->first;
983 uint32 ssrc = it->second;
984 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
985 StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000986 ssrc_id,
987 kSending);
henrike@webrtc.orgd3d6bce2014-03-10 20:41:22 +0000988 if (report == NULL) {
989 // This can happen if a local audio track is added to a stream on the
990 // fly and the report has not been set up yet. Do nothing in this case.
991 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
992 continue;
993 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000994
995 // The same ssrc can be used by both local and remote audio tracks.
996 std::string track_id;
997 if (!ExtractValueFromReport(*report,
998 StatsReport::kStatsValueNameTrackId,
999 &track_id) ||
1000 track_id != track->id()) {
1001 continue;
1002 }
1003
1004 UpdateReportFromAudioTrack(track, report);
1005 }
1006}
1007
1008void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
1009 StatsReport* report) {
1010 ASSERT(track != NULL);
1011 if (report == NULL)
1012 return;
1013
1014 int signal_level = 0;
1015 if (track->GetSignalLevel(&signal_level)) {
1016 report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
1017 talk_base::ToString<int>(signal_level));
1018 }
1019
1020 talk_base::scoped_refptr<AudioProcessorInterface> audio_processor(
1021 track->GetAudioProcessor());
1022 if (audio_processor.get() == NULL)
1023 return;
1024
1025 AudioProcessorInterface::AudioProcessorStats stats;
1026 audio_processor->GetStats(&stats);
1027 report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
1028 stats.typing_noise_detected ? "true" : "false");
1029 report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
1030 talk_base::ToString<int>(stats.echo_return_loss));
1031 report->ReplaceValue(
1032 StatsReport::kStatsValueNameEchoReturnLossEnhancement,
1033 talk_base::ToString<int>(stats.echo_return_loss_enhancement));
1034 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
1035 talk_base::ToString<int>(stats.echo_delay_median_ms));
1036 report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
1037 talk_base::ToString<float>(stats.aec_quality_min));
1038 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
1039 talk_base::ToString<int>(stats.echo_delay_std_ms));
1040}
1041
xians@webrtc.org4cb01282014-06-12 14:57:05 +00001042bool StatsCollector::GetTrackIdBySsrc(uint32 ssrc, std::string* track_id,
1043 TrackDirection direction) {
1044 if (direction == kSending) {
1045 if (!session()->GetLocalTrackIdBySsrc(ssrc, track_id)) {
1046 LOG(LS_WARNING) << "The SSRC " << ssrc
1047 << " is not associated with a sending track";
1048 return false;
1049 }
1050 } else {
1051 ASSERT(direction == kReceiving);
1052 if (!session()->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
1053 LOG(LS_WARNING) << "The SSRC " << ssrc
1054 << " is not associated with a receiving track";
1055 return false;
1056 }
1057 }
1058
1059 return true;
1060}
1061
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062} // namespace webrtc