blob: d434aafe317fdc5ca0e1e3db7bc8237b8ec0f5f5 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2012 Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
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
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000033#include "talk/session/media/channel.h"
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000034#include "webrtc/base/base64.h"
35#include "webrtc/base/scoped_ptr.h"
36#include "webrtc/base/timing.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +000038using rtc::scoped_ptr;
39
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040namespace webrtc {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041namespace {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042
guoweis@webrtc.org950c5182014-12-16 23:01:31 +000043// The following is the enum RTCStatsIceCandidateType from
44// http://w3c.github.io/webrtc-stats/#rtcstatsicecandidatetype-enum such that
45// our stats report for ice candidate type could conform to that.
46const char STATSREPORT_LOCAL_PORT_TYPE[] = "host";
47const char STATSREPORT_STUN_PORT_TYPE[] = "serverreflexive";
48const char STATSREPORT_PRFLX_PORT_TYPE[] = "peerreflexive";
49const char STATSREPORT_RELAY_PORT_TYPE[] = "relayed";
50
51// Strings used by the stats collector to report adapter types. This fits the
52// general stype of http://w3c.github.io/webrtc-stats than what
53// AdapterTypeToString does.
54const char* STATSREPORT_ADAPTER_TYPE_ETHERNET = "lan";
55const char* STATSREPORT_ADAPTER_TYPE_WIFI = "wlan";
56const char* STATSREPORT_ADAPTER_TYPE_WWAN = "wwan";
57const char* STATSREPORT_ADAPTER_TYPE_VPN = "vpn";
phoglund@webrtc.org006521d2015-02-12 09:23:59 +000058const char* STATSREPORT_ADAPTER_TYPE_LOOPBACK = "loopback";
guoweis@webrtc.org950c5182014-12-16 23:01:31 +000059
tommi@webrtc.org47218952014-07-15 19:22:37 +000060bool GetTransportIdFromProxy(const cricket::ProxyTransportMap& map,
61 const std::string& proxy,
62 std::string* transport) {
63 // TODO(hta): Remove handling of empty proxy name once tests do not use it.
64 if (proxy.empty()) {
65 transport->clear();
66 return true;
67 }
68
69 cricket::ProxyTransportMap::const_iterator found = map.find(proxy);
70 if (found == map.end()) {
71 LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
72 return false;
73 }
74
tommi@webrtc.org47218952014-07-15 19:22:37 +000075 // Component 1 is always used for RTP.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +000076 scoped_ptr<StatsReport::Id> id(
77 StatsReport::NewComponentId(found->second, 1));
78 // TODO(tommi): Should |transport| simply be of type StatsReport::Id?
79 // When we support more value types than string (e.g. int, double, vector etc)
80 // we should also support a value type for Id.
81 *transport = id->ToString();
tommi@webrtc.org47218952014-07-15 19:22:37 +000082 return true;
83}
84
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +000085void AddTrackReport(StatsCollection* reports, const std::string& track_id) {
xians@webrtc.org01bda202014-07-09 07:38:38 +000086 // Adds an empty track report.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +000087 rtc::scoped_ptr<StatsReport::Id> id(
88 StatsReport::NewTypedId(StatsReport::kStatsReportTypeTrack, track_id));
89 StatsReport* report = reports->ReplaceOrAddNew(id.Pass());
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000090 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
xians@webrtc.org01bda202014-07-09 07:38:38 +000091}
92
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093template <class TrackVector>
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +000094void CreateTrackReports(const TrackVector& tracks, StatsCollection* reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095 for (size_t j = 0; j < tracks.size(); ++j) {
96 webrtc::MediaStreamTrackInterface* track = tracks[j];
xians@webrtc.org01bda202014-07-09 07:38:38 +000097 AddTrackReport(reports, track->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098 }
99}
100
101void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
102 report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
103 info.audio_level);
104 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
105 info.bytes_rcvd);
106 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
107 info.jitter_ms);
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000108 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
109 info.jitter_buffer_ms);
110 report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
111 info.jitter_buffer_preferred_ms);
112 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
113 info.delay_estimate_ms);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000114 report->AddValue(StatsReport::kStatsValueNameExpandRate,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000115 rtc::ToString<float>(info.expand_rate));
minyue@webrtc.org652bc372015-02-18 23:50:46 +0000116 report->AddValue(StatsReport::kStatsValueNameSpeechExpandRate,
117 rtc::ToString<float>(info.speech_expand_rate));
118 report->AddValue(StatsReport::kStatsValueNameSecondaryDecodedRate,
119 rtc::ToString<float>(info.secondary_decoded_rate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
121 info.packets_rcvd);
122 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
123 info.packets_lost);
buildbot@webrtc.org3e01e0b2014-05-13 17:54:10 +0000124 report->AddValue(StatsReport::kStatsValueNameDecodingCTSG,
125 info.decoding_calls_to_silence_generator);
126 report->AddValue(StatsReport::kStatsValueNameDecodingCTN,
127 info.decoding_calls_to_neteq);
128 report->AddValue(StatsReport::kStatsValueNameDecodingNormal,
129 info.decoding_normal);
130 report->AddValue(StatsReport::kStatsValueNameDecodingPLC,
131 info.decoding_plc);
132 report->AddValue(StatsReport::kStatsValueNameDecodingCNG,
133 info.decoding_cng);
134 report->AddValue(StatsReport::kStatsValueNameDecodingPLCCNG,
135 info.decoding_plc_cng);
buildbot@webrtc.orgb525a9d2014-06-03 09:42:15 +0000136 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
137 info.capture_start_ntp_time_ms);
buildbot@webrtc.org7e71b772014-06-13 01:14:01 +0000138 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139}
140
141void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
142 report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
143 info.audio_level);
144 report->AddValue(StatsReport::kStatsValueNameBytesSent,
145 info.bytes_sent);
146 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
147 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000148 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
149 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
151 info.jitter_ms);
152 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
153 report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000154 rtc::ToString<float>(info.aec_quality_min));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155 report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
156 info.echo_delay_median_ms);
157 report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
158 info.echo_delay_std_ms);
159 report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
160 info.echo_return_loss);
161 report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
162 info.echo_return_loss_enhancement);
163 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000164 report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
165 info.typing_noise_detected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166}
167
168void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
169 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
170 info.bytes_rcvd);
171 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
172 info.packets_rcvd);
173 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
174 info.packets_lost);
175
176 report->AddValue(StatsReport::kStatsValueNameFirsSent,
177 info.firs_sent);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000178 report->AddValue(StatsReport::kStatsValueNamePlisSent,
179 info.plis_sent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180 report->AddValue(StatsReport::kStatsValueNameNacksSent,
181 info.nacks_sent);
182 report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
183 info.frame_width);
184 report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
185 info.frame_height);
186 report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
187 info.framerate_rcvd);
188 report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
189 info.framerate_decoded);
190 report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
191 info.framerate_output);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000192
193 report->AddValue(StatsReport::kStatsValueNameDecodeMs,
194 info.decode_ms);
195 report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
196 info.max_decode_ms);
197 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
198 info.current_delay_ms);
199 report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
200 info.target_delay_ms);
201 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
202 info.jitter_buffer_ms);
203 report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
204 info.min_playout_delay_ms);
205 report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
206 info.render_delay_ms);
buildbot@webrtc.org0581f0b2014-05-06 21:36:31 +0000207
208 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
209 info.capture_start_ntp_time_ms);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210}
211
212void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
213 report->AddValue(StatsReport::kStatsValueNameBytesSent,
214 info.bytes_sent);
215 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
216 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000217 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
218 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219
220 report->AddValue(StatsReport::kStatsValueNameFirsReceived,
221 info.firs_rcvd);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000222 report->AddValue(StatsReport::kStatsValueNamePlisReceived,
223 info.plis_rcvd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000224 report->AddValue(StatsReport::kStatsValueNameNacksReceived,
225 info.nacks_rcvd);
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000226 report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
227 info.input_frame_width);
228 report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
229 info.input_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000230 report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000231 info.send_frame_width);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000232 report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000233 info.send_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234 report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
235 info.framerate_input);
236 report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
237 info.framerate_sent);
238 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
239 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000240 report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
241 (info.adapt_reason & 0x1) > 0);
242 report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
243 (info.adapt_reason & 0x2) > 0);
244 report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
245 (info.adapt_reason & 0x4) > 0);
buildbot@webrtc.org71dffb72014-06-24 07:24:49 +0000246 report->AddValue(StatsReport::kStatsValueNameAdaptationChanges,
247 info.adapt_changes);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000248 report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
249 report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
250 info.capture_jitter_ms);
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000251 report->AddValue(StatsReport::kStatsValueNameCaptureQueueDelayMsPerS,
252 info.capture_queue_delay_ms_per_s);
253 report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
254 info.encode_usage_percent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255}
256
257void ExtractStats(const cricket::BandwidthEstimationInfo& info,
258 double stats_gathering_started,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000259 PeerConnectionInterface::StatsOutputLevel level,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 StatsReport* report) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000261 ASSERT(report->type() == StatsReport::kStatsReportTypeBwe);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262
263 // Clear out stats from previous GatherStats calls if any.
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000264 if (report->timestamp() != stats_gathering_started) {
265 report->ResetValues();
266 report->set_timestamp(stats_gathering_started);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267 }
268
269 report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
270 info.available_send_bandwidth);
271 report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
272 info.available_recv_bandwidth);
273 report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
274 info.target_enc_bitrate);
275 report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
276 info.actual_enc_bitrate);
277 report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
278 info.retransmit_bitrate);
279 report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
280 info.transmit_bitrate);
281 report->AddValue(StatsReport::kStatsValueNameBucketDelay,
282 info.bucket_delay);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000283 if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
284 report->AddValue(
285 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
286 info.total_received_propagation_delta_ms);
287 if (info.recent_received_propagation_delta_ms.size() > 0) {
288 report->AddValue(
289 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
290 info.recent_received_propagation_delta_ms);
291 report->AddValue(
292 StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
293 info.recent_received_packet_group_arrival_time_ms);
294 }
295 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296}
297
wu@webrtc.org97077a32013-10-25 21:18:33 +0000298void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
299 StatsReport* report) {
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000300 report->set_timestamp(info.remote_stats[0].timestamp);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000301 // TODO(hta): Extract some stats here.
302}
303
304void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
305 StatsReport* report) {
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000306 report->set_timestamp(info.remote_stats[0].timestamp);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000307 // TODO(hta): Extract some stats here.
308}
309
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000310// Template to extract stats from a data vector.
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000311// In order to use the template, the functions that are called from it,
312// ExtractStats and ExtractRemoteStats, must be defined and overloaded
313// for each type.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000314template<typename T>
315void ExtractStatsFromList(const std::vector<T>& data,
316 const std::string& transport_id,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000317 StatsCollector* collector,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000318 StatsReport::Direction direction) {
319 for (const auto& d : data) {
320 uint32 ssrc = d.ssrc();
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000321 // Each track can have stats for both local and remote objects.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000322 // TODO(hta): Handle the case of multiple SSRCs per object.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000323 StatsReport* report = collector->PrepareReport(true, ssrc, transport_id,
324 direction);
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000325 if (report)
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000326 ExtractStats(d, report);
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000327
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000328 if (!d.remote_stats.empty()) {
329 report = collector->PrepareReport(false, ssrc, transport_id, direction);
330 if (report)
331 ExtractRemoteStats(d, report);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000332 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000334}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335
336} // namespace
337
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000338const char* IceCandidateTypeToStatsType(const std::string& candidate_type) {
339 if (candidate_type == cricket::LOCAL_PORT_TYPE) {
340 return STATSREPORT_LOCAL_PORT_TYPE;
341 }
342 if (candidate_type == cricket::STUN_PORT_TYPE) {
343 return STATSREPORT_STUN_PORT_TYPE;
344 }
345 if (candidate_type == cricket::PRFLX_PORT_TYPE) {
346 return STATSREPORT_PRFLX_PORT_TYPE;
347 }
348 if (candidate_type == cricket::RELAY_PORT_TYPE) {
349 return STATSREPORT_RELAY_PORT_TYPE;
350 }
351 ASSERT(false);
352 return "unknown";
353}
354
355const char* AdapterTypeToStatsType(rtc::AdapterType type) {
356 switch (type) {
357 case rtc::ADAPTER_TYPE_UNKNOWN:
358 return "unknown";
359 case rtc::ADAPTER_TYPE_ETHERNET:
360 return STATSREPORT_ADAPTER_TYPE_ETHERNET;
361 case rtc::ADAPTER_TYPE_WIFI:
362 return STATSREPORT_ADAPTER_TYPE_WIFI;
363 case rtc::ADAPTER_TYPE_CELLULAR:
364 return STATSREPORT_ADAPTER_TYPE_WWAN;
365 case rtc::ADAPTER_TYPE_VPN:
366 return STATSREPORT_ADAPTER_TYPE_VPN;
phoglund@webrtc.org006521d2015-02-12 09:23:59 +0000367 case rtc::ADAPTER_TYPE_LOOPBACK:
368 return STATSREPORT_ADAPTER_TYPE_LOOPBACK;
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000369 default:
370 ASSERT(false);
371 return "";
372 }
373}
374
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000375StatsCollector::StatsCollector(WebRtcSession* session)
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000376 : session_(session),
377 stats_gathering_started_(0) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000378 ASSERT(session_);
379}
380
381StatsCollector::~StatsCollector() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000382 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000383}
384
decurtis@webrtc.org322a5642015-02-03 22:09:37 +0000385double StatsCollector::GetTimeNow() {
386 return rtc::Timing::WallTimeNow() * rtc::kNumMillisecsPerSec;
387}
388
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000389// Adds a MediaStream with tracks that can be used as a |selector| in a call
390// to GetStats.
391void StatsCollector::AddStream(MediaStreamInterface* stream) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000392 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393 ASSERT(stream != NULL);
394
395 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
396 &reports_);
397 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
398 &reports_);
399}
400
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000401void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
402 uint32 ssrc) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000403 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000404 ASSERT(audio_track != NULL);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000405 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
406 it != local_audio_tracks_.end(); ++it) {
407 ASSERT(it->first != audio_track || it->second != ssrc);
408 }
xians@webrtc.org01bda202014-07-09 07:38:38 +0000409
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000410 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
xians@webrtc.org01bda202014-07-09 07:38:38 +0000411
412 // Create the kStatsReportTypeTrack report for the new track if there is no
413 // report yet.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000414 rtc::scoped_ptr<StatsReport::Id> id(
415 StatsReport::NewTypedId(StatsReport::kStatsReportTypeTrack,
416 audio_track->id()));
417 StatsReport* report = reports_.Find(*id.get());
418 if (!report) {
419 report = reports_.InsertNew(id.Pass());
420 report->AddValue(StatsReport::kStatsValueNameTrackId, audio_track->id());
421 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000422}
423
424void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
425 uint32 ssrc) {
426 ASSERT(audio_track != NULL);
427 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
428 it != local_audio_tracks_.end(); ++it) {
429 if (it->first == audio_track && it->second == ssrc) {
430 local_audio_tracks_.erase(it);
431 return;
432 }
433 }
434
435 ASSERT(false);
436}
437
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000438void StatsCollector::GetStats(MediaStreamTrackInterface* track,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439 StatsReports* reports) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000440 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441 ASSERT(reports != NULL);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000442 ASSERT(reports->empty());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 if (!track) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000445 reports->reserve(reports_.size());
446 for (auto* r : reports_)
447 reports->push_back(r);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000448 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 }
450
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000451 StatsReport* report = reports_.Find(StatsReport::NewTypedId(
452 StatsReport::kStatsReportTypeSession, session_->id()));
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000453 if (report)
454 reports->push_back(report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000456 report = reports_.Find(StatsReport::NewTypedId(
457 StatsReport::kStatsReportTypeTrack, track->id()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000459 if (!report)
460 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000462 reports->push_back(report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463
464 std::string track_id;
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000465 for (const auto* r : reports_) {
466 if (r->type() != StatsReport::kStatsReportTypeSsrc)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000467 continue;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000468
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000469 const StatsReport::Value* v =
470 r->FindValue(StatsReport::kStatsValueNameTrackId);
471 if (v && v->value == track->id())
472 reports->push_back(r);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474}
475
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000476void
477StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000478 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479 double time_now = GetTimeNow();
480 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
481 // ms apart will be ignored.
482 const double kMinGatherStatsPeriod = 50;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000483 if (stats_gathering_started_ != 0 &&
484 stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485 return;
486 }
487 stats_gathering_started_ = time_now;
488
489 if (session_) {
490 ExtractSessionInfo();
491 ExtractVoiceInfo();
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000492 ExtractVideoInfo(level);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000493 ExtractDataInfo();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494 }
495}
496
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000497StatsReport* StatsCollector::PrepareReport(
498 bool local,
wu@webrtc.org97077a32013-10-25 21:18:33 +0000499 uint32 ssrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000500 const std::string& transport_id,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000501 StatsReport::Direction direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000502 ASSERT(session_->signaling_thread()->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000503 const std::string ssrc_id = rtc::ToString<uint32>(ssrc);
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000504 rtc::scoped_ptr<StatsReport::Id> id(StatsReport::NewIdWithDirection(
505 local ? StatsReport::kStatsReportTypeSsrc :
506 StatsReport::kStatsReportTypeRemoteSsrc,
507 ssrc_id, direction));
508 StatsReport* report = reports_.Find(*id.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509
xians@webrtc.org01bda202014-07-09 07:38:38 +0000510 // Use the ID of the track that is currently mapped to the SSRC, if any.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 std::string track_id;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000512 if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000513 if (!report) {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000514 // The ssrc is not used by any track or existing report, return NULL
515 // in such case to indicate no report is prepared for the ssrc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 return NULL;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000517 }
518
519 // The ssrc is not used by any existing track. Keeps the old track id
520 // since we want to report the stats for inactive ssrc.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000521 const StatsReport::Value* v =
522 report->FindValue(StatsReport::kStatsValueNameTrackId);
523 if (v)
524 track_id = v->value;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525 }
526
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000527 if (!report) {
528 report = reports_.InsertNew(id.Pass());
529 } else {
530 // Clear out stats from previous GatherStats calls if any.
531 // This is required since the report will be returned for the new values.
532 // Having the old values in the report will lead to multiple values with
533 // the same name.
534 // TODO(tommi): This seems to be pretty wasteful if some of these values
535 // have not changed (we basically throw them away just to recreate them).
536 // Figure out a way to not have to do this while not breaking the existing
537 // functionality.
538 report->ResetValues();
539 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000541 ASSERT(report->values().empty());
542 // FYI - for remote reports, the timestamp will be overwritten later.
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000543 report->set_timestamp(stats_gathering_started_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544
545 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
546 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
547 // Add the mapping of SSRC to transport.
548 report->AddValue(StatsReport::kStatsValueNameTransportId,
549 transport_id);
550 return report;
551}
552
wu@webrtc.org4551b792013-10-09 15:37:36 +0000553std::string StatsCollector::AddOneCertificateReport(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000554 const rtc::SSLCertificate* cert, const std::string& issuer_id) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000555 ASSERT(session_->signaling_thread()->IsCurrent());
556
wu@webrtc.org4551b792013-10-09 15:37:36 +0000557 // TODO(bemasc): Move this computation to a helper class that caches these
558 // values to reduce CPU use in GetStats. This will require adding a fast
559 // SSLCertificate::Equals() method to detect certificate changes.
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000560
561 std::string digest_algorithm;
562 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
563 return std::string();
564
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000565 rtc::scoped_ptr<rtc::SSLFingerprint> ssl_fingerprint(
566 rtc::SSLFingerprint::Create(digest_algorithm, cert));
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000567
568 // SSLFingerprint::Create can fail if the algorithm returned by
569 // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
570 // implementation of SSLCertificate::ComputeDigest. This currently happens
571 // with MD5- and SHA-224-signed certificates when linked to libNSS.
572 if (!ssl_fingerprint)
573 return std::string();
574
wu@webrtc.org4551b792013-10-09 15:37:36 +0000575 std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
576
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000577 rtc::Buffer der_buffer;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000578 cert->ToDER(&der_buffer);
579 std::string der_base64;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000580 rtc::Base64::EncodeFromArray(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000581 der_buffer.data(), der_buffer.length(), &der_base64);
582
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000583 rtc::scoped_ptr<StatsReport::Id> id(
584 StatsReport::NewTypedId(
585 StatsReport::kStatsReportTypeCertificate, fingerprint));
586 StatsReport* report = reports_.ReplaceOrAddNew(id.Pass());
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000587 report->set_timestamp(stats_gathering_started_);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000588 report->AddValue(StatsReport::kStatsValueNameFingerprint, fingerprint);
589 report->AddValue(StatsReport::kStatsValueNameFingerprintAlgorithm,
590 digest_algorithm);
591 report->AddValue(StatsReport::kStatsValueNameDer, der_base64);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000592 if (!issuer_id.empty())
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000593 report->AddValue(StatsReport::kStatsValueNameIssuerId, issuer_id);
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000594 // TODO(tommi): Can we avoid this?
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000595 return report->id().ToString();
wu@webrtc.org4551b792013-10-09 15:37:36 +0000596}
597
598std::string StatsCollector::AddCertificateReports(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000599 const rtc::SSLCertificate* cert) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000600 ASSERT(session_->signaling_thread()->IsCurrent());
wu@webrtc.org4551b792013-10-09 15:37:36 +0000601 // Produces a chain of StatsReports representing this certificate and the rest
602 // of its chain, and adds those reports to |reports_|. The return value is
603 // the id of the leaf report. The provided cert must be non-null, so at least
604 // one report will always be provided and the returned string will never be
605 // empty.
606 ASSERT(cert != NULL);
607
608 std::string issuer_id;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000609 rtc::scoped_ptr<rtc::SSLCertChain> chain;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000610 if (cert->GetChain(chain.accept())) {
611 // This loop runs in reverse, i.e. from root to leaf, so that each
612 // certificate's issuer's report ID is known before the child certificate's
613 // report is generated. The root certificate does not have an issuer ID
614 // value.
615 for (ptrdiff_t i = chain->GetSize() - 1; i >= 0; --i) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000616 const rtc::SSLCertificate& cert_i = chain->Get(i);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000617 issuer_id = AddOneCertificateReport(&cert_i, issuer_id);
618 }
619 }
620 // Add the leaf certificate.
621 return AddOneCertificateReport(cert, issuer_id);
622}
623
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000624std::string StatsCollector::AddCandidateReport(
625 const cricket::Candidate& candidate,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000626 bool local) {
627 scoped_ptr<StatsReport::Id> id(
628 StatsReport::NewCandidateId(local, candidate.id()));
629 StatsReport* report = reports_.Find(*id.get());
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000630 if (!report) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000631 report = reports_.InsertNew(id.Pass());
632 report->set_timestamp(stats_gathering_started_);
633 if (local) {
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000634 report->AddValue(StatsReport::kStatsValueNameCandidateNetworkType,
635 AdapterTypeToStatsType(candidate.network_type()));
636 }
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000637 report->AddValue(StatsReport::kStatsValueNameCandidateIPAddress,
638 candidate.address().ipaddr().ToString());
639 report->AddValue(StatsReport::kStatsValueNameCandidatePortNumber,
640 candidate.address().PortAsString());
641 report->AddValue(StatsReport::kStatsValueNameCandidatePriority,
642 candidate.priority());
643 report->AddValue(StatsReport::kStatsValueNameCandidateType,
644 IceCandidateTypeToStatsType(candidate.type()));
645 report->AddValue(StatsReport::kStatsValueNameCandidateTransportType,
646 candidate.protocol());
647 }
648
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000649 // TODO(tommi): Necessary?
650 return report->id().ToString();
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000651}
652
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653void StatsCollector::ExtractSessionInfo() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000654 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 // Extract information from the base session.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000656 rtc::scoped_ptr<StatsReport::Id> id(
657 StatsReport::NewTypedId(
658 StatsReport::kStatsReportTypeSession, session_->id()));
659 StatsReport* report = reports_.ReplaceOrAddNew(id.Pass());
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000660 report->set_timestamp(stats_gathering_started_);
661 report->ResetValues();
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000662 report->AddBoolean(StatsReport::kStatsValueNameInitiator,
663 session_->initiator());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664
665 cricket::SessionStats stats;
666 if (session_->GetStats(&stats)) {
667 // Store the proxy map away for use in SSRC reporting.
668 proxy_to_transport_ = stats.proxy_to_transport;
669
670 for (cricket::TransportStatsMap::iterator transport_iter
671 = stats.transport_stats.begin();
672 transport_iter != stats.transport_stats.end(); ++transport_iter) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000673 // Attempt to get a copy of the certificates from the transport and
674 // expose them in stats reports. All channels in a transport share the
675 // same local and remote certificates.
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000676 //
677 // Note that Transport::GetIdentity and Transport::GetRemoteCertificate
678 // invoke method calls on the worker thread and block this thread, but
679 // messages are still processed on this thread, which may blow way the
680 // existing transports. So we cannot reuse |transport| after these calls.
wu@webrtc.org4551b792013-10-09 15:37:36 +0000681 std::string local_cert_report_id, remote_cert_report_id;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000682
wu@webrtc.org4551b792013-10-09 15:37:36 +0000683 cricket::Transport* transport =
684 session_->GetTransport(transport_iter->second.content_name);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000685 rtc::scoped_ptr<rtc::SSLIdentity> identity;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000686 if (transport && transport->GetIdentity(identity.accept())) {
687 local_cert_report_id =
688 AddCertificateReports(&(identity->certificate()));
wu@webrtc.org4551b792013-10-09 15:37:36 +0000689 }
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000690
691 transport = session_->GetTransport(transport_iter->second.content_name);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000692 rtc::scoped_ptr<rtc::SSLCertificate> cert;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000693 if (transport && transport->GetRemoteCertificate(cert.accept())) {
694 remote_cert_report_id = AddCertificateReports(cert.get());
695 }
696
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697 for (cricket::TransportChannelStatsList::iterator channel_iter
698 = transport_iter->second.channel_stats.begin();
699 channel_iter != transport_iter->second.channel_stats.end();
700 ++channel_iter) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000701 rtc::scoped_ptr<StatsReport::Id> id(
702 StatsReport::NewComponentId(transport_iter->second.content_name,
703 channel_iter->component));
704 StatsReport* channel_report = reports_.ReplaceOrAddNew(id.Pass());
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000705 channel_report->set_timestamp(stats_gathering_started_);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000706 channel_report->AddValue(StatsReport::kStatsValueNameComponent,
707 channel_iter->component);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000708 if (!local_cert_report_id.empty()) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000709 channel_report->AddValue(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000710 StatsReport::kStatsValueNameLocalCertificateId,
711 local_cert_report_id);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000712 }
713 if (!remote_cert_report_id.empty()) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000714 channel_report->AddValue(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000715 StatsReport::kStatsValueNameRemoteCertificateId,
716 remote_cert_report_id);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000717 }
pthatcher@webrtc.org7bea1ff2015-03-04 01:38:30 +0000718 const std::string& srtp_cipher = channel_iter->srtp_cipher;
719 if (!srtp_cipher.empty()) {
720 channel_report->AddValue(
721 StatsReport::kStatsValueNameSrtpCipher,
722 srtp_cipher);
723 }
724 const std::string& ssl_cipher = channel_iter->ssl_cipher;
725 if (!ssl_cipher.empty()) {
726 channel_report->AddValue(
727 StatsReport::kStatsValueNameDtlsCipher,
728 ssl_cipher);
729 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730 for (size_t i = 0;
731 i < channel_iter->connection_infos.size();
732 ++i) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000733 rtc::scoped_ptr<StatsReport::Id> id(
734 StatsReport::NewCandidatePairId(transport_iter->first,
735 channel_iter->component, static_cast<int>(i)));
736 StatsReport* report = reports_.ReplaceOrAddNew(id.Pass());
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000737 report->set_timestamp(stats_gathering_started_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 // Link from connection to its containing channel.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000739 // TODO(tommi): Any way to avoid ToString here?
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000740 report->AddValue(StatsReport::kStatsValueNameChannelId,
tommi@webrtc.org8e327c42015-01-19 20:41:26 +0000741 channel_report->id().ToString());
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000742
743 const cricket::ConnectionInfo& info =
744 channel_iter->connection_infos[i];
745 report->AddValue(StatsReport::kStatsValueNameBytesSent,
746 info.sent_total_bytes);
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000747 report->AddValue(StatsReport::kStatsValueNameSendPacketsDiscarded,
748 info.sent_discarded_packets);
749 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
750 info.sent_total_packets);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000751 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
752 info.recv_total_bytes);
753 report->AddBoolean(StatsReport::kStatsValueNameWritable,
754 info.writable);
755 report->AddBoolean(StatsReport::kStatsValueNameReadable,
756 info.readable);
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000757 report->AddValue(StatsReport::kStatsValueNameLocalCandidateId,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000758 AddCandidateReport(info.local_candidate, true));
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000759 report->AddValue(
760 StatsReport::kStatsValueNameRemoteCandidateId,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000761 AddCandidateReport(info.remote_candidate, false));
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000762 report->AddValue(StatsReport::kStatsValueNameLocalAddress,
763 info.local_candidate.address().ToString());
764 report->AddValue(StatsReport::kStatsValueNameRemoteAddress,
765 info.remote_candidate.address().ToString());
766 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
767 report->AddValue(StatsReport::kStatsValueNameTransportType,
768 info.local_candidate.protocol());
769 report->AddValue(StatsReport::kStatsValueNameLocalCandidateType,
770 info.local_candidate.type());
771 report->AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
772 info.remote_candidate.type());
pthatcher@webrtc.org7bea1ff2015-03-04 01:38:30 +0000773 report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
774 info.best_connection);
775 if (info.best_connection) {
776 channel_report->AddValue(
777 StatsReport::kStatsValueNameSelectedCandidatePairId,
778 report->id().ToString());
779 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000780 }
781 }
782 }
783 }
784}
785
786void StatsCollector::ExtractVoiceInfo() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000787 ASSERT(session_->signaling_thread()->IsCurrent());
788
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 if (!session_->voice_channel()) {
790 return;
791 }
792 cricket::VoiceMediaInfo voice_info;
793 if (!session_->voice_channel()->GetStats(&voice_info)) {
794 LOG(LS_ERROR) << "Failed to get voice channel stats.";
795 return;
796 }
797 std::string transport_id;
tommi@webrtc.org47218952014-07-15 19:22:37 +0000798 if (!GetTransportIdFromProxy(proxy_to_transport_,
799 session_->voice_channel()->content_name(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 &transport_id)) {
801 LOG(LS_ERROR) << "Failed to get transport name for proxy "
802 << session_->voice_channel()->content_name();
803 return;
804 }
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000805 ExtractStatsFromList(voice_info.receivers, transport_id, this,
806 StatsReport::kReceive);
807 ExtractStatsFromList(voice_info.senders, transport_id, this,
808 StatsReport::kSend);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000809
810 UpdateStatsFromExistingLocalAudioTracks();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811}
812
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000813void StatsCollector::ExtractVideoInfo(
814 PeerConnectionInterface::StatsOutputLevel level) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000815 ASSERT(session_->signaling_thread()->IsCurrent());
816
817 if (!session_->video_channel())
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 return;
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000819
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000820 cricket::StatsOptions options;
821 options.include_received_propagation_stats =
822 (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
823 true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824 cricket::VideoMediaInfo video_info;
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000825 if (!session_->video_channel()->GetStats(options, &video_info)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826 LOG(LS_ERROR) << "Failed to get video channel stats.";
827 return;
828 }
829 std::string transport_id;
tommi@webrtc.org47218952014-07-15 19:22:37 +0000830 if (!GetTransportIdFromProxy(proxy_to_transport_,
831 session_->video_channel()->content_name(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 &transport_id)) {
833 LOG(LS_ERROR) << "Failed to get transport name for proxy "
834 << session_->video_channel()->content_name();
835 return;
836 }
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000837 ExtractStatsFromList(video_info.receivers, transport_id, this,
838 StatsReport::kReceive);
839 ExtractStatsFromList(video_info.senders, transport_id, this,
840 StatsReport::kSend);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841 if (video_info.bw_estimations.size() != 1) {
842 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
843 } else {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000844 rtc::scoped_ptr<StatsReport::Id> report_id(
845 StatsReport::NewBandwidthEstimationId());
846 StatsReport* report = reports_.FindOrAddNew(report_id.Pass());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 ExtractStats(
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000848 video_info.bw_estimations[0], stats_gathering_started_, level, report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 }
850}
851
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000852void StatsCollector::ExtractDataInfo() {
853 ASSERT(session_->signaling_thread()->IsCurrent());
854
855 for (const auto& dc :
856 session_->mediastream_signaling()->sctp_data_channels()) {
decurtis@webrtc.org322a5642015-02-03 22:09:37 +0000857 rtc::scoped_ptr<StatsReport::Id> id(StatsReport::NewTypedIntId(
858 StatsReport::kStatsReportTypeDataChannel, dc->id()));
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000859 StatsReport* report = reports_.ReplaceOrAddNew(id.Pass());
decurtis@webrtc.org322a5642015-02-03 22:09:37 +0000860 report->set_timestamp(stats_gathering_started_);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000861 report->AddValue(StatsReport::kStatsValueNameLabel, dc->label());
862 report->AddValue(StatsReport::kStatsValueNameDataChannelId, dc->id());
863 report->AddValue(StatsReport::kStatsValueNameProtocol, dc->protocol());
864 report->AddValue(StatsReport::kStatsValueNameState,
865 DataChannelInterface::DataStateString(dc->state()));
866 }
867}
868
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000869StatsReport* StatsCollector::GetReport(const StatsReport::StatsType& type,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000870 const std::string& id,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000871 StatsReport::Direction direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000872 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000873 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
874 type == StatsReport::kStatsReportTypeRemoteSsrc);
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000875 return reports_.Find(StatsReport::NewIdWithDirection(type, id, direction));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000876}
877
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000878StatsReport* StatsCollector::GetOrCreateReport(
879 const StatsReport::StatsType& type,
880 const std::string& id,
881 StatsReport::Direction direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000882 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000883 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
884 type == StatsReport::kStatsReportTypeRemoteSsrc);
885 StatsReport* report = GetReport(type, id, direction);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000886 if (report == NULL) {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000887 rtc::scoped_ptr<StatsReport::Id> report_id(
888 StatsReport::NewIdWithDirection(type, id, direction));
889 report = reports_.InsertNew(report_id.Pass());
wu@webrtc.org97077a32013-10-25 21:18:33 +0000890 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000891
wu@webrtc.org97077a32013-10-25 21:18:33 +0000892 return report;
893}
894
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000895void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000896 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000897 // Loop through the existing local audio tracks.
898 for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
899 it != local_audio_tracks_.end(); ++it) {
900 AudioTrackInterface* track = it->first;
901 uint32 ssrc = it->second;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000902 std::string ssrc_id = rtc::ToString<uint32>(ssrc);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000903 StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000904 ssrc_id,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000905 StatsReport::kSend);
henrike@webrtc.orgd3d6bce2014-03-10 20:41:22 +0000906 if (report == NULL) {
907 // This can happen if a local audio track is added to a stream on the
908 // fly and the report has not been set up yet. Do nothing in this case.
909 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
910 continue;
911 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000912
913 // The same ssrc can be used by both local and remote audio tracks.
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000914 const StatsReport::Value* v =
915 report->FindValue(StatsReport::kStatsValueNameTrackId);
916 if (!v || v->value != track->id())
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000917 continue;
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000918
919 UpdateReportFromAudioTrack(track, report);
920 }
921}
922
923void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
924 StatsReport* report) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000925 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000926 ASSERT(track != NULL);
927 if (report == NULL)
928 return;
929
930 int signal_level = 0;
931 if (track->GetSignalLevel(&signal_level)) {
932 report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000933 rtc::ToString<int>(signal_level));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000934 }
935
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000936 rtc::scoped_refptr<AudioProcessorInterface> audio_processor(
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000937 track->GetAudioProcessor());
938 if (audio_processor.get() == NULL)
939 return;
940
941 AudioProcessorInterface::AudioProcessorStats stats;
942 audio_processor->GetStats(&stats);
943 report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
944 stats.typing_noise_detected ? "true" : "false");
945 report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000946 rtc::ToString<int>(stats.echo_return_loss));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000947 report->ReplaceValue(
948 StatsReport::kStatsValueNameEchoReturnLossEnhancement,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000949 rtc::ToString<int>(stats.echo_return_loss_enhancement));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000950 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000951 rtc::ToString<int>(stats.echo_delay_median_ms));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000952 report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000953 rtc::ToString<float>(stats.aec_quality_min));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000954 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000955 rtc::ToString<int>(stats.echo_delay_std_ms));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000956}
957
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000958bool StatsCollector::GetTrackIdBySsrc(uint32 ssrc, std::string* track_id,
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000959 StatsReport::Direction direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000960 ASSERT(session_->signaling_thread()->IsCurrent());
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000961 if (direction == StatsReport::kSend) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000962 if (!session_->GetLocalTrackIdBySsrc(ssrc, track_id)) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000963 LOG(LS_WARNING) << "The SSRC " << ssrc
964 << " is not associated with a sending track";
965 return false;
966 }
967 } else {
tommi@webrtc.org4fb7e252015-01-21 11:36:18 +0000968 ASSERT(direction == StatsReport::kReceive);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000969 if (!session_->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000970 LOG(LS_WARNING) << "The SSRC " << ssrc
971 << " is not associated with a receiving track";
972 return false;
973 }
974 }
975
976 return true;
977}
978
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000979void StatsCollector::ClearUpdateStatsCacheForTest() {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000980 stats_gathering_started_ = 0;
981}
982
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983} // namespace webrtc