blob: f1c91b1c25158b3d781af7efebc16a63b53fab43 [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
tommi@webrtc.org47218952014-07-15 19:22:37 +000041double GetTimeNow() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000042 return rtc::Timing::WallTimeNow() * rtc::kNumMillisecsPerSec;
tommi@webrtc.org47218952014-07-15 19:22:37 +000043}
44
45bool GetTransportIdFromProxy(const cricket::ProxyTransportMap& map,
46 const std::string& proxy,
47 std::string* transport) {
48 // TODO(hta): Remove handling of empty proxy name once tests do not use it.
49 if (proxy.empty()) {
50 transport->clear();
51 return true;
52 }
53
54 cricket::ProxyTransportMap::const_iterator found = map.find(proxy);
55 if (found == map.end()) {
56 LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
57 return false;
58 }
59
60 std::ostringstream ost;
61 // Component 1 is always used for RTP.
62 ost << "Channel-" << found->second << "-1";
63 *transport = ost.str();
64 return true;
65}
66
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067std::string StatsId(const std::string& type, const std::string& id) {
68 return type + "_" + id;
69}
70
xians@webrtc.org4cb01282014-06-12 14:57:05 +000071std::string StatsId(const std::string& type, const std::string& id,
72 StatsCollector::TrackDirection direction) {
73 ASSERT(direction == StatsCollector::kSending ||
74 direction == StatsCollector::kReceiving);
75
76 // Strings for the direction of the track.
77 const char kSendDirection[] = "send";
78 const char kRecvDirection[] = "recv";
79
80 const std::string direction_id = (direction == StatsCollector::kSending) ?
81 kSendDirection : kRecvDirection;
82 return type + "_" + id + "_" + direction_id;
83}
84
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085bool ExtractValueFromReport(
86 const StatsReport& report,
tommi@webrtc.org242068d2014-07-14 20:19:56 +000087 StatsReport::StatsValueName name,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088 std::string* value) {
89 StatsReport::Values::const_iterator it = report.values.begin();
90 for (; it != report.values.end(); ++it) {
91 if (it->name == name) {
92 *value = it->value;
93 return true;
94 }
95 }
96 return false;
97}
98
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000099void AddTrackReport(StatsSet* reports, const std::string& track_id) {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000100 // Adds an empty track report.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000101 StatsReport* report = reports->ReplaceOrAddNew(
102 StatsId(StatsReport::kStatsReportTypeTrack, track_id));
103 report->type = StatsReport::kStatsReportTypeTrack;
104 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
xians@webrtc.org01bda202014-07-09 07:38:38 +0000105}
106
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107template <class TrackVector>
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000108void CreateTrackReports(const TrackVector& tracks, StatsSet* reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109 for (size_t j = 0; j < tracks.size(); ++j) {
110 webrtc::MediaStreamTrackInterface* track = tracks[j];
xians@webrtc.org01bda202014-07-09 07:38:38 +0000111 AddTrackReport(reports, track->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112 }
113}
114
115void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
116 report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
117 info.audio_level);
118 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
119 info.bytes_rcvd);
120 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
121 info.jitter_ms);
jiayl@webrtc.org11aab0e2014-03-07 18:56:26 +0000122 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
123 info.jitter_buffer_ms);
124 report->AddValue(StatsReport::kStatsValueNamePreferredJitterBufferMs,
125 info.jitter_buffer_preferred_ms);
126 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
127 info.delay_estimate_ms);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000128 report->AddValue(StatsReport::kStatsValueNameExpandRate,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000129 rtc::ToString<float>(info.expand_rate));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
131 info.packets_rcvd);
132 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
133 info.packets_lost);
buildbot@webrtc.org3e01e0b2014-05-13 17:54:10 +0000134 report->AddValue(StatsReport::kStatsValueNameDecodingCTSG,
135 info.decoding_calls_to_silence_generator);
136 report->AddValue(StatsReport::kStatsValueNameDecodingCTN,
137 info.decoding_calls_to_neteq);
138 report->AddValue(StatsReport::kStatsValueNameDecodingNormal,
139 info.decoding_normal);
140 report->AddValue(StatsReport::kStatsValueNameDecodingPLC,
141 info.decoding_plc);
142 report->AddValue(StatsReport::kStatsValueNameDecodingCNG,
143 info.decoding_cng);
144 report->AddValue(StatsReport::kStatsValueNameDecodingPLCCNG,
145 info.decoding_plc_cng);
buildbot@webrtc.orgb525a9d2014-06-03 09:42:15 +0000146 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
147 info.capture_start_ntp_time_ms);
buildbot@webrtc.org7e71b772014-06-13 01:14:01 +0000148 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000149}
150
151void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
152 report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
153 info.audio_level);
154 report->AddValue(StatsReport::kStatsValueNameBytesSent,
155 info.bytes_sent);
156 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
157 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000158 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
159 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
161 info.jitter_ms);
162 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
163 report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000164 rtc::ToString<float>(info.aec_quality_min));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165 report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
166 info.echo_delay_median_ms);
167 report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
168 info.echo_delay_std_ms);
169 report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
170 info.echo_return_loss);
171 report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
172 info.echo_return_loss_enhancement);
173 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000174 report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
175 info.typing_noise_detected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176}
177
178void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
179 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
180 info.bytes_rcvd);
181 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
182 info.packets_rcvd);
183 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
184 info.packets_lost);
185
186 report->AddValue(StatsReport::kStatsValueNameFirsSent,
187 info.firs_sent);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000188 report->AddValue(StatsReport::kStatsValueNamePlisSent,
189 info.plis_sent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190 report->AddValue(StatsReport::kStatsValueNameNacksSent,
191 info.nacks_sent);
192 report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
193 info.frame_width);
194 report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
195 info.frame_height);
196 report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
197 info.framerate_rcvd);
198 report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
199 info.framerate_decoded);
200 report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
201 info.framerate_output);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000202
203 report->AddValue(StatsReport::kStatsValueNameDecodeMs,
204 info.decode_ms);
205 report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
206 info.max_decode_ms);
207 report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
208 info.current_delay_ms);
209 report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
210 info.target_delay_ms);
211 report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
212 info.jitter_buffer_ms);
213 report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
214 info.min_playout_delay_ms);
215 report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
216 info.render_delay_ms);
buildbot@webrtc.org0581f0b2014-05-06 21:36:31 +0000217
218 report->AddValue(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
219 info.capture_start_ntp_time_ms);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220}
221
222void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
223 report->AddValue(StatsReport::kStatsValueNameBytesSent,
224 info.bytes_sent);
225 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
226 info.packets_sent);
henrike@webrtc.orgffe26202014-03-19 22:20:10 +0000227 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
228 info.packets_lost);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229
230 report->AddValue(StatsReport::kStatsValueNameFirsReceived,
231 info.firs_rcvd);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000232 report->AddValue(StatsReport::kStatsValueNamePlisReceived,
233 info.plis_rcvd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234 report->AddValue(StatsReport::kStatsValueNameNacksReceived,
235 info.nacks_rcvd);
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000236 report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
237 info.input_frame_width);
238 report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
239 info.input_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240 report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000241 info.send_frame_width);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000242 report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
wu@webrtc.org987f2c92014-03-28 16:22:19 +0000243 info.send_frame_height);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
245 info.framerate_input);
246 report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
247 info.framerate_sent);
248 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
249 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
mallinath@webrtc.org62451dc2013-12-13 12:29:34 +0000250 report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
251 (info.adapt_reason & 0x1) > 0);
252 report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
253 (info.adapt_reason & 0x2) > 0);
254 report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
255 (info.adapt_reason & 0x4) > 0);
buildbot@webrtc.org71dffb72014-06-24 07:24:49 +0000256 report->AddValue(StatsReport::kStatsValueNameAdaptationChanges,
257 info.adapt_changes);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000258 report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
259 report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
260 info.capture_jitter_ms);
wu@webrtc.org9caf2762013-12-11 18:25:07 +0000261 report->AddValue(StatsReport::kStatsValueNameCaptureQueueDelayMsPerS,
262 info.capture_queue_delay_ms_per_s);
263 report->AddValue(StatsReport::kStatsValueNameEncodeUsagePercent,
264 info.encode_usage_percent);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265}
266
267void ExtractStats(const cricket::BandwidthEstimationInfo& info,
268 double stats_gathering_started,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000269 PeerConnectionInterface::StatsOutputLevel level,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270 StatsReport* report) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000271 ASSERT(report->id == StatsReport::kStatsReportVideoBweId);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272 report->type = StatsReport::kStatsReportTypeBwe;
273
274 // Clear out stats from previous GatherStats calls if any.
275 if (report->timestamp != stats_gathering_started) {
276 report->values.clear();
277 report->timestamp = stats_gathering_started;
278 }
279
280 report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
281 info.available_send_bandwidth);
282 report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
283 info.available_recv_bandwidth);
284 report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
285 info.target_enc_bitrate);
286 report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
287 info.actual_enc_bitrate);
288 report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
289 info.retransmit_bitrate);
290 report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
291 info.transmit_bitrate);
292 report->AddValue(StatsReport::kStatsValueNameBucketDelay,
293 info.bucket_delay);
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000294 if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
295 report->AddValue(
296 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
297 info.total_received_propagation_delta_ms);
298 if (info.recent_received_propagation_delta_ms.size() > 0) {
299 report->AddValue(
300 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
301 info.recent_received_propagation_delta_ms);
302 report->AddValue(
303 StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
304 info.recent_received_packet_group_arrival_time_ms);
305 }
306 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307}
308
wu@webrtc.org97077a32013-10-25 21:18:33 +0000309void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
310 StatsReport* report) {
311 report->timestamp = info.remote_stats[0].timestamp;
312 // TODO(hta): Extract some stats here.
313}
314
315void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
316 StatsReport* report) {
317 report->timestamp = info.remote_stats[0].timestamp;
318 // TODO(hta): Extract some stats here.
319}
320
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321// Template to extract stats from a data vector.
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000322// In order to use the template, the functions that are called from it,
323// ExtractStats and ExtractRemoteStats, must be defined and overloaded
324// for each type.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000325template<typename T>
326void ExtractStatsFromList(const std::vector<T>& data,
327 const std::string& transport_id,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000328 StatsCollector* collector,
329 StatsCollector::TrackDirection direction) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000330 typename std::vector<T>::const_iterator it = data.begin();
331 for (; it != data.end(); ++it) {
332 std::string id;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000333 uint32 ssrc = it->ssrc();
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000334 // Each track can have stats for both local and remote objects.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000335 // TODO(hta): Handle the case of multiple SSRCs per object.
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000336 StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id,
337 direction);
338 if (report)
339 ExtractStats(*it, report);
340
wu@webrtc.org97077a32013-10-25 21:18:33 +0000341 if (it->remote_stats.size() > 0) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000342 report = collector->PrepareRemoteReport(ssrc, transport_id,
343 direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000344 if (!report) {
345 continue;
346 }
347 ExtractRemoteStats(*it, report);
348 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 }
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000350}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351
352} // namespace
353
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000354StatsCollector::StatsCollector(WebRtcSession* session)
355 : session_(session), stats_gathering_started_(0) {
356 ASSERT(session_);
357}
358
359StatsCollector::~StatsCollector() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000360 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361}
362
363// Adds a MediaStream with tracks that can be used as a |selector| in a call
364// to GetStats.
365void StatsCollector::AddStream(MediaStreamInterface* stream) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000366 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 ASSERT(stream != NULL);
368
369 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
370 &reports_);
371 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
372 &reports_);
373}
374
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000375void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
376 uint32 ssrc) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000377 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000378 ASSERT(audio_track != NULL);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000379 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
380 it != local_audio_tracks_.end(); ++it) {
381 ASSERT(it->first != audio_track || it->second != ssrc);
382 }
xians@webrtc.org01bda202014-07-09 07:38:38 +0000383
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000384 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
xians@webrtc.org01bda202014-07-09 07:38:38 +0000385
386 // Create the kStatsReportTypeTrack report for the new track if there is no
387 // report yet.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000388 StatsReport* found = reports_.Find(
xians@webrtc.org01bda202014-07-09 07:38:38 +0000389 StatsId(StatsReport::kStatsReportTypeTrack, audio_track->id()));
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000390 if (!found)
xians@webrtc.org01bda202014-07-09 07:38:38 +0000391 AddTrackReport(&reports_, audio_track->id());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000392}
393
394void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
395 uint32 ssrc) {
396 ASSERT(audio_track != NULL);
397 for (LocalAudioTrackVector::iterator it = local_audio_tracks_.begin();
398 it != local_audio_tracks_.end(); ++it) {
399 if (it->first == audio_track && it->second == ssrc) {
400 local_audio_tracks_.erase(it);
401 return;
402 }
403 }
404
405 ASSERT(false);
406}
407
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000408void StatsCollector::GetStats(MediaStreamTrackInterface* track,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000409 StatsReports* reports) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000410 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 ASSERT(reports != NULL);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000412 ASSERT(reports->empty());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000414 if (!track) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000415 StatsSet::const_iterator it;
416 for (it = reports_.begin(); it != reports_.end(); ++it)
417 reports->push_back(&(*it));
418 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 }
420
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000421 StatsReport* report =
422 reports_.Find(StatsId(StatsReport::kStatsReportTypeSession,
423 session_->id()));
424 if (report)
425 reports->push_back(report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000427 report = reports_.Find(
428 StatsId(StatsReport::kStatsReportTypeTrack, track->id()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000430 if (!report)
431 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000433 reports->push_back(report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434
435 std::string track_id;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000436 for (StatsSet::const_iterator it = reports_.begin(); it != reports_.end();
437 ++it) {
438 if (it->type != StatsReport::kStatsReportTypeSsrc)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439 continue;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000440
441 if (ExtractValueFromReport(*it,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000442 StatsReport::kStatsValueNameTrackId,
443 &track_id)) {
444 if (track_id == track->id()) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000445 reports->push_back(&(*it));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 }
447 }
448 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449}
450
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000451void
452StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000453 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454 double time_now = GetTimeNow();
455 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
456 // ms apart will be ignored.
457 const double kMinGatherStatsPeriod = 50;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000458 if (stats_gathering_started_ != 0 &&
459 stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460 return;
461 }
462 stats_gathering_started_ = time_now;
463
464 if (session_) {
465 ExtractSessionInfo();
466 ExtractVoiceInfo();
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000467 ExtractVideoInfo(level);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000468 }
469}
470
wu@webrtc.org97077a32013-10-25 21:18:33 +0000471StatsReport* StatsCollector::PrepareLocalReport(
472 uint32 ssrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000473 const std::string& transport_id,
474 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000475 ASSERT(session_->signaling_thread()->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000476 const std::string ssrc_id = rtc::ToString<uint32>(ssrc);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000477 StatsReport* report = reports_.Find(
478 StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id, direction));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479
xians@webrtc.org01bda202014-07-09 07:38:38 +0000480 // Use the ID of the track that is currently mapped to the SSRC, if any.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 std::string track_id;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000482 if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000483 if (!report) {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000484 // The ssrc is not used by any track or existing report, return NULL
485 // in such case to indicate no report is prepared for the ssrc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000486 return NULL;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000487 }
488
489 // The ssrc is not used by any existing track. Keeps the old track id
490 // since we want to report the stats for inactive ssrc.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000491 ExtractValueFromReport(*report,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 StatsReport::kStatsValueNameTrackId,
493 &track_id);
494 }
495
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000496 report = GetOrCreateReport(
497 StatsReport::kStatsReportTypeSsrc, ssrc_id, direction);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498
499 // Clear out stats from previous GatherStats calls if any.
xians@webrtc.org01bda202014-07-09 07:38:38 +0000500 // This is required since the report will be returned for the new values.
501 // Having the old values in the report will lead to multiple values with
502 // the same name.
503 // TODO(xians): Consider changing StatsReport to use map instead of vector.
504 report->values.clear();
505 report->timestamp = stats_gathering_started_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506
507 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
508 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
509 // Add the mapping of SSRC to transport.
510 report->AddValue(StatsReport::kStatsValueNameTransportId,
511 transport_id);
512 return report;
513}
514
wu@webrtc.org97077a32013-10-25 21:18:33 +0000515StatsReport* StatsCollector::PrepareRemoteReport(
516 uint32 ssrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000517 const std::string& transport_id,
518 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000519 ASSERT(session_->signaling_thread()->IsCurrent());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000520 const std::string ssrc_id = rtc::ToString<uint32>(ssrc);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000521 StatsReport* report = reports_.Find(
522 StatsId(StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction));
wu@webrtc.org97077a32013-10-25 21:18:33 +0000523
xians@webrtc.org01bda202014-07-09 07:38:38 +0000524 // Use the ID of the track that is currently mapped to the SSRC, if any.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000525 std::string track_id;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000526 if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000527 if (!report) {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000528 // The ssrc is not used by any track or existing report, return NULL
529 // in such case to indicate no report is prepared for the ssrc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000530 return NULL;
xians@webrtc.org01bda202014-07-09 07:38:38 +0000531 }
532
533 // The ssrc is not used by any existing track. Keeps the old track id
534 // since we want to report the stats for inactive ssrc.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000535 ExtractValueFromReport(*report,
wu@webrtc.org97077a32013-10-25 21:18:33 +0000536 StatsReport::kStatsValueNameTrackId,
537 &track_id);
538 }
539
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000540 report = GetOrCreateReport(
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000541 StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id, direction);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000542
543 // Clear out stats from previous GatherStats calls if any.
544 // The timestamp will be added later. Zero it for debugging.
545 report->values.clear();
546 report->timestamp = 0;
547
548 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
549 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
550 // Add the mapping of SSRC to transport.
551 report->AddValue(StatsReport::kStatsValueNameTransportId,
552 transport_id);
553 return report;
554}
555
wu@webrtc.org4551b792013-10-09 15:37:36 +0000556std::string StatsCollector::AddOneCertificateReport(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000557 const rtc::SSLCertificate* cert, const std::string& issuer_id) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000558 // TODO(bemasc): Move this computation to a helper class that caches these
559 // values to reduce CPU use in GetStats. This will require adding a fast
560 // SSLCertificate::Equals() method to detect certificate changes.
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000561
562 std::string digest_algorithm;
563 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
564 return std::string();
565
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000566 rtc::scoped_ptr<rtc::SSLFingerprint> ssl_fingerprint(
567 rtc::SSLFingerprint::Create(digest_algorithm, cert));
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000568
569 // SSLFingerprint::Create can fail if the algorithm returned by
570 // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
571 // implementation of SSLCertificate::ComputeDigest. This currently happens
572 // with MD5- and SHA-224-signed certificates when linked to libNSS.
573 if (!ssl_fingerprint)
574 return std::string();
575
wu@webrtc.org4551b792013-10-09 15:37:36 +0000576 std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
577
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000578 rtc::Buffer der_buffer;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000579 cert->ToDER(&der_buffer);
580 std::string der_base64;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000581 rtc::Base64::EncodeFromArray(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000582 der_buffer.data(), der_buffer.length(), &der_base64);
583
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000584 StatsReport* report = reports_.ReplaceOrAddNew(
585 StatsId(StatsReport::kStatsReportTypeCertificate, fingerprint));
586 report->type = StatsReport::kStatsReportTypeCertificate;
587 report->timestamp = stats_gathering_started_;
588 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);
594 return report->id;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000595}
596
597std::string StatsCollector::AddCertificateReports(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000598 const rtc::SSLCertificate* cert) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000599 // Produces a chain of StatsReports representing this certificate and the rest
600 // of its chain, and adds those reports to |reports_|. The return value is
601 // the id of the leaf report. The provided cert must be non-null, so at least
602 // one report will always be provided and the returned string will never be
603 // empty.
604 ASSERT(cert != NULL);
605
606 std::string issuer_id;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000607 rtc::scoped_ptr<rtc::SSLCertChain> chain;
wu@webrtc.org4551b792013-10-09 15:37:36 +0000608 if (cert->GetChain(chain.accept())) {
609 // This loop runs in reverse, i.e. from root to leaf, so that each
610 // certificate's issuer's report ID is known before the child certificate's
611 // report is generated. The root certificate does not have an issuer ID
612 // value.
613 for (ptrdiff_t i = chain->GetSize() - 1; i >= 0; --i) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000614 const rtc::SSLCertificate& cert_i = chain->Get(i);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000615 issuer_id = AddOneCertificateReport(&cert_i, issuer_id);
616 }
617 }
618 // Add the leaf certificate.
619 return AddOneCertificateReport(cert, issuer_id);
620}
621
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622void StatsCollector::ExtractSessionInfo() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000623 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 // Extract information from the base session.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000625 StatsReport* report = reports_.ReplaceOrAddNew(
626 StatsId(StatsReport::kStatsReportTypeSession, session_->id()));
627 report->type = StatsReport::kStatsReportTypeSession;
628 report->timestamp = stats_gathering_started_;
629 report->values.clear();
630 report->AddBoolean(StatsReport::kStatsValueNameInitiator,
631 session_->initiator());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632
633 cricket::SessionStats stats;
634 if (session_->GetStats(&stats)) {
635 // Store the proxy map away for use in SSRC reporting.
636 proxy_to_transport_ = stats.proxy_to_transport;
637
638 for (cricket::TransportStatsMap::iterator transport_iter
639 = stats.transport_stats.begin();
640 transport_iter != stats.transport_stats.end(); ++transport_iter) {
wu@webrtc.org4551b792013-10-09 15:37:36 +0000641 // Attempt to get a copy of the certificates from the transport and
642 // expose them in stats reports. All channels in a transport share the
643 // same local and remote certificates.
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000644 //
645 // Note that Transport::GetIdentity and Transport::GetRemoteCertificate
646 // invoke method calls on the worker thread and block this thread, but
647 // messages are still processed on this thread, which may blow way the
648 // existing transports. So we cannot reuse |transport| after these calls.
wu@webrtc.org4551b792013-10-09 15:37:36 +0000649 std::string local_cert_report_id, remote_cert_report_id;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000650
wu@webrtc.org4551b792013-10-09 15:37:36 +0000651 cricket::Transport* transport =
652 session_->GetTransport(transport_iter->second.content_name);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000653 rtc::scoped_ptr<rtc::SSLIdentity> identity;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000654 if (transport && transport->GetIdentity(identity.accept())) {
655 local_cert_report_id =
656 AddCertificateReports(&(identity->certificate()));
wu@webrtc.org4551b792013-10-09 15:37:36 +0000657 }
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000658
659 transport = session_->GetTransport(transport_iter->second.content_name);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000660 rtc::scoped_ptr<rtc::SSLCertificate> cert;
jiayl@webrtc.org06b04ec2014-07-24 20:41:20 +0000661 if (transport && transport->GetRemoteCertificate(cert.accept())) {
662 remote_cert_report_id = AddCertificateReports(cert.get());
663 }
664
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 for (cricket::TransportChannelStatsList::iterator channel_iter
666 = transport_iter->second.channel_stats.begin();
667 channel_iter != transport_iter->second.channel_stats.end();
668 ++channel_iter) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 std::ostringstream ostc;
670 ostc << "Channel-" << transport_iter->second.content_name
671 << "-" << channel_iter->component;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000672 StatsReport* channel_report = reports_.ReplaceOrAddNew(ostc.str());
673 channel_report->type = StatsReport::kStatsReportTypeComponent;
674 channel_report->timestamp = stats_gathering_started_;
675 channel_report->AddValue(StatsReport::kStatsValueNameComponent,
676 channel_iter->component);
wu@webrtc.org4551b792013-10-09 15:37:36 +0000677 if (!local_cert_report_id.empty())
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000678 channel_report->AddValue(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000679 StatsReport::kStatsValueNameLocalCertificateId,
680 local_cert_report_id);
681 if (!remote_cert_report_id.empty())
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000682 channel_report->AddValue(
wu@webrtc.org4551b792013-10-09 15:37:36 +0000683 StatsReport::kStatsValueNameRemoteCertificateId,
684 remote_cert_report_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 for (size_t i = 0;
686 i < channel_iter->connection_infos.size();
687 ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 std::ostringstream ost;
689 ost << "Conn-" << transport_iter->first << "-"
690 << channel_iter->component << "-" << i;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000691 StatsReport* report = reports_.ReplaceOrAddNew(ost.str());
692 report->type = StatsReport::kStatsReportTypeCandidatePair;
693 report->timestamp = stats_gathering_started_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 // Link from connection to its containing channel.
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000695 report->AddValue(StatsReport::kStatsValueNameChannelId,
696 channel_report->id);
697
698 const cricket::ConnectionInfo& info =
699 channel_iter->connection_infos[i];
700 report->AddValue(StatsReport::kStatsValueNameBytesSent,
701 info.sent_total_bytes);
guoweis@webrtc.org930e0042014-11-17 19:42:14 +0000702 report->AddValue(StatsReport::kStatsValueNameSendPacketsDiscarded,
703 info.sent_discarded_packets);
704 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
705 info.sent_total_packets);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000706 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
707 info.recv_total_bytes);
708 report->AddBoolean(StatsReport::kStatsValueNameWritable,
709 info.writable);
710 report->AddBoolean(StatsReport::kStatsValueNameReadable,
711 info.readable);
712 report->AddBoolean(StatsReport::kStatsValueNameActiveConnection,
713 info.best_connection);
714 report->AddValue(StatsReport::kStatsValueNameLocalAddress,
715 info.local_candidate.address().ToString());
716 report->AddValue(StatsReport::kStatsValueNameRemoteAddress,
717 info.remote_candidate.address().ToString());
718 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
719 report->AddValue(StatsReport::kStatsValueNameTransportType,
720 info.local_candidate.protocol());
721 report->AddValue(StatsReport::kStatsValueNameLocalCandidateType,
722 info.local_candidate.type());
723 report->AddValue(StatsReport::kStatsValueNameRemoteCandidateType,
724 info.remote_candidate.type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000725 }
726 }
727 }
728 }
729}
730
731void StatsCollector::ExtractVoiceInfo() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000732 ASSERT(session_->signaling_thread()->IsCurrent());
733
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734 if (!session_->voice_channel()) {
735 return;
736 }
737 cricket::VoiceMediaInfo voice_info;
738 if (!session_->voice_channel()->GetStats(&voice_info)) {
739 LOG(LS_ERROR) << "Failed to get voice channel stats.";
740 return;
741 }
742 std::string transport_id;
tommi@webrtc.org47218952014-07-15 19:22:37 +0000743 if (!GetTransportIdFromProxy(proxy_to_transport_,
744 session_->voice_channel()->content_name(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 &transport_id)) {
746 LOG(LS_ERROR) << "Failed to get transport name for proxy "
747 << session_->voice_channel()->content_name();
748 return;
749 }
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000750 ExtractStatsFromList(voice_info.receivers, transport_id, this, kReceiving);
751 ExtractStatsFromList(voice_info.senders, transport_id, this, kSending);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000752
753 UpdateStatsFromExistingLocalAudioTracks();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754}
755
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000756void StatsCollector::ExtractVideoInfo(
757 PeerConnectionInterface::StatsOutputLevel level) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000758 ASSERT(session_->signaling_thread()->IsCurrent());
759
760 if (!session_->video_channel())
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 return;
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000762
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000763 cricket::StatsOptions options;
764 options.include_received_propagation_stats =
765 (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
766 true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 cricket::VideoMediaInfo video_info;
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000768 if (!session_->video_channel()->GetStats(options, &video_info)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 LOG(LS_ERROR) << "Failed to get video channel stats.";
770 return;
771 }
772 std::string transport_id;
tommi@webrtc.org47218952014-07-15 19:22:37 +0000773 if (!GetTransportIdFromProxy(proxy_to_transport_,
774 session_->video_channel()->content_name(),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 &transport_id)) {
776 LOG(LS_ERROR) << "Failed to get transport name for proxy "
777 << session_->video_channel()->content_name();
778 return;
779 }
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000780 ExtractStatsFromList(video_info.receivers, transport_id, this, kReceiving);
781 ExtractStatsFromList(video_info.senders, transport_id, this, kSending);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 if (video_info.bw_estimations.size() != 1) {
783 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
784 } else {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000785 StatsReport* report =
786 reports_.FindOrAddNew(StatsReport::kStatsReportVideoBweId);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 ExtractStats(
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000788 video_info.bw_estimations[0], stats_gathering_started_, level, report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 }
790}
791
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000792StatsReport* StatsCollector::GetReport(const std::string& type,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000793 const std::string& id,
794 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000795 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000796 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
797 type == StatsReport::kStatsReportTypeRemoteSsrc);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000798 return reports_.Find(StatsId(type, id, direction));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000799}
800
801StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000802 const std::string& id,
803 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000804 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000805 ASSERT(type == StatsReport::kStatsReportTypeSsrc ||
806 type == StatsReport::kStatsReportTypeRemoteSsrc);
807 StatsReport* report = GetReport(type, id, direction);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000808 if (report == NULL) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000809 std::string statsid = StatsId(type, id, direction);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000810 report = reports_.FindOrAddNew(statsid);
811 ASSERT(report->id == statsid);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000812 report->type = type;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000813 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000814
wu@webrtc.org97077a32013-10-25 21:18:33 +0000815 return report;
816}
817
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000818void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000819 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000820 // Loop through the existing local audio tracks.
821 for (LocalAudioTrackVector::const_iterator it = local_audio_tracks_.begin();
822 it != local_audio_tracks_.end(); ++it) {
823 AudioTrackInterface* track = it->first;
824 uint32 ssrc = it->second;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000825 std::string ssrc_id = rtc::ToString<uint32>(ssrc);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000826 StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000827 ssrc_id,
828 kSending);
henrike@webrtc.orgd3d6bce2014-03-10 20:41:22 +0000829 if (report == NULL) {
830 // This can happen if a local audio track is added to a stream on the
831 // fly and the report has not been set up yet. Do nothing in this case.
832 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
833 continue;
834 }
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000835
836 // The same ssrc can be used by both local and remote audio tracks.
837 std::string track_id;
838 if (!ExtractValueFromReport(*report,
839 StatsReport::kStatsValueNameTrackId,
840 &track_id) ||
841 track_id != track->id()) {
842 continue;
843 }
844
845 UpdateReportFromAudioTrack(track, report);
846 }
847}
848
849void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
850 StatsReport* report) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000851 ASSERT(session_->signaling_thread()->IsCurrent());
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000852 ASSERT(track != NULL);
853 if (report == NULL)
854 return;
855
856 int signal_level = 0;
857 if (track->GetSignalLevel(&signal_level)) {
858 report->ReplaceValue(StatsReport::kStatsValueNameAudioInputLevel,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000859 rtc::ToString<int>(signal_level));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000860 }
861
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000862 rtc::scoped_refptr<AudioProcessorInterface> audio_processor(
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000863 track->GetAudioProcessor());
864 if (audio_processor.get() == NULL)
865 return;
866
867 AudioProcessorInterface::AudioProcessorStats stats;
868 audio_processor->GetStats(&stats);
869 report->ReplaceValue(StatsReport::kStatsValueNameTypingNoiseState,
870 stats.typing_noise_detected ? "true" : "false");
871 report->ReplaceValue(StatsReport::kStatsValueNameEchoReturnLoss,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000872 rtc::ToString<int>(stats.echo_return_loss));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000873 report->ReplaceValue(
874 StatsReport::kStatsValueNameEchoReturnLossEnhancement,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000875 rtc::ToString<int>(stats.echo_return_loss_enhancement));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000876 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayMedian,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000877 rtc::ToString<int>(stats.echo_delay_median_ms));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000878 report->ReplaceValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000879 rtc::ToString<float>(stats.aec_quality_min));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000880 report->ReplaceValue(StatsReport::kStatsValueNameEchoDelayStdDev,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000881 rtc::ToString<int>(stats.echo_delay_std_ms));
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000882}
883
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000884bool StatsCollector::GetTrackIdBySsrc(uint32 ssrc, std::string* track_id,
885 TrackDirection direction) {
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000886 ASSERT(session_->signaling_thread()->IsCurrent());
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000887 if (direction == kSending) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000888 if (!session_->GetLocalTrackIdBySsrc(ssrc, track_id)) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000889 LOG(LS_WARNING) << "The SSRC " << ssrc
890 << " is not associated with a sending track";
891 return false;
892 }
893 } else {
894 ASSERT(direction == kReceiving);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000895 if (!session_->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
xians@webrtc.org4cb01282014-06-12 14:57:05 +0000896 LOG(LS_WARNING) << "The SSRC " << ssrc
897 << " is not associated with a receiving track";
898 return false;
899 }
900 }
901
902 return true;
903}
904
tommi@webrtc.org69bc5a32014-12-15 09:44:48 +0000905void StatsCollector::ClearUpdateStatsCacheForTest() {
xians@webrtc.org01bda202014-07-09 07:38:38 +0000906 stats_gathering_started_ = 0;
907}
908
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909} // namespace webrtc