blob: e2d444e5e1727cd37857cc8df69750d94a9d7c67 [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
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
38namespace webrtc {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039namespace {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040
guoweis@webrtc.org950c5182014-12-16 23:01:31 +000041// The following is the enum RTCStatsIceCandidateType from
42// http://w3c.github.io/webrtc-stats/#rtcstatsicecandidatetype-enum such that
43// our stats report for ice candidate type could conform to that.
44const char STATSREPORT_LOCAL_PORT_TYPE[] = "host";
45const char STATSREPORT_STUN_PORT_TYPE[] = "serverreflexive";
46const char STATSREPORT_PRFLX_PORT_TYPE[] = "peerreflexive";
47const char STATSREPORT_RELAY_PORT_TYPE[] = "relayed";
48
49// Strings used by the stats collector to report adapter types. This fits the
50// general stype of http://w3c.github.io/webrtc-stats than what
51// AdapterTypeToString does.
52const char* STATSREPORT_ADAPTER_TYPE_ETHERNET = "lan";
53const char* STATSREPORT_ADAPTER_TYPE_WIFI = "wlan";
54const char* STATSREPORT_ADAPTER_TYPE_WWAN = "wwan";
55const char* STATSREPORT_ADAPTER_TYPE_VPN = "vpn";
56
tommi@webrtc.org47218952014-07-15 19:22:37 +000057double GetTimeNow() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000058 return rtc::Timing::WallTimeNow() * rtc::kNumMillisecsPerSec;
tommi@webrtc.org47218952014-07-15 19:22:37 +000059}
60
61bool GetTransportIdFromProxy(const cricket::ProxyTransportMap& map,
62 const std::string& proxy,
63 std::string* transport) {
64 // TODO(hta): Remove handling of empty proxy name once tests do not use it.
65 if (proxy.empty()) {
66 transport->clear();
67 return true;
68 }
69
70 cricket::ProxyTransportMap::const_iterator found = map.find(proxy);
71 if (found == map.end()) {
72 LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
73 return false;
74 }
75
76 std::ostringstream ost;
77 // Component 1 is always used for RTP.
78 ost << "Channel-" << found->second << "-1";
79 *transport = ost.str();
80 return true;
81}
82
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083std::string StatsId(const std::string& type, const std::string& id) {
84 return type + "_" + id;
85}
86
xians@webrtc.org4cb01282014-06-12 14:57:05 +000087std::string StatsId(const std::string& type, const std::string& id,
88 StatsCollector::TrackDirection direction) {
89 ASSERT(direction == StatsCollector::kSending ||
90 direction == StatsCollector::kReceiving);
91
92 // Strings for the direction of the track.
93 const char kSendDirection[] = "send";
94 const char kRecvDirection[] = "recv";
95
96 const std::string direction_id = (direction == StatsCollector::kSending) ?
97 kSendDirection : kRecvDirection;
98 return type + "_" + id + "_" + direction_id;
99}
100
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101bool ExtractValueFromReport(
102 const StatsReport& report,
tommi@webrtc.org242068d2014-07-14 20:19:56 +0000103 StatsReport::StatsValueName name,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104 std::string* value) {
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000105 StatsReport::Values::const_iterator it = report.values().begin();
106 for (; it != report.values().end(); ++it) {
107 if ((*it)->name == name) {
108 *value = (*it)->value;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109 return true;
110 }
111 }
112 return false;
113}
114
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000115void AddTrackReport(StatsSet* reports, const std::string& track_id) {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000116 // Adds an empty track report.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000117 StatsReport* report = reports->ReplaceOrAddNew(
118 StatsId(StatsReport::kStatsReportTypeTrack, track_id));
119 report->type = StatsReport::kStatsReportTypeTrack;
120 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
xians@webrtc.org01bda202014-07-09 07:38:38 +0000121}
122
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123template <class TrackVector>
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000124void CreateTrackReports(const TrackVector& tracks, StatsSet* reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125 for (size_t j = 0; j < tracks.size(); ++j) {
126 webrtc::MediaStreamTrackInterface* track = tracks[j];
xians@webrtc.org01bda202014-07-09 07:38:38 +0000127 AddTrackReport(reports, track->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128 }
129}
130
131void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
132 report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
133 info.audio_level);
134 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
135 info.bytes_rcvd);
136 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
137 info.jitter_ms);
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000138 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
139 info.jitter_buffer_ms);
140 report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
141 info.jitter_buffer_preferred_ms);
142 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
143 info.delay_estimate_ms);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000144 report->AddValue(StatsReport::kStatsValueNameExpandRate,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000145 rtc::ToString<float>(info.expand_rate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
147 info.packets_rcvd);
148 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
149 info.packets_lost);
buildbot@webrtc.org3e01e0b2014-05-13 17:54:10 +0000150 report->AddValue(StatsReport::kStatsValueNameDecodingCTSG,
151 info.decoding_calls_to_silence_generator);
152 report->AddValue(StatsReport::kStatsValueNameDecodingCTN,
153 info.decoding_calls_to_neteq);
154 report->AddValue(StatsReport::kStatsValueNameDecodingNormal,
155 info.decoding_normal);
156 report->AddValue(StatsReport::kStatsValueNameDecodingPLC,
157 info.decoding_plc);
158 report->AddValue(StatsReport::kStatsValueNameDecodingCNG,
159 info.decoding_cng);
160 report->AddValue(StatsReport::kStatsValueNameDecodingPLCCNG,
161 info.decoding_plc_cng);
buildbot@webrtc.orgb525a9d2014-06-03 09:42:15 +0000162 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
163 info.capture_start_ntp_time_ms);
buildbot@webrtc.org7e71b772014-06-13 01:14:01 +0000164 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165}
166
167void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
168 report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
169 info.audio_level);
170 report->AddValue(StatsReport::kStatsValueNameBytesSent,
171 info.bytes_sent);
172 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
173 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000174 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
175 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
177 info.jitter_ms);
178 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
179 report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000180 rtc::ToString<float>(info.aec_quality_min));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000181 report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
182 info.echo_delay_median_ms);
183 report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
184 info.echo_delay_std_ms);
185 report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
186 info.echo_return_loss);
187 report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
188 info.echo_return_loss_enhancement);
189 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000190 report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
191 info.typing_noise_detected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192}
193
194void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
195 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
196 info.bytes_rcvd);
197 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
198 info.packets_rcvd);
199 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
200 info.packets_lost);
201
202 report->AddValue(StatsReport::kStatsValueNameFirsSent,
203 info.firs_sent);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000204 report->AddValue(StatsReport::kStatsValueNamePlisSent,
205 info.plis_sent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206 report->AddValue(StatsReport::kStatsValueNameNacksSent,
207 info.nacks_sent);
208 report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
209 info.frame_width);
210 report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
211 info.frame_height);
212 report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
213 info.framerate_rcvd);
214 report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
215 info.framerate_decoded);
216 report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
217 info.framerate_output);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000218
219 report->AddValue(StatsReport::kStatsValueNameDecodeMs,
220 info.decode_ms);
221 report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
222 info.max_decode_ms);
223 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
224 info.current_delay_ms);
225 report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
226 info.target_delay_ms);
227 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
228 info.jitter_buffer_ms);
229 report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
230 info.min_playout_delay_ms);
231 report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
232 info.render_delay_ms);
buildbot@webrtc.org0581f0b2014-05-06 21:36:31 +0000233
234 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
235 info.capture_start_ntp_time_ms);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000236}
237
238void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
239 report->AddValue(StatsReport::kStatsValueNameBytesSent,
240 info.bytes_sent);
241 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
242 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000243 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
244 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245
246 report->AddValue(StatsReport::kStatsValueNameFirsReceived,
247 info.firs_rcvd);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000248 report->AddValue(StatsReport::kStatsValueNamePlisReceived,
249 info.plis_rcvd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250 report->AddValue(StatsReport::kStatsValueNameNacksReceived,
251 info.nacks_rcvd);
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000252 report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
253 info.input_frame_width);
254 report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
255 info.input_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256 report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000257 info.send_frame_width);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258 report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000259 info.send_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
261 info.framerate_input);
262 report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
263 info.framerate_sent);
264 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
265 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000266 report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
267 (info.adapt_reason & 0x1) > 0);
268 report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
269 (info.adapt_reason & 0x2) > 0);
270 report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
271 (info.adapt_reason & 0x4) > 0);
buildbot@webrtc.org71dffb72014-06-24 07:24:49 +0000272 report->AddValue(StatsReport::kStatsValueNameAdaptationChanges,
273 info.adapt_changes);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000274 report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
275 report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
276 info.capture_jitter_ms);
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000277 report->AddValue(StatsReport::kStatsValueNameCaptureQueueDelayMsPerS,
278 info.capture_queue_delay_ms_per_s);
279 report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
280 info.encode_usage_percent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000281}
282
283void ExtractStats(const cricket::BandwidthEstimationInfo& info,
284 double stats_gathering_started,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000285 PeerConnectionInterface::StatsOutputLevel level,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 StatsReport* report) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000287 report->type = StatsReport::kStatsReportTypeBwe;
288
289 // Clear out stats from previous GatherStats calls if any.
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000290 if (report->timestamp() != stats_gathering_started) {
291 report->ResetValues();
292 report->set_timestamp(stats_gathering_started);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 }
294
295 report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
296 info.available_send_bandwidth);
297 report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
298 info.available_recv_bandwidth);
299 report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
300 info.target_enc_bitrate);
301 report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
302 info.actual_enc_bitrate);
303 report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
304 info.retransmit_bitrate);
305 report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
306 info.transmit_bitrate);
307 report->AddValue(StatsReport::kStatsValueNameBucketDelay,
308 info.bucket_delay);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000309 if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
310 report->AddValue(
311 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
312 info.total_received_propagation_delta_ms);
313 if (info.recent_received_propagation_delta_ms.size() > 0) {
314 report->AddValue(
315 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
316 info.recent_received_propagation_delta_ms);
317 report->AddValue(
318 StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
319 info.recent_received_packet_group_arrival_time_ms);
320 }
321 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322}
323
wu@webrtc.org97077a32013-10-25 21:18:33 +0000324void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
325 StatsReport* report) {
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000326 report->set_timestamp(info.remote_stats[0].timestamp);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000327 // TODO(hta): Extract some stats here.
328}
329
330void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
331 StatsReport* report) {
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000332 report->set_timestamp(info.remote_stats[0].timestamp);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000333 // TODO(hta): Extract some stats here.
334}
335
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336// Template to extract stats from a data vector.
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000337// In order to use the template, the functions that are called from it,
338// ExtractStats and ExtractRemoteStats, must be defined and overloaded
339// for each type.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340template<typename T>
341void ExtractStatsFromList(const std::vector<T>& data,
342 const std::string& transport_id,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000343 StatsCollector* collector,
344 StatsCollector::TrackDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000345 typename std::vector<T>::const_iterator it = data.begin();
346 for (; it != data.end(); ++it) {
347 std::string id;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000348 uint32 ssrc = it->ssrc();
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000349 // Each track can have stats for both local and remote objects.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000350 // TODO(hta): Handle the case of multiple SSRCs per object.
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000351 StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id,
352 direction);
353 if (report)
354 ExtractStats(*it, report);
355
wu@webrtc.org97077a32013-10-25 21:18:33 +0000356 if (it->remote_stats.size() > 0) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000357 report = collector->PrepareRemoteReport(ssrc, transport_id,
358 direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000359 if (!report) {
360 continue;
361 }
362 ExtractRemoteStats(*it, report);
363 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000364 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000365}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000366
367} // namespace
368
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000369const char* IceCandidateTypeToStatsType(const std::string& candidate_type) {
370 if (candidate_type == cricket::LOCAL_PORT_TYPE) {
371 return STATSREPORT_LOCAL_PORT_TYPE;
372 }
373 if (candidate_type == cricket::STUN_PORT_TYPE) {
374 return STATSREPORT_STUN_PORT_TYPE;
375 }
376 if (candidate_type == cricket::PRFLX_PORT_TYPE) {
377 return STATSREPORT_PRFLX_PORT_TYPE;
378 }
379 if (candidate_type == cricket::RELAY_PORT_TYPE) {
380 return STATSREPORT_RELAY_PORT_TYPE;
381 }
382 ASSERT(false);
383 return "unknown";
384}
385
386const char* AdapterTypeToStatsType(rtc::AdapterType type) {
387 switch (type) {
388 case rtc::ADAPTER_TYPE_UNKNOWN:
389 return "unknown";
390 case rtc::ADAPTER_TYPE_ETHERNET:
391 return STATSREPORT_ADAPTER_TYPE_ETHERNET;
392 case rtc::ADAPTER_TYPE_WIFI:
393 return STATSREPORT_ADAPTER_TYPE_WIFI;
394 case rtc::ADAPTER_TYPE_CELLULAR:
395 return STATSREPORT_ADAPTER_TYPE_WWAN;
396 case rtc::ADAPTER_TYPE_VPN:
397 return STATSREPORT_ADAPTER_TYPE_VPN;
398 default:
399 ASSERT(false);
400 return "";
401 }
402}
403
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000404StatsCollector::StatsCollector(WebRtcSession* session)
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000405 : session_(session),
406 stats_gathering_started_(0) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000407 ASSERT(session_);
408}
409
410StatsCollector::~StatsCollector() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000411 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000412}
413
414// Adds a MediaStream with tracks that can be used as a |selector| in a call
415// to GetStats.
416void StatsCollector::AddStream(MediaStreamInterface* stream) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000417 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418 ASSERT(stream != NULL);
419
420 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
421 &reports_);
422 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
423 &reports_);
424}
425
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000426void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
427 uint32 ssrc) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000428 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000429 ASSERT(audio_track != NULL);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000430 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
431 it != local_audio_tracks_.end(); ++it) {
432 ASSERT(it->first != audio_track || it->second != ssrc);
433 }
xians@webrtc.org01bda202014-07-09 07:38:38 +0000434
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000435 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
xians@webrtc.org01bda202014-07-09 07:38:38 +0000436
437 // Create the kStatsReportTypeTrack report for the new track if there is no
438 // report yet.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000439 StatsReport* found = reports_.Find(
xians@webrtc.org01bda202014-07-09 07:38:38 +0000440 StatsId(StatsReport::kStatsReportTypeTrack, audio_track->id()));
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000441 if (!found)
xians@webrtc.org01bda202014-07-09 07:38:38 +0000442 AddTrackReport(&reports_, audio_track->id());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000443}
444
445void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
446 uint32 ssrc) {
447 ASSERT(audio_track != NULL);
448 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
449 it != local_audio_tracks_.end(); ++it) {
450 if (it->first == audio_track && it->second == ssrc) {
451 local_audio_tracks_.erase(it);
452 return;
453 }
454 }
455
456 ASSERT(false);
457}
458
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000459void StatsCollector::GetStats(MediaStreamTrackInterface* track,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460 StatsReports* reports) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000461 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462 ASSERT(reports != NULL);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000463 ASSERT(reports->empty());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465 if (!track) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000466 StatsSet::const_iterator it;
467 for (it = reports_.begin(); it != reports_.end(); ++it)
468 reports->push_back(&(*it));
469 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 }
471
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000472 StatsReport* report =
473 reports_.Find(StatsId(StatsReport::kStatsReportTypeSession,
474 session_->id()));
475 if (report)
476 reports->push_back(report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000477
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000478 report = reports_.Find(
479 StatsId(StatsReport::kStatsReportTypeTrack, track->id()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000481 if (!report)
482 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000484 reports->push_back(report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485
486 std::string track_id;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000487 for (StatsSet::const_iterator it = reports_.begin(); it != reports_.end();
488 ++it) {
489 if (it->type != StatsReport::kStatsReportTypeSsrc)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490 continue;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000491
492 if (ExtractValueFromReport(*it,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493 StatsReport::kStatsValueNameTrackId,
494 &track_id)) {
495 if (track_id == track->id()) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000496 reports->push_back(&(*it));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 }
498 }
499 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500}
501
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000502void
503StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000504 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 double time_now = GetTimeNow();
506 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
507 // ms apart will be ignored.
508 const double kMinGatherStatsPeriod = 50;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000509 if (stats_gathering_started_ != 0 &&
510 stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 return;
512 }
513 stats_gathering_started_ = time_now;
514
515 if (session_) {
516 ExtractSessionInfo();
517 ExtractVoiceInfo();
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000518 ExtractVideoInfo(level);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000519 ExtractDataInfo();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520 }
521}
522
wu@webrtc.org97077a32013-10-25 21:18:33 +0000523StatsReport* StatsCollector::PrepareLocalReport(
524 uint32 ssrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000525 const std::string& transport_id,
526 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000527 ASSERT(session_->signaling_thread()->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000528 const std::string ssrc_id = rtc::ToString<uint32>(ssrc);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000529 StatsReport* report = reports_.Find(
530 StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id, direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531
xians@webrtc.org01bda202014-07-09 07:38:38 +0000532 // Use the ID of the track that is currently mapped to the SSRC, if any.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 std::string track_id;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000534 if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000535 if (!report) {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000536 // The ssrc is not used by any track or existing report, return NULL
537 // in such case to indicate no report is prepared for the ssrc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 return NULL;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000539 }
540
541 // The ssrc is not used by any existing track. Keeps the old track id
542 // since we want to report the stats for inactive ssrc.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000543 ExtractValueFromReport(*report,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 StatsReport::kStatsValueNameTrackId,
545 &track_id);
546 }
547
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000548 report = GetOrCreateReport(
549 StatsReport::kStatsReportTypeSsrc, ssrc_id, direction);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550
551 // Clear out stats from previous GatherStats calls if any.
xians@webrtc.org01bda202014-07-09 07:38:38 +0000552 // This is required since the report will be returned for the new values.
553 // Having the old values in the report will lead to multiple values with
554 // the same name.
555 // TODO(xians): Consider changing StatsReport to use map instead of vector.
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000556 report->ResetValues();
557 report->set_timestamp(stats_gathering_started_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558
559 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
560 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
561 // Add the mapping of SSRC to transport.
562 report->AddValue(StatsReport::kStatsValueNameTransportId,
563 transport_id);
564 return report;
565}
566
wu@webrtc.org97077a32013-10-25 21:18:33 +0000567StatsReport* StatsCollector::PrepareRemoteReport(
568 uint32 ssrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000569 const std::string& transport_id,
570 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000571 ASSERT(session_->signaling_thread()->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000572 const std::string ssrc_id = rtc::ToString<uint32>(ssrc);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000573 StatsReport* report = reports_.Find(
574 StatsId(StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction));
wu@webrtc.org97077a32013-10-25 21:18:33 +0000575
xians@webrtc.org01bda202014-07-09 07:38:38 +0000576 // Use the ID of the track that is currently mapped to the SSRC, if any.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000577 std::string track_id;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000578 if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000579 if (!report) {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000580 // The ssrc is not used by any track or existing report, return NULL
581 // in such case to indicate no report is prepared for the ssrc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000582 return NULL;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000583 }
584
585 // The ssrc is not used by any existing track. Keeps the old track id
586 // since we want to report the stats for inactive ssrc.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000587 ExtractValueFromReport(*report,
wu@webrtc.org97077a32013-10-25 21:18:33 +0000588 StatsReport::kStatsValueNameTrackId,
589 &track_id);
590 }
591
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000592 report = GetOrCreateReport(
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000593 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000594
595 // Clear out stats from previous GatherStats calls if any.
596 // The timestamp will be added later. Zero it for debugging.
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000597 report->ResetValues();
598 report->set_timestamp(0);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000599
600 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
601 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
602 // Add the mapping of SSRC to transport.
603 report->AddValue(StatsReport::kStatsValueNameTransportId,
604 transport_id);
605 return report;
606}
607
wu@webrtc.org4551b792013-10-09 15:37:36 +0000608std::string StatsCollector::AddOneCertificateReport(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000609 const rtc::SSLCertificate* cert, const std::string& issuer_id) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000610 // TODO(bemasc): Move this computation to a helper class that caches these
611 // values to reduce CPU use in GetStats. This will require adding a fast
612 // SSLCertificate::Equals() method to detect certificate changes.
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000613
614 std::string digest_algorithm;
615 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
616 return std::string();
617
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000618 rtc::scoped_ptr<rtc::SSLFingerprint> ssl_fingerprint(
619 rtc::SSLFingerprint::Create(digest_algorithm, cert));
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000620
621 // SSLFingerprint::Create can fail if the algorithm returned by
622 // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
623 // implementation of SSLCertificate::ComputeDigest. This currently happens
624 // with MD5- and SHA-224-signed certificates when linked to libNSS.
625 if (!ssl_fingerprint)
626 return std::string();
627
wu@webrtc.org4551b792013-10-09 15:37:36 +0000628 std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
629
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000630 rtc::Buffer der_buffer;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000631 cert->ToDER(&der_buffer);
632 std::string der_base64;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000633 rtc::Base64::EncodeFromArray(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000634 der_buffer.data(), der_buffer.length(), &der_base64);
635
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000636 StatsReport* report = reports_.ReplaceOrAddNew(
637 StatsId(StatsReport::kStatsReportTypeCertificate, fingerprint));
638 report->type = StatsReport::kStatsReportTypeCertificate;
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000639 report->set_timestamp(stats_gathering_started_);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000640 report->AddValue(StatsReport::kStatsValueNameFingerprint, fingerprint);
641 report->AddValue(StatsReport::kStatsValueNameFingerprintAlgorithm,
642 digest_algorithm);
643 report->AddValue(StatsReport::kStatsValueNameDer, der_base64);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000644 if (!issuer_id.empty())
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000645 report->AddValue(StatsReport::kStatsValueNameIssuerId, issuer_id);
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000646 return report->id().ToString();
wu@webrtc.org4551b792013-10-09 15:37:36 +0000647}
648
649std::string StatsCollector::AddCertificateReports(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000650 const rtc::SSLCertificate* cert) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000651 // Produces a chain of StatsReports representing this certificate and the rest
652 // of its chain, and adds those reports to |reports_|. The return value is
653 // the id of the leaf report. The provided cert must be non-null, so at least
654 // one report will always be provided and the returned string will never be
655 // empty.
656 ASSERT(cert != NULL);
657
658 std::string issuer_id;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000659 rtc::scoped_ptr<rtc::SSLCertChain> chain;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000660 if (cert->GetChain(chain.accept())) {
661 // This loop runs in reverse, i.e. from root to leaf, so that each
662 // certificate's issuer's report ID is known before the child certificate's
663 // report is generated. The root certificate does not have an issuer ID
664 // value.
665 for (ptrdiff_t i = chain->GetSize() - 1; i >= 0; --i) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000666 const rtc::SSLCertificate& cert_i = chain->Get(i);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000667 issuer_id = AddOneCertificateReport(&cert_i, issuer_id);
668 }
669 }
670 // Add the leaf certificate.
671 return AddOneCertificateReport(cert, issuer_id);
672}
673
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000674std::string StatsCollector::AddCandidateReport(
675 const cricket::Candidate& candidate,
676 const std::string& report_type) {
677 std::ostringstream ost;
678 ost << "Cand-" << candidate.id();
679 StatsReport* report = reports_.Find(ost.str());
680 if (!report) {
681 report = reports_.InsertNew(ost.str());
682 DCHECK(StatsReport::kStatsReportTypeIceLocalCandidate == report_type ||
683 StatsReport::kStatsReportTypeIceRemoteCandidate == report_type);
684 report->type = report_type;
685 if (report_type == StatsReport::kStatsReportTypeIceLocalCandidate) {
686 report->AddValue(StatsReport::kStatsValueNameCandidateNetworkType,
687 AdapterTypeToStatsType(candidate.network_type()));
688 }
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000689 report->set_timestamp(stats_gathering_started_);
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000690 report->AddValue(StatsReport::kStatsValueNameCandidateIPAddress,
691 candidate.address().ipaddr().ToString());
692 report->AddValue(StatsReport::kStatsValueNameCandidatePortNumber,
693 candidate.address().PortAsString());
694 report->AddValue(StatsReport::kStatsValueNameCandidatePriority,
695 candidate.priority());
696 report->AddValue(StatsReport::kStatsValueNameCandidateType,
697 IceCandidateTypeToStatsType(candidate.type()));
698 report->AddValue(StatsReport::kStatsValueNameCandidateTransportType,
699 candidate.protocol());
700 }
701
702 return ost.str();
703}
704
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705void StatsCollector::ExtractSessionInfo() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000706 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 // Extract information from the base session.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000708 StatsReport* report = reports_.ReplaceOrAddNew(
709 StatsId(StatsReport::kStatsReportTypeSession, session_->id()));
710 report->type = StatsReport::kStatsReportTypeSession;
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000711 report->set_timestamp(stats_gathering_started_);
712 report->ResetValues();
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000713 report->AddBoolean(StatsReport::kStatsValueNameInitiator,
714 session_->initiator());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000715
716 cricket::SessionStats stats;
717 if (session_->GetStats(&stats)) {
718 // Store the proxy map away for use in SSRC reporting.
719 proxy_to_transport_ = stats.proxy_to_transport;
720
721 for (cricket::TransportStatsMap::iterator transport_iter
722 = stats.transport_stats.begin();
723 transport_iter != stats.transport_stats.end(); ++transport_iter) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000724 // Attempt to get a copy of the certificates from the transport and
725 // expose them in stats reports. All channels in a transport share the
726 // same local and remote certificates.
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000727 //
728 // Note that Transport::GetIdentity and Transport::GetRemoteCertificate
729 // invoke method calls on the worker thread and block this thread, but
730 // messages are still processed on this thread, which may blow way the
731 // existing transports. So we cannot reuse |transport| after these calls.
wu@webrtc.org4551b792013-10-09 15:37:36 +0000732 std::string local_cert_report_id, remote_cert_report_id;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000733
wu@webrtc.org4551b792013-10-09 15:37:36 +0000734 cricket::Transport* transport =
735 session_->GetTransport(transport_iter->second.content_name);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000736 rtc::scoped_ptr<rtc::SSLIdentity> identity;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000737 if (transport && transport->GetIdentity(identity.accept())) {
738 local_cert_report_id =
739 AddCertificateReports(&(identity->certificate()));
wu@webrtc.org4551b792013-10-09 15:37:36 +0000740 }
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000741
742 transport = session_->GetTransport(transport_iter->second.content_name);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000743 rtc::scoped_ptr<rtc::SSLCertificate> cert;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000744 if (transport && transport->GetRemoteCertificate(cert.accept())) {
745 remote_cert_report_id = AddCertificateReports(cert.get());
746 }
747
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 for (cricket::TransportChannelStatsList::iterator channel_iter
749 = transport_iter->second.channel_stats.begin();
750 channel_iter != transport_iter->second.channel_stats.end();
751 ++channel_iter) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 std::ostringstream ostc;
753 ostc << "Channel-" << transport_iter->second.content_name
754 << "-" << channel_iter->component;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000755 StatsReport* channel_report = reports_.ReplaceOrAddNew(ostc.str());
756 channel_report->type = StatsReport::kStatsReportTypeComponent;
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000757 channel_report->set_timestamp(stats_gathering_started_);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000758 channel_report->AddValue(StatsReport::kStatsValueNameComponent,
759 channel_iter->component);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000760 if (!local_cert_report_id.empty()) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000761 channel_report->AddValue(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000762 StatsReport::kStatsValueNameLocalCertificateId,
763 local_cert_report_id);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000764 }
765 if (!remote_cert_report_id.empty()) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000766 channel_report->AddValue(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000767 StatsReport::kStatsValueNameRemoteCertificateId,
768 remote_cert_report_id);
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000769 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 for (size_t i = 0;
771 i < channel_iter->connection_infos.size();
772 ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 std::ostringstream ost;
774 ost << "Conn-" << transport_iter->first << "-"
775 << channel_iter->component << "-" << i;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000776 StatsReport* report = reports_.ReplaceOrAddNew(ost.str());
777 report->type = StatsReport::kStatsReportTypeCandidatePair;
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000778 report->set_timestamp(stats_gathering_started_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779 // Link from connection to its containing channel.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000780 report->AddValue(StatsReport::kStatsValueNameChannelId,
tommi@webrtc.org5b76fd72015-01-19 16:49:33 +0000781 channel_report->id().ToString());
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000782
783 const cricket::ConnectionInfo& info =
784 channel_iter->connection_infos[i];
785 report->AddValue(StatsReport::kStatsValueNameBytesSent,
786 info.sent_total_bytes);
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000787 report->AddValue(StatsReport::kStatsValueNameSendPacketsDiscarded,
788 info.sent_discarded_packets);
789 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
790 info.sent_total_packets);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000791 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
792 info.recv_total_bytes);
793 report->AddBoolean(StatsReport::kStatsValueNameWritable,
794 info.writable);
795 report->AddBoolean(StatsReport::kStatsValueNameReadable,
796 info.readable);
797 report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
798 info.best_connection);
guoweis@webrtc.org950c5182014-12-16 23:01:31 +0000799 report->AddValue(StatsReport::kStatsValueNameLocalCandidateId,
800 AddCandidateReport(
801 info.local_candidate,
802 StatsReport::kStatsReportTypeIceLocalCandidate));
803 report->AddValue(
804 StatsReport::kStatsValueNameRemoteCandidateId,
805 AddCandidateReport(
806 info.remote_candidate,
807 StatsReport::kStatsReportTypeIceRemoteCandidate));
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000808 report->AddValue(StatsReport::kStatsValueNameLocalAddress,
809 info.local_candidate.address().ToString());
810 report->AddValue(StatsReport::kStatsValueNameRemoteAddress,
811 info.remote_candidate.address().ToString());
812 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
813 report->AddValue(StatsReport::kStatsValueNameTransportType,
814 info.local_candidate.protocol());
815 report->AddValue(StatsReport::kStatsValueNameLocalCandidateType,
816 info.local_candidate.type());
817 report->AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
818 info.remote_candidate.type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 }
820 }
821 }
822 }
823}
824
825void StatsCollector::ExtractVoiceInfo() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000826 ASSERT(session_->signaling_thread()->IsCurrent());
827
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 if (!session_->voice_channel()) {
829 return;
830 }
831 cricket::VoiceMediaInfo voice_info;
832 if (!session_->voice_channel()->GetStats(&voice_info)) {
833 LOG(LS_ERROR) << "Failed to get voice channel stats.";
834 return;
835 }
836 std::string transport_id;
tommi@webrtc.org47218952014-07-15 19:22:37 +0000837 if (!GetTransportIdFromProxy(proxy_to_transport_,
838 session_->voice_channel()->content_name(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839 &transport_id)) {
840 LOG(LS_ERROR) << "Failed to get transport name for proxy "
841 << session_->voice_channel()->content_name();
842 return;
843 }
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000844 ExtractStatsFromList(voice_info.receivers, transport_id, this, kReceiving);
845 ExtractStatsFromList(voice_info.senders, transport_id, this, kSending);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000846
847 UpdateStatsFromExistingLocalAudioTracks();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848}
849
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000850void StatsCollector::ExtractVideoInfo(
851 PeerConnectionInterface::StatsOutputLevel level) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000852 ASSERT(session_->signaling_thread()->IsCurrent());
853
854 if (!session_->video_channel())
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 return;
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000856
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000857 cricket::StatsOptions options;
858 options.include_received_propagation_stats =
859 (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
860 true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861 cricket::VideoMediaInfo video_info;
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000862 if (!session_->video_channel()->GetStats(options, &video_info)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 LOG(LS_ERROR) << "Failed to get video channel stats.";
864 return;
865 }
866 std::string transport_id;
tommi@webrtc.org47218952014-07-15 19:22:37 +0000867 if (!GetTransportIdFromProxy(proxy_to_transport_,
868 session_->video_channel()->content_name(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869 &transport_id)) {
870 LOG(LS_ERROR) << "Failed to get transport name for proxy "
871 << session_->video_channel()->content_name();
872 return;
873 }
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000874 ExtractStatsFromList(video_info.receivers, transport_id, this, kReceiving);
875 ExtractStatsFromList(video_info.senders, transport_id, this, kSending);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876 if (video_info.bw_estimations.size() != 1) {
877 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
878 } else {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000879 StatsReport* report =
880 reports_.FindOrAddNew(StatsReport::kStatsReportVideoBweId);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 ExtractStats(
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000882 video_info.bw_estimations[0], stats_gathering_started_, level, report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 }
884}
885
decurtis@webrtc.org487a4442015-01-15 22:55:07 +0000886void StatsCollector::ExtractDataInfo() {
887 ASSERT(session_->signaling_thread()->IsCurrent());
888
889 for (const auto& dc :
890 session_->mediastream_signaling()->sctp_data_channels()) {
891 StatsReport* report = reports_.ReplaceOrAddNew(
892 StatsId(StatsReport::kStatsReportTypeDataChannel, dc->label()));
893 report->type = StatsReport::kStatsReportTypeDataChannel;
894 report->AddValue(StatsReport::kStatsValueNameLabel, dc->label());
895 report->AddValue(StatsReport::kStatsValueNameDataChannelId, dc->id());
896 report->AddValue(StatsReport::kStatsValueNameProtocol, dc->protocol());
897 report->AddValue(StatsReport::kStatsValueNameState,
898 DataChannelInterface::DataStateString(dc->state()));
899 }
900}
901
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000902StatsReport* StatsCollector::GetReport(const std::string& type,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000903 const std::string& id,
904 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000905 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000906 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
907 type == StatsReport::kStatsReportTypeRemoteSsrc);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000908 return reports_.Find(StatsId(type, id, direction));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000909}
910
911StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000912 const std::string& id,
913 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000914 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000915 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
916 type == StatsReport::kStatsReportTypeRemoteSsrc);
917 StatsReport* report = GetReport(type, id, direction);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000918 if (report == NULL) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000919 std::string statsid = StatsId(type, id, direction);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000920 report = reports_.FindOrAddNew(statsid);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000921 report->type = type;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000922 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000923
wu@webrtc.org97077a32013-10-25 21:18:33 +0000924 return report;
925}
926
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000927void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000928 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000929 // Loop through the existing local audio tracks.
930 for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
931 it != local_audio_tracks_.end(); ++it) {
932 AudioTrackInterface* track = it->first;
933 uint32 ssrc = it->second;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000934 std::string ssrc_id = rtc::ToString<uint32>(ssrc);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000935 StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000936 ssrc_id,
937 kSending);
henrike@webrtc.orgd3d6bce2014-03-10 20:41:22 +0000938 if (report == NULL) {
939 // This can happen if a local audio track is added to a stream on the
940 // fly and the report has not been set up yet. Do nothing in this case.
941 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
942 continue;
943 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000944
945 // The same ssrc can be used by both local and remote audio tracks.
946 std::string track_id;
947 if (!ExtractValueFromReport(*report,
948 StatsReport::kStatsValueNameTrackId,
949 &track_id) ||
950 track_id != track->id()) {
951 continue;
952 }
953
954 UpdateReportFromAudioTrack(track, report);
955 }
956}
957
958void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
959 StatsReport* report) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000960 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000961 ASSERT(track != NULL);
962 if (report == NULL)
963 return;
964
965 int signal_level = 0;
966 if (track->GetSignalLevel(&signal_level)) {
967 report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000968 rtc::ToString<int>(signal_level));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000969 }
970
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000971 rtc::scoped_refptr<AudioProcessorInterface> audio_processor(
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000972 track->GetAudioProcessor());
973 if (audio_processor.get() == NULL)
974 return;
975
976 AudioProcessorInterface::AudioProcessorStats stats;
977 audio_processor->GetStats(&stats);
978 report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
979 stats.typing_noise_detected ? "true" : "false");
980 report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000981 rtc::ToString<int>(stats.echo_return_loss));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000982 report->ReplaceValue(
983 StatsReport::kStatsValueNameEchoReturnLossEnhancement,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000984 rtc::ToString<int>(stats.echo_return_loss_enhancement));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000985 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000986 rtc::ToString<int>(stats.echo_delay_median_ms));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000987 report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000988 rtc::ToString<float>(stats.aec_quality_min));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000989 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000990 rtc::ToString<int>(stats.echo_delay_std_ms));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000991}
992
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000993bool StatsCollector::GetTrackIdBySsrc(uint32 ssrc, std::string* track_id,
994 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000995 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000996 if (direction == kSending) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000997 if (!session_->GetLocalTrackIdBySsrc(ssrc, track_id)) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000998 LOG(LS_WARNING) << "The SSRC " << ssrc
999 << " is not associated with a sending track";
1000 return false;
1001 }
1002 } else {
1003 ASSERT(direction == kReceiving);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001004 if (!session_->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +00001005 LOG(LS_WARNING) << "The SSRC " << ssrc
1006 << " is not associated with a receiving track";
1007 return false;
1008 }
1009 }
1010
1011 return true;
1012}
1013
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +00001014void StatsCollector::ClearUpdateStatsCacheForTest() {
xians@webrtc.org01bda202014-07-09 07:38:38 +00001015 stats_gathering_started_ = 0;
1016}
1017
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018} // namespace webrtc