blob: 1f6114e42b4f797c855fa0eaaddb1cf19359f43c [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";
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +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
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
109const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000110const char StatsReport::kStatsValueNameFrameWidthInput[] =
111 "googFrameWidthInput";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112const char StatsReport::kStatsValueNameFrameWidthReceived[] =
113 "googFrameWidthReceived";
114const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
115const char StatsReport::kStatsValueNameInitiator[] = "googInitiator";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000116const char StatsReport::kStatsValueNameIssuerId[] = "googIssuerId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117const char StatsReport::kStatsValueNameJitterReceived[] = "googJitterReceived";
118const char StatsReport::kStatsValueNameLocalAddress[] = "googLocalAddress";
wu@webrtc.org364f2042013-11-20 21:49:41 +0000119const char StatsReport::kStatsValueNameLocalCandidateType[] =
120 "googLocalCandidateType";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000121const char StatsReport::kStatsValueNameLocalCertificateId[] =
122 "googLocalCertificateId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
124const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000125const char StatsReport::kStatsValueNamePlisReceived[] = "googPlisReceived";
126const char StatsReport::kStatsValueNamePlisSent[] = "googPlisSent";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
128const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
129const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000130const char StatsReport::kStatsValueNamePreferredJitterBufferMs[] =
131 "googPreferredJitterBufferMs";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132const char StatsReport::kStatsValueNameReadable[] = "googReadable";
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000133const char StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug[] =
134 "googReceivedPacketGroupArrivalTimeDebug";
135const char StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug[] =
136 "googReceivedPacketGroupPropagationDeltaDebug";
137const char
138StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[] =
139 "googReceivedPacketGroupPropagationDeltaSumDebug";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
wu@webrtc.org364f2042013-11-20 21:49:41 +0000141const char StatsReport::kStatsValueNameRemoteCandidateType[] =
142 "googRemoteCandidateType";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000143const char StatsReport::kStatsValueNameRemoteCertificateId[] =
144 "googRemoteCertificateId";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145const char StatsReport::kStatsValueNameRetransmitBitrate[] =
146 "googRetransmitBitrate";
147const char StatsReport::kStatsValueNameRtt[] = "googRtt";
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000148const char StatsReport::kStatsValueNameSsrc[] = "ssrc";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000149const char StatsReport::kStatsValueNameTargetEncBitrate[] =
150 "googTargetEncBitrate";
151const char StatsReport::kStatsValueNameTransmitBitrate[] =
152 "googTransmitBitrate";
153const char StatsReport::kStatsValueNameTransportId[] = "transportId";
154const char StatsReport::kStatsValueNameTransportType[] = "googTransportType";
155const char StatsReport::kStatsValueNameTrackId[] = "googTrackId";
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000156const char StatsReport::kStatsValueNameTypingNoiseState[] =
157 "googTypingNoiseState";
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000158const char StatsReport::kStatsValueNameViewLimitedResolution[] =
159 "googViewLimitedResolution";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160const char StatsReport::kStatsValueNameWritable[] = "googWritable";
161
162const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
163const char StatsReport::kStatsReportTypeBwe[] = "VideoBwe";
wu@webrtc.org97077a32013-10-25 21:18:33 +0000164const char StatsReport::kStatsReportTypeRemoteSsrc[] = "remoteSsrc";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165const char StatsReport::kStatsReportTypeSsrc[] = "ssrc";
166const char StatsReport::kStatsReportTypeTrack[] = "googTrack";
167const char StatsReport::kStatsReportTypeIceCandidate[] = "iceCandidate";
168const char StatsReport::kStatsReportTypeTransport[] = "googTransport";
169const char StatsReport::kStatsReportTypeComponent[] = "googComponent";
170const char StatsReport::kStatsReportTypeCandidatePair[] = "googCandidatePair";
wu@webrtc.org4551b792013-10-09 15:37:36 +0000171const char StatsReport::kStatsReportTypeCertificate[] = "googCertificate";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000172
173const char StatsReport::kStatsReportVideoBweId[] = "bweforvideo";
174
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000175
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176// Implementations of functions in statstypes.h
177void StatsReport::AddValue(const std::string& name, const std::string& value) {
178 Value temp;
179 temp.name = name;
180 temp.value = value;
181 values.push_back(temp);
182}
183
184void StatsReport::AddValue(const std::string& name, int64 value) {
185 AddValue(name, talk_base::ToString<int64>(value));
186}
187
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000188template <typename T>
189void StatsReport::AddValue(const std::string& name,
190 const std::vector<T>& value) {
191 std::ostringstream oss;
192 oss << "[";
193 for (size_t i = 0; i < value.size(); ++i) {
194 oss << talk_base::ToString<T>(value[i]);
195 if (i != value.size() - 1)
196 oss << ", ";
197 }
198 oss << "]";
199 AddValue(name, oss.str());
200}
201
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202void StatsReport::AddBoolean(const std::string& name, bool value) {
203 AddValue(name, value ? "true" : "false");
204}
205
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000206void StatsReport::ReplaceValue(const std::string& name,
207 const std::string& value) {
208 for (Values::iterator it = values.begin(); it != values.end(); ++it) {
209 if ((*it).name == name) {
210 it->value = value;
211 return;
212 }
213 }
214 // It is not reachable here, add an ASSERT to make sure the overwriting is
215 // always a success.
216 ASSERT(false);
217}
218
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219namespace {
220typedef std::map<std::string, StatsReport> StatsMap;
221
222std::string StatsId(const std::string& type, const std::string& id) {
223 return type + "_" + id;
224}
225
226bool ExtractValueFromReport(
227 const StatsReport& report,
228 const std::string& name,
229 std::string* value) {
230 StatsReport::Values::const_iterator it = report.values.begin();
231 for (; it != report.values.end(); ++it) {
232 if (it->name == name) {
233 *value = it->value;
234 return true;
235 }
236 }
237 return false;
238}
239
240template <class TrackVector>
241void CreateTrackReports(const TrackVector& tracks, StatsMap* reports) {
242 for (size_t j = 0; j < tracks.size(); ++j) {
243 webrtc::MediaStreamTrackInterface* track = tracks[j];
244 // Adds an empty track report.
245 StatsReport report;
246 report.type = StatsReport::kStatsReportTypeTrack;
247 report.id = StatsId(StatsReport::kStatsReportTypeTrack, track->id());
248 report.AddValue(StatsReport::kStatsValueNameTrackId,
249 track->id());
250 (*reports)[report.id] = report;
251 }
252}
253
254void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
255 report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
256 info.audio_level);
257 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
258 info.bytes_rcvd);
259 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
260 info.jitter_ms);
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000261 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
262 info.jitter_buffer_ms);
263 report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
264 info.jitter_buffer_preferred_ms);
265 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
266 info.delay_estimate_ms);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000267 report->AddValue(StatsReport::kStatsValueNameExpandRate,
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000268 talk_base::ToString<float>(info.expand_rate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
270 info.packets_rcvd);
271 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
272 info.packets_lost);
273}
274
275void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
276 report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
277 info.audio_level);
278 report->AddValue(StatsReport::kStatsValueNameBytesSent,
279 info.bytes_sent);
280 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
281 info.packets_sent);
282 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
283 info.jitter_ms);
284 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
285 report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
286 talk_base::ToString<float>(info.aec_quality_min));
287 report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
288 info.echo_delay_median_ms);
289 report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
290 info.echo_delay_std_ms);
291 report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
292 info.echo_return_loss);
293 report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
294 info.echo_return_loss_enhancement);
295 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000296 report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
297 info.typing_noise_detected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298}
299
300void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
301 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
302 info.bytes_rcvd);
303 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
304 info.packets_rcvd);
305 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
306 info.packets_lost);
307
308 report->AddValue(StatsReport::kStatsValueNameFirsSent,
309 info.firs_sent);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000310 report->AddValue(StatsReport::kStatsValueNamePlisSent,
311 info.plis_sent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000312 report->AddValue(StatsReport::kStatsValueNameNacksSent,
313 info.nacks_sent);
314 report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
315 info.frame_width);
316 report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
317 info.frame_height);
318 report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
319 info.framerate_rcvd);
320 report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
321 info.framerate_decoded);
322 report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
323 info.framerate_output);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000324
325 report->AddValue(StatsReport::kStatsValueNameDecodeMs,
326 info.decode_ms);
327 report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
328 info.max_decode_ms);
329 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
330 info.current_delay_ms);
331 report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
332 info.target_delay_ms);
333 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
334 info.jitter_buffer_ms);
335 report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
336 info.min_playout_delay_ms);
337 report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
338 info.render_delay_ms);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000339}
340
341void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
342 report->AddValue(StatsReport::kStatsValueNameBytesSent,
343 info.bytes_sent);
344 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
345 info.packets_sent);
346
347 report->AddValue(StatsReport::kStatsValueNameFirsReceived,
348 info.firs_rcvd);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000349 report->AddValue(StatsReport::kStatsValueNamePlisReceived,
350 info.plis_rcvd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351 report->AddValue(StatsReport::kStatsValueNameNacksReceived,
352 info.nacks_rcvd);
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000353 report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
354 info.input_frame_width);
355 report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
356 info.input_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000358 info.send_frame_width);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359 report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000360 info.send_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
362 info.framerate_input);
363 report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
364 info.framerate_sent);
365 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
366 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000367 report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
368 (info.adapt_reason & 0x1) > 0);
369 report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
370 (info.adapt_reason & 0x2) > 0);
371 report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
372 (info.adapt_reason & 0x4) > 0);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000373 report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
374 report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
375 info.capture_jitter_ms);
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000376 report->AddValue(StatsReport::kStatsValueNameCaptureQueueDelayMsPerS,
377 info.capture_queue_delay_ms_per_s);
378 report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
379 info.encode_usage_percent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000380}
381
382void ExtractStats(const cricket::BandwidthEstimationInfo& info,
383 double stats_gathering_started,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000384 PeerConnectionInterface::StatsOutputLevel level,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385 StatsReport* report) {
386 report->id = StatsReport::kStatsReportVideoBweId;
387 report->type = StatsReport::kStatsReportTypeBwe;
388
389 // Clear out stats from previous GatherStats calls if any.
390 if (report->timestamp != stats_gathering_started) {
391 report->values.clear();
392 report->timestamp = stats_gathering_started;
393 }
394
395 report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
396 info.available_send_bandwidth);
397 report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
398 info.available_recv_bandwidth);
399 report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
400 info.target_enc_bitrate);
401 report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
402 info.actual_enc_bitrate);
403 report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
404 info.retransmit_bitrate);
405 report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
406 info.transmit_bitrate);
407 report->AddValue(StatsReport::kStatsValueNameBucketDelay,
408 info.bucket_delay);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000409 if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
410 report->AddValue(
411 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
412 info.total_received_propagation_delta_ms);
413 if (info.recent_received_propagation_delta_ms.size() > 0) {
414 report->AddValue(
415 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
416 info.recent_received_propagation_delta_ms);
417 report->AddValue(
418 StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
419 info.recent_received_packet_group_arrival_time_ms);
420 }
421 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422}
423
wu@webrtc.org97077a32013-10-25 21:18:33 +0000424void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
425 StatsReport* report) {
426 report->timestamp = info.remote_stats[0].timestamp;
427 // TODO(hta): Extract some stats here.
428}
429
430void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
431 StatsReport* report) {
432 report->timestamp = info.remote_stats[0].timestamp;
433 // TODO(hta): Extract some stats here.
434}
435
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436// Template to extract stats from a data vector.
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000437// In order to use the template, the functions that are called from it,
438// ExtractStats and ExtractRemoteStats, must be defined and overloaded
439// for each type.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440template<typename T>
441void ExtractStatsFromList(const std::vector<T>& data,
442 const std::string& transport_id,
443 StatsCollector* collector) {
444 typename std::vector<T>::const_iterator it = data.begin();
445 for (; it != data.end(); ++it) {
446 std::string id;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000447 uint32 ssrc = it->ssrc();
wu@webrtc.org97077a32013-10-25 21:18:33 +0000448 // Each object can result in 2 objects, a local and a remote object.
449 // TODO(hta): Handle the case of multiple SSRCs per object.
450 StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000451 if (!report) {
452 continue;
453 }
454 ExtractStats(*it, report);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000455 if (it->remote_stats.size() > 0) {
456 report = collector->PrepareRemoteReport(ssrc, transport_id);
457 if (!report) {
458 continue;
459 }
460 ExtractRemoteStats(*it, report);
461 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000463}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464
465} // namespace
466
467StatsCollector::StatsCollector()
468 : session_(NULL), stats_gathering_started_(0) {
469}
470
471// Adds a MediaStream with tracks that can be used as a |selector| in a call
472// to GetStats.
473void StatsCollector::AddStream(MediaStreamInterface* stream) {
474 ASSERT(stream != NULL);
475
476 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
477 &reports_);
478 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
479 &reports_);
480}
481
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000482void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
483 uint32 ssrc) {
484 ASSERT(audio_track != NULL);
485#ifdef _DEBUG
486 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
487 it != local_audio_tracks_.end(); ++it) {
488 ASSERT(it->first != audio_track || it->second != ssrc);
489 }
490#endif
491 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
492}
493
494void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
495 uint32 ssrc) {
496 ASSERT(audio_track != NULL);
497 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
498 it != local_audio_tracks_.end(); ++it) {
499 if (it->first == audio_track && it->second == ssrc) {
500 local_audio_tracks_.erase(it);
501 return;
502 }
503 }
504
505 ASSERT(false);
506}
507
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
509 StatsReports* reports) {
510 ASSERT(reports != NULL);
511 reports->clear();
512
513 StatsMap::iterator it;
514 if (!track) {
515 for (it = reports_.begin(); it != reports_.end(); ++it) {
516 reports->push_back(it->second);
517 }
518 return true;
519 }
520
521 it = reports_.find(StatsId(StatsReport::kStatsReportTypeSession,
522 session_->id()));
523 if (it != reports_.end()) {
524 reports->push_back(it->second);
525 }
526
527 it = reports_.find(StatsId(StatsReport::kStatsReportTypeTrack, track->id()));
528
529 if (it == reports_.end()) {
530 LOG(LS_WARNING) << "No StatsReport is available for "<< track->id();
531 return false;
532 }
533
534 reports->push_back(it->second);
535
536 std::string track_id;
537 for (it = reports_.begin(); it != reports_.end(); ++it) {
538 if (it->second.type != StatsReport::kStatsReportTypeSsrc) {
539 continue;
540 }
541 if (ExtractValueFromReport(it->second,
542 StatsReport::kStatsValueNameTrackId,
543 &track_id)) {
544 if (track_id == track->id()) {
545 reports->push_back(it->second);
546 }
547 }
548 }
549
550 return true;
551}
552
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000553void
554StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 double time_now = GetTimeNow();
556 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
557 // ms apart will be ignored.
558 const double kMinGatherStatsPeriod = 50;
559 if (stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
560 return;
561 }
562 stats_gathering_started_ = time_now;
563
564 if (session_) {
565 ExtractSessionInfo();
566 ExtractVoiceInfo();
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000567 ExtractVideoInfo(level);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 }
569}
570
wu@webrtc.org97077a32013-10-25 21:18:33 +0000571StatsReport* StatsCollector::PrepareLocalReport(
572 uint32 ssrc,
573 const std::string& transport_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
575 StatsMap::iterator it = reports_.find(StatsId(
576 StatsReport::kStatsReportTypeSsrc, ssrc_id));
577
578 std::string track_id;
579 if (it == reports_.end()) {
580 if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000581 LOG(LS_WARNING) << "The SSRC " << ssrc
582 << " is not associated with a track";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 return NULL;
584 }
585 } else {
586 // Keeps the old track id since we want to report the stats for inactive
587 // tracks.
588 ExtractValueFromReport(it->second,
589 StatsReport::kStatsValueNameTrackId,
590 &track_id);
591 }
592
wu@webrtc.org97077a32013-10-25 21:18:33 +0000593 StatsReport* report = GetOrCreateReport(StatsReport::kStatsReportTypeSsrc,
594 ssrc_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595
596 // Clear out stats from previous GatherStats calls if any.
597 if (report->timestamp != stats_gathering_started_) {
598 report->values.clear();
599 report->timestamp = stats_gathering_started_;
600 }
601
602 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
603 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
604 // Add the mapping of SSRC to transport.
605 report->AddValue(StatsReport::kStatsValueNameTransportId,
606 transport_id);
607 return report;
608}
609
wu@webrtc.org97077a32013-10-25 21:18:33 +0000610StatsReport* StatsCollector::PrepareRemoteReport(
611 uint32 ssrc,
612 const std::string& transport_id) {
613 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
614 StatsMap::iterator it = reports_.find(StatsId(
615 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id));
616
617 std::string track_id;
618 if (it == reports_.end()) {
619 if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
620 LOG(LS_WARNING) << "The SSRC " << ssrc
621 << " is not associated with a track";
622 return NULL;
623 }
624 } else {
625 // Keeps the old track id since we want to report the stats for inactive
626 // tracks.
627 ExtractValueFromReport(it->second,
628 StatsReport::kStatsValueNameTrackId,
629 &track_id);
630 }
631
632 StatsReport* report = GetOrCreateReport(
633 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id);
634
635 // Clear out stats from previous GatherStats calls if any.
636 // The timestamp will be added later. Zero it for debugging.
637 report->values.clear();
638 report->timestamp = 0;
639
640 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
641 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
642 // Add the mapping of SSRC to transport.
643 report->AddValue(StatsReport::kStatsValueNameTransportId,
644 transport_id);
645 return report;
646}
647
wu@webrtc.org4551b792013-10-09 15:37:36 +0000648std::string StatsCollector::AddOneCertificateReport(
649 const talk_base::SSLCertificate* cert, const std::string& issuer_id) {
650 // TODO(bemasc): Move this computation to a helper class that caches these
651 // values to reduce CPU use in GetStats. This will require adding a fast
652 // SSLCertificate::Equals() method to detect certificate changes.
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000653
654 std::string digest_algorithm;
655 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
656 return std::string();
657
wu@webrtc.org4551b792013-10-09 15:37:36 +0000658 talk_base::scoped_ptr<talk_base::SSLFingerprint> ssl_fingerprint(
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000659 talk_base::SSLFingerprint::Create(digest_algorithm, cert));
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000660
661 // SSLFingerprint::Create can fail if the algorithm returned by
662 // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
663 // implementation of SSLCertificate::ComputeDigest. This currently happens
664 // with MD5- and SHA-224-signed certificates when linked to libNSS.
665 if (!ssl_fingerprint)
666 return std::string();
667
wu@webrtc.org4551b792013-10-09 15:37:36 +0000668 std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
669
670 talk_base::Buffer der_buffer;
671 cert->ToDER(&der_buffer);
672 std::string der_base64;
673 talk_base::Base64::EncodeFromArray(
674 der_buffer.data(), der_buffer.length(), &der_base64);
675
676 StatsReport report;
677 report.type = StatsReport::kStatsReportTypeCertificate;
678 report.id = StatsId(report.type, fingerprint);
679 report.timestamp = stats_gathering_started_;
680 report.AddValue(StatsReport::kStatsValueNameFingerprint, fingerprint);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000681 report.AddValue(StatsReport::kStatsValueNameFingerprintAlgorithm,
682 digest_algorithm);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000683 report.AddValue(StatsReport::kStatsValueNameDer, der_base64);
684 if (!issuer_id.empty())
685 report.AddValue(StatsReport::kStatsValueNameIssuerId, issuer_id);
686 reports_[report.id] = report;
687 return report.id;
688}
689
690std::string StatsCollector::AddCertificateReports(
691 const talk_base::SSLCertificate* cert) {
692 // Produces a chain of StatsReports representing this certificate and the rest
693 // of its chain, and adds those reports to |reports_|. The return value is
694 // the id of the leaf report. The provided cert must be non-null, so at least
695 // one report will always be provided and the returned string will never be
696 // empty.
697 ASSERT(cert != NULL);
698
699 std::string issuer_id;
700 talk_base::scoped_ptr<talk_base::SSLCertChain> chain;
701 if (cert->GetChain(chain.accept())) {
702 // This loop runs in reverse, i.e. from root to leaf, so that each
703 // certificate's issuer's report ID is known before the child certificate's
704 // report is generated. The root certificate does not have an issuer ID
705 // value.
706 for (ptrdiff_t i = chain->GetSize() - 1; i >= 0; --i) {
707 const talk_base::SSLCertificate& cert_i = chain->Get(i);
708 issuer_id = AddOneCertificateReport(&cert_i, issuer_id);
709 }
710 }
711 // Add the leaf certificate.
712 return AddOneCertificateReport(cert, issuer_id);
713}
714
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000715void StatsCollector::ExtractSessionInfo() {
716 // Extract information from the base session.
717 StatsReport report;
718 report.id = StatsId(StatsReport::kStatsReportTypeSession, session_->id());
719 report.type = StatsReport::kStatsReportTypeSession;
720 report.timestamp = stats_gathering_started_;
721 report.values.clear();
722 report.AddBoolean(StatsReport::kStatsValueNameInitiator,
723 session_->initiator());
724
725 reports_[report.id] = report;
726
727 cricket::SessionStats stats;
728 if (session_->GetStats(&stats)) {
729 // Store the proxy map away for use in SSRC reporting.
730 proxy_to_transport_ = stats.proxy_to_transport;
731
732 for (cricket::TransportStatsMap::iterator transport_iter
733 = stats.transport_stats.begin();
734 transport_iter != stats.transport_stats.end(); ++transport_iter) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000735 // Attempt to get a copy of the certificates from the transport and
736 // expose them in stats reports. All channels in a transport share the
737 // same local and remote certificates.
738 std::string local_cert_report_id, remote_cert_report_id;
739 cricket::Transport* transport =
740 session_->GetTransport(transport_iter->second.content_name);
741 if (transport) {
742 talk_base::scoped_ptr<talk_base::SSLIdentity> identity;
743 if (transport->GetIdentity(identity.accept()))
744 local_cert_report_id = AddCertificateReports(
745 &(identity->certificate()));
746
747 talk_base::scoped_ptr<talk_base::SSLCertificate> cert;
748 if (transport->GetRemoteCertificate(cert.accept()))
749 remote_cert_report_id = AddCertificateReports(cert.get());
750 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751 for (cricket::TransportChannelStatsList::iterator channel_iter
752 = transport_iter->second.channel_stats.begin();
753 channel_iter != transport_iter->second.channel_stats.end();
754 ++channel_iter) {
755 StatsReport channel_report;
756 std::ostringstream ostc;
757 ostc << "Channel-" << transport_iter->second.content_name
758 << "-" << channel_iter->component;
759 channel_report.id = ostc.str();
760 channel_report.type = StatsReport::kStatsReportTypeComponent;
761 channel_report.timestamp = stats_gathering_started_;
762 channel_report.AddValue(StatsReport::kStatsValueNameComponent,
763 channel_iter->component);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000764 if (!local_cert_report_id.empty())
765 channel_report.AddValue(
766 StatsReport::kStatsValueNameLocalCertificateId,
767 local_cert_report_id);
768 if (!remote_cert_report_id.empty())
769 channel_report.AddValue(
770 StatsReport::kStatsValueNameRemoteCertificateId,
771 remote_cert_report_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 reports_[channel_report.id] = channel_report;
773 for (size_t i = 0;
774 i < channel_iter->connection_infos.size();
775 ++i) {
776 StatsReport report;
777 const cricket::ConnectionInfo& info
778 = channel_iter->connection_infos[i];
779 std::ostringstream ost;
780 ost << "Conn-" << transport_iter->first << "-"
781 << channel_iter->component << "-" << i;
782 report.id = ost.str();
783 report.type = StatsReport::kStatsReportTypeCandidatePair;
784 report.timestamp = stats_gathering_started_;
785 // Link from connection to its containing channel.
786 report.AddValue(StatsReport::kStatsValueNameChannelId,
787 channel_report.id);
788 report.AddValue(StatsReport::kStatsValueNameBytesSent,
789 info.sent_total_bytes);
790 report.AddValue(StatsReport::kStatsValueNameBytesReceived,
791 info.recv_total_bytes);
792 report.AddBoolean(StatsReport::kStatsValueNameWritable,
793 info.writable);
794 report.AddBoolean(StatsReport::kStatsValueNameReadable,
795 info.readable);
796 report.AddBoolean(StatsReport::kStatsValueNameActiveConnection,
797 info.best_connection);
798 report.AddValue(StatsReport::kStatsValueNameLocalAddress,
799 info.local_candidate.address().ToString());
800 report.AddValue(StatsReport::kStatsValueNameRemoteAddress,
801 info.remote_candidate.address().ToString());
wu@webrtc.org97077a32013-10-25 21:18:33 +0000802 report.AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
803 report.AddValue(StatsReport::kStatsValueNameTransportType,
804 info.local_candidate.protocol());
wu@webrtc.org364f2042013-11-20 21:49:41 +0000805 report.AddValue(StatsReport::kStatsValueNameLocalCandidateType,
806 info.local_candidate.type());
807 report.AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
808 info.remote_candidate.type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 reports_[report.id] = report;
810 }
811 }
812 }
813 }
814}
815
816void StatsCollector::ExtractVoiceInfo() {
817 if (!session_->voice_channel()) {
818 return;
819 }
820 cricket::VoiceMediaInfo voice_info;
821 if (!session_->voice_channel()->GetStats(&voice_info)) {
822 LOG(LS_ERROR) << "Failed to get voice channel stats.";
823 return;
824 }
825 std::string transport_id;
826 if (!GetTransportIdFromProxy(session_->voice_channel()->content_name(),
827 &transport_id)) {
828 LOG(LS_ERROR) << "Failed to get transport name for proxy "
829 << session_->voice_channel()->content_name();
830 return;
831 }
832 ExtractStatsFromList(voice_info.receivers, transport_id, this);
833 ExtractStatsFromList(voice_info.senders, transport_id, this);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000834
835 UpdateStatsFromExistingLocalAudioTracks();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836}
837
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000838void StatsCollector::ExtractVideoInfo(
839 PeerConnectionInterface::StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 if (!session_->video_channel()) {
841 return;
842 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000843 cricket::StatsOptions options;
844 options.include_received_propagation_stats =
845 (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
846 true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 cricket::VideoMediaInfo video_info;
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000848 if (!session_->video_channel()->GetStats(options, &video_info)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 LOG(LS_ERROR) << "Failed to get video channel stats.";
850 return;
851 }
852 std::string transport_id;
853 if (!GetTransportIdFromProxy(session_->video_channel()->content_name(),
854 &transport_id)) {
855 LOG(LS_ERROR) << "Failed to get transport name for proxy "
856 << session_->video_channel()->content_name();
857 return;
858 }
859 ExtractStatsFromList(video_info.receivers, transport_id, this);
860 ExtractStatsFromList(video_info.senders, transport_id, this);
861 if (video_info.bw_estimations.size() != 1) {
862 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
863 } else {
864 StatsReport* report = &reports_[StatsReport::kStatsReportVideoBweId];
865 ExtractStats(
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000866 video_info.bw_estimations[0], stats_gathering_started_, level, report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 }
868}
869
870double StatsCollector::GetTimeNow() {
871 return timing_.WallTimeNow() * talk_base::kNumMillisecsPerSec;
872}
873
874bool StatsCollector::GetTransportIdFromProxy(const std::string& proxy,
875 std::string* transport) {
876 // TODO(hta): Remove handling of empty proxy name once tests do not use it.
877 if (proxy.empty()) {
878 transport->clear();
879 return true;
880 }
881 if (proxy_to_transport_.find(proxy) == proxy_to_transport_.end()) {
882 LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
883 return false;
884 }
885 std::ostringstream ost;
886 // Component 1 is always used for RTP.
887 ost << "Channel-" << proxy_to_transport_[proxy] << "-1";
888 *transport = ost.str();
889 return true;
890}
891
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000892StatsReport* StatsCollector::GetReport(const std::string& type,
893 const std::string& id) {
wu@webrtc.org97077a32013-10-25 21:18:33 +0000894 std::string statsid = StatsId(type, id);
895 StatsReport* report = NULL;
896 std::map<std::string, StatsReport>::iterator it = reports_.find(statsid);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000897 if (it != reports_.end())
898 report = &(it->second);
899
900 return report;
901}
902
903StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
904 const std::string& id) {
905 StatsReport* report = GetReport(type, id);
906 if (report == NULL) {
907 std::string statsid = StatsId(type, id);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000908 report = &reports_[statsid]; // Create new element.
909 report->id = statsid;
910 report->type = type;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000911 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000912
wu@webrtc.org97077a32013-10-25 21:18:33 +0000913 return report;
914}
915
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000916void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
917 // Loop through the existing local audio tracks.
918 for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
919 it != local_audio_tracks_.end(); ++it) {
920 AudioTrackInterface* track = it->first;
921 uint32 ssrc = it->second;
922 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
923 StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
924 ssrc_id);
henrike@webrtc.orgd3d6bce2014-03-10 20:41:22 +0000925 if (report == NULL) {
926 // This can happen if a local audio track is added to a stream on the
927 // fly and the report has not been set up yet. Do nothing in this case.
928 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
929 continue;
930 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000931
932 // The same ssrc can be used by both local and remote audio tracks.
933 std::string track_id;
934 if (!ExtractValueFromReport(*report,
935 StatsReport::kStatsValueNameTrackId,
936 &track_id) ||
937 track_id != track->id()) {
938 continue;
939 }
940
941 UpdateReportFromAudioTrack(track, report);
942 }
943}
944
945void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
946 StatsReport* report) {
947 ASSERT(track != NULL);
948 if (report == NULL)
949 return;
950
951 int signal_level = 0;
952 if (track->GetSignalLevel(&signal_level)) {
953 report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
954 talk_base::ToString<int>(signal_level));
955 }
956
957 talk_base::scoped_refptr<AudioProcessorInterface> audio_processor(
958 track->GetAudioProcessor());
959 if (audio_processor.get() == NULL)
960 return;
961
962 AudioProcessorInterface::AudioProcessorStats stats;
963 audio_processor->GetStats(&stats);
964 report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
965 stats.typing_noise_detected ? "true" : "false");
966 report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
967 talk_base::ToString<int>(stats.echo_return_loss));
968 report->ReplaceValue(
969 StatsReport::kStatsValueNameEchoReturnLossEnhancement,
970 talk_base::ToString<int>(stats.echo_return_loss_enhancement));
971 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
972 talk_base::ToString<int>(stats.echo_delay_median_ms));
973 report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
974 talk_base::ToString<float>(stats.aec_quality_min));
975 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
976 talk_base::ToString<int>(stats.echo_delay_std_ms));
977}
978
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979} // namespace webrtc