blob: 4952012648c5f22a1dc37d50c3adf129756efa6b [file] [log] [blame]
hbosd565b732016-08-30 14:04:35 -07001/*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
ossu7bb87ee2017-01-23 04:56:25 -080011#include "webrtc/pc/rtcstatscollector.h"
hbosd565b732016-08-30 14:04:35 -070012
13#include <memory>
hbos9e302742017-01-20 02:47:10 -080014#include <sstream>
hbosd565b732016-08-30 14:04:35 -070015#include <utility>
16#include <vector>
17
hbos09bc1282016-11-08 06:29:22 -080018#include "webrtc/api/mediastreaminterface.h"
ossu7bb87ee2017-01-23 04:56:25 -080019#include "webrtc/api/peerconnectioninterface.h"
hbos6ded1902016-11-01 01:50:46 -070020#include "webrtc/media/base/mediachannel.h"
hbosab9f6e42016-10-07 02:18:47 -070021#include "webrtc/p2p/base/candidate.h"
hbos2fa7c672016-10-24 04:00:05 -070022#include "webrtc/p2p/base/p2pconstants.h"
hbosab9f6e42016-10-07 02:18:47 -070023#include "webrtc/p2p/base/port.h"
ossu7bb87ee2017-01-23 04:56:25 -080024#include "webrtc/pc/peerconnection.h"
25#include "webrtc/pc/webrtcsession.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020026#include "webrtc/rtc_base/checks.h"
ehmaldonadoa26196b2017-07-18 03:30:29 -070027#include "webrtc/rtc_base/stringutils.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020028#include "webrtc/rtc_base/timeutils.h"
ehmaldonadoa26196b2017-07-18 03:30:29 -070029#include "webrtc/rtc_base/trace_event.h"
hbosd565b732016-08-30 14:04:35 -070030
31namespace webrtc {
32
hboscc555c52016-10-18 12:48:31 -070033namespace {
34
mbonadei3439c892017-08-14 23:48:03 -070035const int kStatTypeMemberNameAndIdMaxLen = 1024;
36
37std::string GetStatTypeMemberNameAndId(const RTCStats& stats,
38 const RTCStatsMemberInterface* member) {
39 RTC_DCHECK(strlen(stats.type()) + strlen(member->name())
40 + stats.id().size() + 3 < kStatTypeMemberNameAndIdMaxLen);
41 char buffer[kStatTypeMemberNameAndIdMaxLen];
42 rtc::sprintfn(&buffer[0], sizeof(buffer), "%s.%s.%s", stats.type(),
43 member->name(), stats.id().c_str());
44 return buffer;
45}
46
hbos2fa7c672016-10-24 04:00:05 -070047std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) {
48 return "RTCCertificate_" + fingerprint;
49}
50
hbos0adb8282016-11-23 02:32:06 -080051std::string RTCCodecStatsIDFromDirectionMediaAndPayload(
52 bool inbound, bool audio, uint32_t payload_type) {
hbos585a9b12017-02-07 04:59:16 -080053 // TODO(hbos): The present codec ID assignment is not sufficient to support
54 // Unified Plan or unbundled connections in all cases. When we are able to
55 // handle multiple m= lines of the same media type (and multiple BaseChannels
56 // for the same type is possible?) this needs to be updated to differentiate
57 // the transport being used, and stats need to be collected for all of them.
hbos0adb8282016-11-23 02:32:06 -080058 if (inbound) {
59 return audio ? "RTCCodec_InboundAudio_" + rtc::ToString<>(payload_type)
60 : "RTCCodec_InboundVideo_" + rtc::ToString<>(payload_type);
61 }
62 return audio ? "RTCCodec_OutboundAudio_" + rtc::ToString<>(payload_type)
63 : "RTCCodec_OutboundVideo_" + rtc::ToString<>(payload_type);
64}
65
hbos2fa7c672016-10-24 04:00:05 -070066std::string RTCIceCandidatePairStatsIDFromConnectionInfo(
67 const cricket::ConnectionInfo& info) {
68 return "RTCIceCandidatePair_" + info.local_candidate.id() + "_" +
69 info.remote_candidate.id();
70}
71
hbos9e302742017-01-20 02:47:10 -080072std::string RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
73 bool is_local, const char* kind, const std::string& id, uint32_t ssrc) {
74 RTC_DCHECK(kind == MediaStreamTrackInterface::kAudioKind ||
75 kind == MediaStreamTrackInterface::kVideoKind);
76 std::ostringstream oss;
77 oss << (is_local ? "RTCMediaStreamTrack_local_"
78 : "RTCMediaStreamTrack_remote_");
79 oss << kind << "_";
80 oss << id << "_";
81 oss << ssrc;
82 return oss.str();
hbos09bc1282016-11-08 06:29:22 -080083}
84
hbos2fa7c672016-10-24 04:00:05 -070085std::string RTCTransportStatsIDFromTransportChannel(
86 const std::string& transport_name, int channel_component) {
87 return "RTCTransport_" + transport_name + "_" +
88 rtc::ToString<>(channel_component);
89}
90
hbos6ded1902016-11-01 01:50:46 -070091std::string RTCTransportStatsIDFromBaseChannel(
92 const ProxyTransportMap& proxy_to_transport,
93 const cricket::BaseChannel& base_channel) {
94 auto proxy_it = proxy_to_transport.find(base_channel.content_name());
95 if (proxy_it == proxy_to_transport.cend())
96 return "";
97 return RTCTransportStatsIDFromTransportChannel(
98 proxy_it->second, cricket::ICE_CANDIDATE_COMPONENT_RTP);
99}
100
hboseeafe942016-11-01 03:00:17 -0700101std::string RTCInboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
102 return audio ? "RTCInboundRTPAudioStream_" + rtc::ToString<>(ssrc)
103 : "RTCInboundRTPVideoStream_" + rtc::ToString<>(ssrc);
104}
105
hbos6ded1902016-11-01 01:50:46 -0700106std::string RTCOutboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
107 return audio ? "RTCOutboundRTPAudioStream_" + rtc::ToString<>(ssrc)
108 : "RTCOutboundRTPVideoStream_" + rtc::ToString<>(ssrc);
109}
110
hbosab9f6e42016-10-07 02:18:47 -0700111const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
112 if (type == cricket::LOCAL_PORT_TYPE)
113 return RTCIceCandidateType::kHost;
114 if (type == cricket::STUN_PORT_TYPE)
115 return RTCIceCandidateType::kSrflx;
116 if (type == cricket::PRFLX_PORT_TYPE)
117 return RTCIceCandidateType::kPrflx;
118 if (type == cricket::RELAY_PORT_TYPE)
119 return RTCIceCandidateType::kRelay;
120 RTC_NOTREACHED();
121 return nullptr;
122}
123
hboscc555c52016-10-18 12:48:31 -0700124const char* DataStateToRTCDataChannelState(
125 DataChannelInterface::DataState state) {
126 switch (state) {
127 case DataChannelInterface::kConnecting:
128 return RTCDataChannelState::kConnecting;
129 case DataChannelInterface::kOpen:
130 return RTCDataChannelState::kOpen;
131 case DataChannelInterface::kClosing:
132 return RTCDataChannelState::kClosing;
133 case DataChannelInterface::kClosed:
134 return RTCDataChannelState::kClosed;
135 default:
136 RTC_NOTREACHED();
137 return nullptr;
138 }
139}
140
hbos06495bc2017-01-02 08:08:18 -0800141const char* IceCandidatePairStateToRTCStatsIceCandidatePairState(
142 cricket::IceCandidatePairState state) {
143 switch (state) {
144 case cricket::IceCandidatePairState::WAITING:
145 return RTCStatsIceCandidatePairState::kWaiting;
146 case cricket::IceCandidatePairState::IN_PROGRESS:
147 return RTCStatsIceCandidatePairState::kInProgress;
148 case cricket::IceCandidatePairState::SUCCEEDED:
149 return RTCStatsIceCandidatePairState::kSucceeded;
150 case cricket::IceCandidatePairState::FAILED:
151 return RTCStatsIceCandidatePairState::kFailed;
152 default:
153 RTC_NOTREACHED();
154 return nullptr;
155 }
156}
157
hbos7064d592017-01-16 07:38:02 -0800158const char* DtlsTransportStateToRTCDtlsTransportState(
159 cricket::DtlsTransportState state) {
160 switch (state) {
161 case cricket::DTLS_TRANSPORT_NEW:
162 return RTCDtlsTransportState::kNew;
163 case cricket::DTLS_TRANSPORT_CONNECTING:
164 return RTCDtlsTransportState::kConnecting;
165 case cricket::DTLS_TRANSPORT_CONNECTED:
166 return RTCDtlsTransportState::kConnected;
167 case cricket::DTLS_TRANSPORT_CLOSED:
168 return RTCDtlsTransportState::kClosed;
169 case cricket::DTLS_TRANSPORT_FAILED:
170 return RTCDtlsTransportState::kFailed;
171 default:
172 RTC_NOTREACHED();
173 return nullptr;
174 }
175}
176
hbos9e302742017-01-20 02:47:10 -0800177double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
178 RTC_DCHECK_GE(audio_level, 0);
179 RTC_DCHECK_LE(audio_level, 32767);
180 return audio_level / 32767.0;
181}
182
hbos0adb8282016-11-23 02:32:06 -0800183std::unique_ptr<RTCCodecStats> CodecStatsFromRtpCodecParameters(
184 uint64_t timestamp_us, bool inbound, bool audio,
185 const RtpCodecParameters& codec_params) {
186 RTC_DCHECK_GE(codec_params.payload_type, 0);
187 RTC_DCHECK_LE(codec_params.payload_type, 127);
deadbeefe702b302017-02-04 12:09:01 -0800188 RTC_DCHECK(codec_params.clock_rate);
hbos0adb8282016-11-23 02:32:06 -0800189 uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type);
190 std::unique_ptr<RTCCodecStats> codec_stats(new RTCCodecStats(
191 RTCCodecStatsIDFromDirectionMediaAndPayload(inbound, audio, payload_type),
192 timestamp_us));
193 codec_stats->payload_type = payload_type;
hbos13f54b22017-02-28 06:56:04 -0800194 codec_stats->mime_type = codec_params.mime_type();
deadbeefe702b302017-02-04 12:09:01 -0800195 if (codec_params.clock_rate) {
196 codec_stats->clock_rate = static_cast<uint32_t>(*codec_params.clock_rate);
197 }
hbos0adb8282016-11-23 02:32:06 -0800198 return codec_stats;
199}
200
hbos09bc1282016-11-08 06:29:22 -0800201void SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
202 const MediaStreamTrackInterface& track,
203 RTCMediaStreamTrackStats* track_stats) {
204 track_stats->track_identifier = track.id();
205 track_stats->ended = (track.state() == MediaStreamTrackInterface::kEnded);
206}
207
hbos820f5782016-11-22 03:16:50 -0800208// Provides the media independent counters (both audio and video).
hboseeafe942016-11-01 03:00:17 -0700209void SetInboundRTPStreamStatsFromMediaReceiverInfo(
210 const cricket::MediaReceiverInfo& media_receiver_info,
211 RTCInboundRTPStreamStats* inbound_stats) {
212 RTC_DCHECK(inbound_stats);
hbos3443bb72017-02-07 06:28:11 -0800213 inbound_stats->ssrc = media_receiver_info.ssrc();
hboseeafe942016-11-01 03:00:17 -0700214 // TODO(hbos): Support the remote case. crbug.com/657855
215 inbound_stats->is_remote = false;
hboseeafe942016-11-01 03:00:17 -0700216 inbound_stats->packets_received =
217 static_cast<uint32_t>(media_receiver_info.packets_rcvd);
218 inbound_stats->bytes_received =
219 static_cast<uint64_t>(media_receiver_info.bytes_rcvd);
hbos02cd4d62016-12-09 04:19:44 -0800220 inbound_stats->packets_lost =
221 static_cast<uint32_t>(media_receiver_info.packets_lost);
hboseeafe942016-11-01 03:00:17 -0700222 inbound_stats->fraction_lost =
223 static_cast<double>(media_receiver_info.fraction_lost);
224}
225
226void SetInboundRTPStreamStatsFromVoiceReceiverInfo(
227 const cricket::VoiceReceiverInfo& voice_receiver_info,
hbos820f5782016-11-22 03:16:50 -0800228 RTCInboundRTPStreamStats* inbound_audio) {
hboseeafe942016-11-01 03:00:17 -0700229 SetInboundRTPStreamStatsFromMediaReceiverInfo(
hbos820f5782016-11-22 03:16:50 -0800230 voice_receiver_info, inbound_audio);
231 inbound_audio->media_type = "audio";
hbos585a9b12017-02-07 04:59:16 -0800232 if (voice_receiver_info.codec_payload_type) {
233 inbound_audio->codec_id =
234 RTCCodecStatsIDFromDirectionMediaAndPayload(
235 true, true, *voice_receiver_info.codec_payload_type);
236 }
hbos820f5782016-11-22 03:16:50 -0800237 inbound_audio->jitter =
hboseeafe942016-11-01 03:00:17 -0700238 static_cast<double>(voice_receiver_info.jitter_ms) /
239 rtc::kNumMillisecsPerSec;
hbos820f5782016-11-22 03:16:50 -0800240 // |fir_count|, |pli_count| and |sli_count| are only valid for video and are
241 // purposefully left undefined for audio.
hboseeafe942016-11-01 03:00:17 -0700242}
243
244void SetInboundRTPStreamStatsFromVideoReceiverInfo(
245 const cricket::VideoReceiverInfo& video_receiver_info,
hbos820f5782016-11-22 03:16:50 -0800246 RTCInboundRTPStreamStats* inbound_video) {
hboseeafe942016-11-01 03:00:17 -0700247 SetInboundRTPStreamStatsFromMediaReceiverInfo(
hbos820f5782016-11-22 03:16:50 -0800248 video_receiver_info, inbound_video);
249 inbound_video->media_type = "video";
hbos585a9b12017-02-07 04:59:16 -0800250 if (video_receiver_info.codec_payload_type) {
251 inbound_video->codec_id =
252 RTCCodecStatsIDFromDirectionMediaAndPayload(
253 true, false, *video_receiver_info.codec_payload_type);
254 }
hbos820f5782016-11-22 03:16:50 -0800255 inbound_video->fir_count =
256 static_cast<uint32_t>(video_receiver_info.firs_sent);
257 inbound_video->pli_count =
258 static_cast<uint32_t>(video_receiver_info.plis_sent);
259 inbound_video->nack_count =
260 static_cast<uint32_t>(video_receiver_info.nacks_sent);
hbos6769c492017-01-02 08:35:13 -0800261 inbound_video->frames_decoded = video_receiver_info.frames_decoded;
hbosa51d4f32017-02-16 05:34:48 -0800262 if (video_receiver_info.qp_sum)
263 inbound_video->qp_sum = *video_receiver_info.qp_sum;
hboseeafe942016-11-01 03:00:17 -0700264}
265
hbos820f5782016-11-22 03:16:50 -0800266// Provides the media independent counters (both audio and video).
hbos6ded1902016-11-01 01:50:46 -0700267void SetOutboundRTPStreamStatsFromMediaSenderInfo(
268 const cricket::MediaSenderInfo& media_sender_info,
269 RTCOutboundRTPStreamStats* outbound_stats) {
270 RTC_DCHECK(outbound_stats);
hbos3443bb72017-02-07 06:28:11 -0800271 outbound_stats->ssrc = media_sender_info.ssrc();
hbos6ded1902016-11-01 01:50:46 -0700272 // TODO(hbos): Support the remote case. crbug.com/657856
273 outbound_stats->is_remote = false;
hbos6ded1902016-11-01 01:50:46 -0700274 outbound_stats->packets_sent =
275 static_cast<uint32_t>(media_sender_info.packets_sent);
276 outbound_stats->bytes_sent =
277 static_cast<uint64_t>(media_sender_info.bytes_sent);
hbos6ded1902016-11-01 01:50:46 -0700278}
279
280void SetOutboundRTPStreamStatsFromVoiceSenderInfo(
281 const cricket::VoiceSenderInfo& voice_sender_info,
282 RTCOutboundRTPStreamStats* outbound_audio) {
283 SetOutboundRTPStreamStatsFromMediaSenderInfo(
284 voice_sender_info, outbound_audio);
285 outbound_audio->media_type = "audio";
hbos585a9b12017-02-07 04:59:16 -0800286 if (voice_sender_info.codec_payload_type) {
287 outbound_audio->codec_id =
288 RTCCodecStatsIDFromDirectionMediaAndPayload(
289 false, true, *voice_sender_info.codec_payload_type);
290 }
hbos6ded1902016-11-01 01:50:46 -0700291 // |fir_count|, |pli_count| and |sli_count| are only valid for video and are
292 // purposefully left undefined for audio.
293}
294
295void SetOutboundRTPStreamStatsFromVideoSenderInfo(
296 const cricket::VideoSenderInfo& video_sender_info,
297 RTCOutboundRTPStreamStats* outbound_video) {
298 SetOutboundRTPStreamStatsFromMediaSenderInfo(
299 video_sender_info, outbound_video);
300 outbound_video->media_type = "video";
hbos585a9b12017-02-07 04:59:16 -0800301 if (video_sender_info.codec_payload_type) {
302 outbound_video->codec_id =
303 RTCCodecStatsIDFromDirectionMediaAndPayload(
304 false, false, *video_sender_info.codec_payload_type);
305 }
hbos6ded1902016-11-01 01:50:46 -0700306 outbound_video->fir_count =
307 static_cast<uint32_t>(video_sender_info.firs_rcvd);
308 outbound_video->pli_count =
309 static_cast<uint32_t>(video_sender_info.plis_rcvd);
310 outbound_video->nack_count =
311 static_cast<uint32_t>(video_sender_info.nacks_rcvd);
hbos6769c492017-01-02 08:35:13 -0800312 if (video_sender_info.qp_sum)
313 outbound_video->qp_sum = *video_sender_info.qp_sum;
314 outbound_video->frames_encoded = video_sender_info.frames_encoded;
hbos6ded1902016-11-01 01:50:46 -0700315}
316
hbos02ba2112016-10-28 05:14:53 -0700317void ProduceCertificateStatsFromSSLCertificateStats(
318 int64_t timestamp_us, const rtc::SSLCertificateStats& certificate_stats,
319 RTCStatsReport* report) {
320 RTCCertificateStats* prev_certificate_stats = nullptr;
321 for (const rtc::SSLCertificateStats* s = &certificate_stats; s;
322 s = s->issuer.get()) {
hbos02d2a922016-12-21 01:29:05 -0800323 std::string certificate_stats_id =
324 RTCCertificateIDFromFingerprint(s->fingerprint);
325 // It is possible for the same certificate to show up multiple times, e.g.
326 // if local and remote side use the same certificate in a loopback call.
327 // If the report already contains stats for this certificate, skip it.
328 if (report->Get(certificate_stats_id)) {
329 RTC_DCHECK_EQ(s, &certificate_stats);
330 break;
331 }
hbos02ba2112016-10-28 05:14:53 -0700332 RTCCertificateStats* certificate_stats = new RTCCertificateStats(
hbos02d2a922016-12-21 01:29:05 -0800333 certificate_stats_id, timestamp_us);
hbos02ba2112016-10-28 05:14:53 -0700334 certificate_stats->fingerprint = s->fingerprint;
335 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm;
336 certificate_stats->base64_certificate = s->base64_certificate;
337 if (prev_certificate_stats)
338 prev_certificate_stats->issuer_certificate_id = certificate_stats->id();
339 report->AddStats(std::unique_ptr<RTCCertificateStats>(certificate_stats));
340 prev_certificate_stats = certificate_stats;
341 }
342}
343
344const std::string& ProduceIceCandidateStats(
345 int64_t timestamp_us, const cricket::Candidate& candidate, bool is_local,
hbosb4e426e2017-01-02 09:59:31 -0800346 const std::string& transport_id, RTCStatsReport* report) {
hbos02ba2112016-10-28 05:14:53 -0700347 const std::string& id = "RTCIceCandidate_" + candidate.id();
348 const RTCStats* stats = report->Get(id);
349 if (!stats) {
350 std::unique_ptr<RTCIceCandidateStats> candidate_stats;
351 if (is_local)
352 candidate_stats.reset(new RTCLocalIceCandidateStats(id, timestamp_us));
353 else
354 candidate_stats.reset(new RTCRemoteIceCandidateStats(id, timestamp_us));
hbosb4e426e2017-01-02 09:59:31 -0800355 candidate_stats->transport_id = transport_id;
hbos02ba2112016-10-28 05:14:53 -0700356 candidate_stats->ip = candidate.address().ipaddr().ToString();
357 candidate_stats->port = static_cast<int32_t>(candidate.address().port());
358 candidate_stats->protocol = candidate.protocol();
359 candidate_stats->candidate_type = CandidateTypeToRTCIceCandidateType(
360 candidate.type());
361 candidate_stats->priority = static_cast<int32_t>(candidate.priority());
362
363 stats = candidate_stats.get();
364 report->AddStats(std::move(candidate_stats));
365 }
366 RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType
367 : RTCRemoteIceCandidateStats::kType);
368 return stats->id();
369}
370
hbos9e302742017-01-20 02:47:10 -0800371std::unique_ptr<RTCMediaStreamTrackStats>
372ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
373 int64_t timestamp_us,
374 const AudioTrackInterface& audio_track,
375 const cricket::VoiceSenderInfo& voice_sender_info) {
376 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
377 new RTCMediaStreamTrackStats(
378 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
379 true, MediaStreamTrackInterface::kAudioKind, audio_track.id(),
380 voice_sender_info.ssrc()),
381 timestamp_us,
382 RTCMediaStreamTrackKind::kAudio));
383 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
384 audio_track, audio_track_stats.get());
385 audio_track_stats->remote_source = false;
386 audio_track_stats->detached = false;
387 if (voice_sender_info.audio_level >= 0) {
388 audio_track_stats->audio_level = DoubleAudioLevelFromIntAudioLevel(
389 voice_sender_info.audio_level);
390 }
zsteine76bd3a2017-07-14 12:17:49 -0700391 audio_track_stats->total_audio_energy = voice_sender_info.total_input_energy;
392 audio_track_stats->total_samples_duration =
393 voice_sender_info.total_input_duration;
hbos9e302742017-01-20 02:47:10 -0800394 if (voice_sender_info.echo_return_loss != -100) {
395 audio_track_stats->echo_return_loss = static_cast<double>(
396 voice_sender_info.echo_return_loss);
397 }
398 if (voice_sender_info.echo_return_loss_enhancement != -100) {
399 audio_track_stats->echo_return_loss_enhancement = static_cast<double>(
400 voice_sender_info.echo_return_loss_enhancement);
401 }
402 return audio_track_stats;
403}
404
405std::unique_ptr<RTCMediaStreamTrackStats>
406ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
407 int64_t timestamp_us,
408 const AudioTrackInterface& audio_track,
409 const cricket::VoiceReceiverInfo& voice_receiver_info) {
410 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
411 new RTCMediaStreamTrackStats(
412 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
413 false, MediaStreamTrackInterface::kAudioKind, audio_track.id(),
414 voice_receiver_info.ssrc()),
415 timestamp_us,
416 RTCMediaStreamTrackKind::kAudio));
417 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
418 audio_track, audio_track_stats.get());
419 audio_track_stats->remote_source = true;
420 audio_track_stats->detached = false;
421 if (voice_receiver_info.audio_level >= 0) {
422 audio_track_stats->audio_level = DoubleAudioLevelFromIntAudioLevel(
423 voice_receiver_info.audio_level);
424 }
zsteine76bd3a2017-07-14 12:17:49 -0700425 audio_track_stats->total_audio_energy =
426 voice_receiver_info.total_output_energy;
427 audio_track_stats->total_samples_duration =
428 voice_receiver_info.total_output_duration;
hbos9e302742017-01-20 02:47:10 -0800429 return audio_track_stats;
430}
431
432std::unique_ptr<RTCMediaStreamTrackStats>
433ProduceMediaStreamTrackStatsFromVideoSenderInfo(
434 int64_t timestamp_us,
435 const VideoTrackInterface& video_track,
436 const cricket::VideoSenderInfo& video_sender_info) {
437 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
438 new RTCMediaStreamTrackStats(
439 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
440 true, MediaStreamTrackInterface::kVideoKind, video_track.id(),
441 video_sender_info.ssrc()),
442 timestamp_us,
443 RTCMediaStreamTrackKind::kVideo));
444 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
445 video_track, video_track_stats.get());
446 video_track_stats->remote_source = false;
447 video_track_stats->detached = false;
448 video_track_stats->frame_width = static_cast<uint32_t>(
449 video_sender_info.send_frame_width);
450 video_track_stats->frame_height = static_cast<uint32_t>(
451 video_sender_info.send_frame_height);
hbosfefe0762017-01-20 06:14:25 -0800452 // TODO(hbos): Will reduce this by frames dropped due to congestion control
453 // when available. crbug.com/659137
454 video_track_stats->frames_sent = video_sender_info.frames_encoded;
hbos9e302742017-01-20 02:47:10 -0800455 return video_track_stats;
456}
457
458std::unique_ptr<RTCMediaStreamTrackStats>
459ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
460 int64_t timestamp_us,
461 const VideoTrackInterface& video_track,
462 const cricket::VideoReceiverInfo& video_receiver_info) {
463 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
464 new RTCMediaStreamTrackStats(
465 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
466 false, MediaStreamTrackInterface::kVideoKind, video_track.id(),
467 video_receiver_info.ssrc()),
468 timestamp_us,
469 RTCMediaStreamTrackKind::kVideo));
470 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
471 video_track, video_track_stats.get());
472 video_track_stats->remote_source = true;
473 video_track_stats->detached = false;
474 if (video_receiver_info.frame_width > 0 &&
475 video_receiver_info.frame_height > 0) {
476 video_track_stats->frame_width = static_cast<uint32_t>(
477 video_receiver_info.frame_width);
478 video_track_stats->frame_height = static_cast<uint32_t>(
479 video_receiver_info.frame_height);
480 }
hbos42f6d2f2017-01-20 03:56:50 -0800481 video_track_stats->frames_received = video_receiver_info.frames_received;
hbosf64941f2017-01-20 07:39:09 -0800482 // TODO(hbos): When we support receiving simulcast, this should be the total
483 // number of frames correctly decoded, independent of which SSRC it was
484 // received from. Since we don't support that, this is correct and is the same
485 // value as "RTCInboundRTPStreamStats.framesDecoded". crbug.com/659137
486 video_track_stats->frames_decoded = video_receiver_info.frames_decoded;
hbos50cfe1f2017-01-23 07:21:55 -0800487 RTC_DCHECK_GE(video_receiver_info.frames_received,
488 video_receiver_info.frames_rendered);
489 video_track_stats->frames_dropped = video_receiver_info.frames_received -
490 video_receiver_info.frames_rendered;
hbos9e302742017-01-20 02:47:10 -0800491 return video_track_stats;
492}
493
hbos09bc1282016-11-08 06:29:22 -0800494void ProduceMediaStreamAndTrackStats(
495 int64_t timestamp_us,
hbos9e302742017-01-20 02:47:10 -0800496 const TrackMediaInfoMap& track_media_info_map,
hbos09bc1282016-11-08 06:29:22 -0800497 rtc::scoped_refptr<StreamCollectionInterface> streams,
498 bool is_local,
499 RTCStatsReport* report) {
500 // TODO(hbos): When "AddTrack" is implemented we should iterate tracks to
501 // find which streams exist, not iterate streams to find tracks.
502 // crbug.com/659137
503 // TODO(hbos): Return stats of detached tracks. We have to perform stats
504 // gathering at the time of detachment to get accurate stats and timestamps.
505 // crbug.com/659137
506 if (!streams)
507 return;
508 for (size_t i = 0; i < streams->count(); ++i) {
509 MediaStreamInterface* stream = streams->at(i);
510
511 std::unique_ptr<RTCMediaStreamStats> stream_stats(
hbos02d2a922016-12-21 01:29:05 -0800512 new RTCMediaStreamStats(
513 (is_local ? "RTCMediaStream_local_" : "RTCMediaStream_remote_") +
514 stream->label(), timestamp_us));
hbos09bc1282016-11-08 06:29:22 -0800515 stream_stats->stream_identifier = stream->label();
516 stream_stats->track_ids = std::vector<std::string>();
hbos9e302742017-01-20 02:47:10 -0800517 // The track stats are per-attachment to the connection. There can be one
518 // for receiving (remote) tracks and multiple attachments for sending
519 // (local) tracks.
520 if (is_local) {
521 // Local Audio Tracks
522 for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track :
523 stream->GetAudioTracks()) {
524 const std::vector<cricket::VoiceSenderInfo*>* voice_sender_infos =
525 track_media_info_map.GetVoiceSenderInfos(*audio_track);
526 if (!voice_sender_infos) {
527 continue;
hbos9a394f02016-12-14 07:58:22 -0800528 }
hbos9e302742017-01-20 02:47:10 -0800529 for (const auto& voice_sender_info : *voice_sender_infos) {
530 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
531 ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
532 timestamp_us, *audio_track, *voice_sender_info);
533 stream_stats->track_ids->push_back(audio_track_stats->id());
534 report->AddStats(std::move(audio_track_stats));
hbos9a394f02016-12-14 07:58:22 -0800535 }
hbos09bc1282016-11-08 06:29:22 -0800536 }
hbos9e302742017-01-20 02:47:10 -0800537 // Local Video Tracks
538 for (const rtc::scoped_refptr<VideoTrackInterface>& video_track :
539 stream->GetVideoTracks()) {
540 const std::vector<cricket::VideoSenderInfo*>* video_sender_infos =
541 track_media_info_map.GetVideoSenderInfos(*video_track);
542 if (!video_sender_infos) {
543 continue;
544 }
545 for (const auto& video_sender_info : *video_sender_infos) {
546 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
547 ProduceMediaStreamTrackStatsFromVideoSenderInfo(
548 timestamp_us, *video_track, *video_sender_info);
549 stream_stats->track_ids->push_back(video_track_stats->id());
550 report->AddStats(std::move(video_track_stats));
hbos09bc1282016-11-08 06:29:22 -0800551 }
552 }
hbos9e302742017-01-20 02:47:10 -0800553 } else {
554 // Remote Audio Tracks
555 for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track :
556 stream->GetAudioTracks()) {
557 const cricket::VoiceReceiverInfo* voice_receiver_info =
558 track_media_info_map.GetVoiceReceiverInfo(*audio_track);
559 if (!voice_receiver_info) {
560 continue;
561 }
562 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
563 ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
564 timestamp_us, *audio_track, *voice_receiver_info);
565 stream_stats->track_ids->push_back(audio_track_stats->id());
566 report->AddStats(std::move(audio_track_stats));
567 }
568 // Remote Video Tracks
569 for (const rtc::scoped_refptr<VideoTrackInterface>& video_track :
570 stream->GetVideoTracks()) {
571 const cricket::VideoReceiverInfo* video_receiver_info =
572 track_media_info_map.GetVideoReceiverInfo(*video_track);
573 if (!video_receiver_info) {
574 continue;
575 }
576 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
577 ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
578 timestamp_us, *video_track, *video_receiver_info);
579 stream_stats->track_ids->push_back(video_track_stats->id());
580 report->AddStats(std::move(video_track_stats));
581 }
hbos09bc1282016-11-08 06:29:22 -0800582 }
583 report->AddStats(std::move(stream_stats));
584 }
585}
586
hboscc555c52016-10-18 12:48:31 -0700587} // namespace
588
hbosc82f2e12016-09-05 01:36:50 -0700589rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
590 PeerConnection* pc, int64_t cache_lifetime_us) {
591 return rtc::scoped_refptr<RTCStatsCollector>(
592 new rtc::RefCountedObject<RTCStatsCollector>(pc, cache_lifetime_us));
593}
594
595RTCStatsCollector::RTCStatsCollector(PeerConnection* pc,
596 int64_t cache_lifetime_us)
hbosd565b732016-08-30 14:04:35 -0700597 : pc_(pc),
hbosc82f2e12016-09-05 01:36:50 -0700598 signaling_thread_(pc->session()->signaling_thread()),
599 worker_thread_(pc->session()->worker_thread()),
600 network_thread_(pc->session()->network_thread()),
601 num_pending_partial_reports_(0),
602 partial_report_timestamp_us_(0),
hbos0e6758d2016-08-31 07:57:36 -0700603 cache_timestamp_us_(0),
604 cache_lifetime_us_(cache_lifetime_us) {
hbosd565b732016-08-30 14:04:35 -0700605 RTC_DCHECK(pc_);
hbosc82f2e12016-09-05 01:36:50 -0700606 RTC_DCHECK(signaling_thread_);
607 RTC_DCHECK(worker_thread_);
608 RTC_DCHECK(network_thread_);
hbos0e6758d2016-08-31 07:57:36 -0700609 RTC_DCHECK_GE(cache_lifetime_us_, 0);
hbos82ebe022016-11-14 01:41:09 -0800610 pc_->SignalDataChannelCreated.connect(
611 this, &RTCStatsCollector::OnDataChannelCreated);
hbosd565b732016-08-30 14:04:35 -0700612}
613
hbosb78306a2016-12-19 05:06:57 -0800614RTCStatsCollector::~RTCStatsCollector() {
615 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
616}
617
hbosc82f2e12016-09-05 01:36:50 -0700618void RTCStatsCollector::GetStatsReport(
619 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
620 RTC_DCHECK(signaling_thread_->IsCurrent());
621 RTC_DCHECK(callback);
622 callbacks_.push_back(callback);
623
hbos0e6758d2016-08-31 07:57:36 -0700624 // "Now" using a monotonically increasing timer.
625 int64_t cache_now_us = rtc::TimeMicros();
626 if (cached_report_ &&
627 cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) {
hbosc82f2e12016-09-05 01:36:50 -0700628 // We have a fresh cached report to deliver.
629 DeliverCachedReport();
630 } else if (!num_pending_partial_reports_) {
631 // Only start gathering stats if we're not already gathering stats. In the
632 // case of already gathering stats, |callback_| will be invoked when there
633 // are no more pending partial reports.
634
635 // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
636 // UTC), in microseconds. The system clock could be modified and is not
637 // necessarily monotonically increasing.
nissecdf37a92016-09-13 23:41:47 -0700638 int64_t timestamp_us = rtc::TimeUTCMicros();
hbosc82f2e12016-09-05 01:36:50 -0700639
hbosf415f8a2017-01-02 04:28:51 -0800640 num_pending_partial_reports_ = 2;
hbosc82f2e12016-09-05 01:36:50 -0700641 partial_report_timestamp_us_ = cache_now_us;
hbosdf6075a2016-12-19 04:58:02 -0800642
hbos84abeb12017-01-16 06:16:44 -0800643 // Prepare |channel_name_pairs_| for use in
hbosdf6075a2016-12-19 04:58:02 -0800644 // |ProducePartialResultsOnNetworkThread|.
645 channel_name_pairs_.reset(new ChannelNamePairs());
646 if (pc_->session()->voice_channel()) {
647 channel_name_pairs_->voice = rtc::Optional<ChannelNamePair>(
648 ChannelNamePair(pc_->session()->voice_channel()->content_name(),
649 pc_->session()->voice_channel()->transport_name()));
650 }
651 if (pc_->session()->video_channel()) {
652 channel_name_pairs_->video = rtc::Optional<ChannelNamePair>(
653 ChannelNamePair(pc_->session()->video_channel()->content_name(),
654 pc_->session()->video_channel()->transport_name()));
655 }
deadbeef953c2ce2017-01-09 14:53:41 -0800656 if (pc_->session()->rtp_data_channel()) {
657 channel_name_pairs_->data =
658 rtc::Optional<ChannelNamePair>(ChannelNamePair(
659 pc_->session()->rtp_data_channel()->content_name(),
660 pc_->session()->rtp_data_channel()->transport_name()));
661 }
662 if (pc_->session()->sctp_content_name()) {
hbosdf6075a2016-12-19 04:58:02 -0800663 channel_name_pairs_->data = rtc::Optional<ChannelNamePair>(
deadbeef953c2ce2017-01-09 14:53:41 -0800664 ChannelNamePair(*pc_->session()->sctp_content_name(),
665 *pc_->session()->sctp_transport_name()));
hbosdf6075a2016-12-19 04:58:02 -0800666 }
hbos84abeb12017-01-16 06:16:44 -0800667 // Prepare |track_media_info_map_| for use in
668 // |ProducePartialResultsOnNetworkThread| and
669 // |ProducePartialResultsOnSignalingThread|.
670 track_media_info_map_.reset(PrepareTrackMediaInfoMap_s().release());
671 // Prepare |track_to_id_| for use in |ProducePartialResultsOnNetworkThread|.
672 // This avoids a possible deadlock if |MediaStreamTrackInterface::id| is
673 // implemented to invoke on the signaling thread.
674 track_to_id_ = PrepareTrackToID_s();
hbosf415f8a2017-01-02 04:28:51 -0800675
stefanf79ade12017-06-02 06:44:03 -0700676 // Prepare |call_stats_| here since GetCallStats() will hop to the worker
677 // thread.
678 // TODO(holmer): To avoid the hop we could move BWE and BWE stats to the
679 // network thread, where it more naturally belongs.
680 call_stats_ = pc_->session()->GetCallStats();
681
682 invoker_.AsyncInvoke<void>(
683 RTC_FROM_HERE, network_thread_,
hbosc82f2e12016-09-05 01:36:50 -0700684 rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread,
stefanf79ade12017-06-02 06:44:03 -0700685 rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us));
hbosf415f8a2017-01-02 04:28:51 -0800686 ProducePartialResultsOnSignalingThread(timestamp_us);
hbos0e6758d2016-08-31 07:57:36 -0700687 }
hbosd565b732016-08-30 14:04:35 -0700688}
689
690void RTCStatsCollector::ClearCachedStatsReport() {
hbosc82f2e12016-09-05 01:36:50 -0700691 RTC_DCHECK(signaling_thread_->IsCurrent());
hbosd565b732016-08-30 14:04:35 -0700692 cached_report_ = nullptr;
693}
694
hbosb78306a2016-12-19 05:06:57 -0800695void RTCStatsCollector::WaitForPendingRequest() {
696 RTC_DCHECK(signaling_thread_->IsCurrent());
697 if (num_pending_partial_reports_) {
698 rtc::Thread::Current()->ProcessMessages(0);
699 while (num_pending_partial_reports_) {
700 rtc::Thread::Current()->SleepMs(1);
701 rtc::Thread::Current()->ProcessMessages(0);
702 }
703 }
704}
705
hbosc82f2e12016-09-05 01:36:50 -0700706void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
707 int64_t timestamp_us) {
708 RTC_DCHECK(signaling_thread_->IsCurrent());
hbos6ded1902016-11-01 01:50:46 -0700709 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(
710 timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -0700711
hboscc555c52016-10-18 12:48:31 -0700712 ProduceDataChannelStats_s(timestamp_us, report.get());
hbos09bc1282016-11-08 06:29:22 -0800713 ProduceMediaStreamAndTrackStats_s(timestamp_us, report.get());
hbos6ab97ce2016-10-03 14:16:56 -0700714 ProducePeerConnectionStats_s(timestamp_us, report.get());
hbosc82f2e12016-09-05 01:36:50 -0700715
716 AddPartialResults(report);
717}
718
hbosc82f2e12016-09-05 01:36:50 -0700719void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
720 int64_t timestamp_us) {
721 RTC_DCHECK(network_thread_->IsCurrent());
hbos6ded1902016-11-01 01:50:46 -0700722 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(
723 timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -0700724
hbosdf6075a2016-12-19 04:58:02 -0800725 std::unique_ptr<SessionStats> session_stats =
726 pc_->session()->GetStats(*channel_name_pairs_);
727 if (session_stats) {
728 std::map<std::string, CertificateStatsPair> transport_cert_stats =
729 PrepareTransportCertificateStats_n(*session_stats);
730
731 ProduceCertificateStats_n(
732 timestamp_us, transport_cert_stats, report.get());
733 ProduceCodecStats_n(
hbos84abeb12017-01-16 06:16:44 -0800734 timestamp_us, *track_media_info_map_, report.get());
stefanf79ade12017-06-02 06:44:03 -0700735 ProduceIceCandidateAndPairStats_n(timestamp_us, *session_stats,
736 track_media_info_map_->video_media_info(),
737 call_stats_, report.get());
hbosdf6075a2016-12-19 04:58:02 -0800738 ProduceRTPStreamStats_n(
hbos84abeb12017-01-16 06:16:44 -0800739 timestamp_us, *session_stats, *track_media_info_map_, report.get());
hbosdf6075a2016-12-19 04:58:02 -0800740 ProduceTransportStats_n(
741 timestamp_us, *session_stats, transport_cert_stats, report.get());
742 }
hbosc82f2e12016-09-05 01:36:50 -0700743
744 AddPartialResults(report);
745}
746
747void RTCStatsCollector::AddPartialResults(
748 const rtc::scoped_refptr<RTCStatsReport>& partial_report) {
749 if (!signaling_thread_->IsCurrent()) {
750 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
751 rtc::Bind(&RTCStatsCollector::AddPartialResults_s,
752 rtc::scoped_refptr<RTCStatsCollector>(this),
753 partial_report));
754 return;
755 }
756 AddPartialResults_s(partial_report);
757}
758
759void RTCStatsCollector::AddPartialResults_s(
760 rtc::scoped_refptr<RTCStatsReport> partial_report) {
761 RTC_DCHECK(signaling_thread_->IsCurrent());
762 RTC_DCHECK_GT(num_pending_partial_reports_, 0);
763 if (!partial_report_)
764 partial_report_ = partial_report;
765 else
766 partial_report_->TakeMembersFrom(partial_report);
767 --num_pending_partial_reports_;
768 if (!num_pending_partial_reports_) {
769 cache_timestamp_us_ = partial_report_timestamp_us_;
770 cached_report_ = partial_report_;
771 partial_report_ = nullptr;
hbos84abeb12017-01-16 06:16:44 -0800772 channel_name_pairs_.reset();
773 track_media_info_map_.reset();
774 track_to_id_.clear();
ehmaldonadoa26196b2017-07-18 03:30:29 -0700775 // Trace WebRTC Stats when getStats is called on Javascript.
776 // This allows access to WebRTC stats from trace logs. To enable them,
777 // select the "webrtc_stats" category when recording traces.
mbonadei3439c892017-08-14 23:48:03 -0700778 for (const RTCStats& stats : *cached_report_) {
779 for (const RTCStatsMemberInterface* member : stats.Members()) {
780 if (member->is_defined()) {
781 TRACE_EVENT_INSTANT2("webrtc_stats", "webrtc_stats",
782 "value", member->ValueToString(),
783 "type.name.id", GetStatTypeMemberNameAndId(
784 stats, member));
785 }
786 }
787 }
hbosc82f2e12016-09-05 01:36:50 -0700788 DeliverCachedReport();
789 }
790}
791
792void RTCStatsCollector::DeliverCachedReport() {
793 RTC_DCHECK(signaling_thread_->IsCurrent());
794 RTC_DCHECK(!callbacks_.empty());
795 RTC_DCHECK(cached_report_);
796 for (const rtc::scoped_refptr<RTCStatsCollectorCallback>& callback :
797 callbacks_) {
798 callback->OnStatsDelivered(cached_report_);
799 }
800 callbacks_.clear();
hbosd565b732016-08-30 14:04:35 -0700801}
802
hbosdf6075a2016-12-19 04:58:02 -0800803void RTCStatsCollector::ProduceCertificateStats_n(
hbos2fa7c672016-10-24 04:00:05 -0700804 int64_t timestamp_us,
805 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
hbos6ab97ce2016-10-03 14:16:56 -0700806 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800807 RTC_DCHECK(network_thread_->IsCurrent());
hbos02ba2112016-10-28 05:14:53 -0700808 for (const auto& transport_cert_stats_pair : transport_cert_stats) {
809 if (transport_cert_stats_pair.second.local) {
810 ProduceCertificateStatsFromSSLCertificateStats(
811 timestamp_us, *transport_cert_stats_pair.second.local.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -0700812 }
hbos02ba2112016-10-28 05:14:53 -0700813 if (transport_cert_stats_pair.second.remote) {
814 ProduceCertificateStatsFromSSLCertificateStats(
815 timestamp_us, *transport_cert_stats_pair.second.remote.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -0700816 }
817 }
818}
819
hbosdf6075a2016-12-19 04:58:02 -0800820void RTCStatsCollector::ProduceCodecStats_n(
hbos84abeb12017-01-16 06:16:44 -0800821 int64_t timestamp_us, const TrackMediaInfoMap& track_media_info_map,
hbos0adb8282016-11-23 02:32:06 -0800822 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800823 RTC_DCHECK(network_thread_->IsCurrent());
hbos0adb8282016-11-23 02:32:06 -0800824 // Audio
hbos84abeb12017-01-16 06:16:44 -0800825 if (track_media_info_map.voice_media_info()) {
hbos0adb8282016-11-23 02:32:06 -0800826 // Inbound
hbos84abeb12017-01-16 06:16:44 -0800827 for (const auto& pair :
828 track_media_info_map.voice_media_info()->receive_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800829 report->AddStats(CodecStatsFromRtpCodecParameters(
830 timestamp_us, true, true, pair.second));
831 }
832 // Outbound
hbos84abeb12017-01-16 06:16:44 -0800833 for (const auto& pair :
834 track_media_info_map.voice_media_info()->send_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800835 report->AddStats(CodecStatsFromRtpCodecParameters(
836 timestamp_us, false, true, pair.second));
837 }
838 }
839 // Video
hbos84abeb12017-01-16 06:16:44 -0800840 if (track_media_info_map.video_media_info()) {
hbos0adb8282016-11-23 02:32:06 -0800841 // Inbound
hbos84abeb12017-01-16 06:16:44 -0800842 for (const auto& pair :
843 track_media_info_map.video_media_info()->receive_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800844 report->AddStats(CodecStatsFromRtpCodecParameters(
845 timestamp_us, true, false, pair.second));
846 }
847 // Outbound
hbos84abeb12017-01-16 06:16:44 -0800848 for (const auto& pair :
849 track_media_info_map.video_media_info()->send_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800850 report->AddStats(CodecStatsFromRtpCodecParameters(
851 timestamp_us, false, false, pair.second));
852 }
853 }
854}
855
hboscc555c52016-10-18 12:48:31 -0700856void RTCStatsCollector::ProduceDataChannelStats_s(
857 int64_t timestamp_us, RTCStatsReport* report) const {
858 RTC_DCHECK(signaling_thread_->IsCurrent());
859 for (const rtc::scoped_refptr<DataChannel>& data_channel :
860 pc_->sctp_data_channels()) {
861 std::unique_ptr<RTCDataChannelStats> data_channel_stats(
862 new RTCDataChannelStats(
863 "RTCDataChannel_" + rtc::ToString<>(data_channel->id()),
864 timestamp_us));
865 data_channel_stats->label = data_channel->label();
866 data_channel_stats->protocol = data_channel->protocol();
867 data_channel_stats->datachannelid = data_channel->id();
868 data_channel_stats->state =
869 DataStateToRTCDataChannelState(data_channel->state());
870 data_channel_stats->messages_sent = data_channel->messages_sent();
871 data_channel_stats->bytes_sent = data_channel->bytes_sent();
872 data_channel_stats->messages_received = data_channel->messages_received();
873 data_channel_stats->bytes_received = data_channel->bytes_received();
874 report->AddStats(std::move(data_channel_stats));
875 }
876}
877
hbosdf6075a2016-12-19 04:58:02 -0800878void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
stefanf79ade12017-06-02 06:44:03 -0700879 int64_t timestamp_us,
880 const SessionStats& session_stats,
881 const cricket::VideoMediaInfo* video_media_info,
882 const Call::Stats& call_stats,
883 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800884 RTC_DCHECK(network_thread_->IsCurrent());
hbosc47a0c32016-10-11 14:54:49 -0700885 for (const auto& transport_stats : session_stats.transport_stats) {
886 for (const auto& channel_stats : transport_stats.second.channel_stats) {
hbos0583b282016-11-30 01:50:14 -0800887 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
888 transport_stats.second.transport_name, channel_stats.component);
hbosc47a0c32016-10-11 14:54:49 -0700889 for (const cricket::ConnectionInfo& info :
890 channel_stats.connection_infos) {
hbosc47a0c32016-10-11 14:54:49 -0700891 std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
hbos2fa7c672016-10-24 04:00:05 -0700892 new RTCIceCandidatePairStats(
893 RTCIceCandidatePairStatsIDFromConnectionInfo(info),
894 timestamp_us));
hbosc47a0c32016-10-11 14:54:49 -0700895
hbos0583b282016-11-30 01:50:14 -0800896 candidate_pair_stats->transport_id = transport_id;
hbosab9f6e42016-10-07 02:18:47 -0700897 // TODO(hbos): There could be other candidates that are not paired with
898 // anything. We don't have a complete list. Local candidates come from
899 // Port objects, and prflx candidates (both local and remote) are only
900 // stored in candidate pairs. crbug.com/632723
hbos02ba2112016-10-28 05:14:53 -0700901 candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -0800902 timestamp_us, info.local_candidate, true, transport_id, report);
hbos02ba2112016-10-28 05:14:53 -0700903 candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -0800904 timestamp_us, info.remote_candidate, false, transport_id, report);
hbos06495bc2017-01-02 08:08:18 -0800905 candidate_pair_stats->state =
906 IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
907 candidate_pair_stats->priority = info.priority;
hbos92eaec62017-02-27 01:38:08 -0800908 candidate_pair_stats->nominated = info.nominated;
hbosc47a0c32016-10-11 14:54:49 -0700909 // TODO(hbos): This writable is different than the spec. It goes to
910 // false after a certain amount of time without a response passes.
911 // crbug.com/633550
912 candidate_pair_stats->writable = info.writable;
hbosc47a0c32016-10-11 14:54:49 -0700913 candidate_pair_stats->bytes_sent =
914 static_cast<uint64_t>(info.sent_total_bytes);
915 candidate_pair_stats->bytes_received =
916 static_cast<uint64_t>(info.recv_total_bytes);
hbosbf8d3e52017-02-28 06:34:47 -0800917 candidate_pair_stats->total_round_trip_time =
918 static_cast<double>(info.total_round_trip_time_ms) /
919 rtc::kNumMillisecsPerSec;
920 if (info.current_round_trip_time_ms) {
921 candidate_pair_stats->current_round_trip_time =
922 static_cast<double>(*info.current_round_trip_time_ms) /
923 rtc::kNumMillisecsPerSec;
924 }
stefanf79ade12017-06-02 06:44:03 -0700925 if (info.best_connection) {
hbos338f78a2017-02-07 06:41:21 -0800926 // The bandwidth estimations we have are for the selected candidate
927 // pair ("info.best_connection").
stefanf79ade12017-06-02 06:44:03 -0700928 RTC_DCHECK_GE(call_stats.send_bandwidth_bps, 0);
929 RTC_DCHECK_GE(call_stats.recv_bandwidth_bps, 0);
930 if (call_stats.send_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -0800931 candidate_pair_stats->available_outgoing_bitrate =
stefanf79ade12017-06-02 06:44:03 -0700932 static_cast<double>(call_stats.send_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -0800933 }
stefanf79ade12017-06-02 06:44:03 -0700934 if (call_stats.recv_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -0800935 candidate_pair_stats->available_incoming_bitrate =
stefanf79ade12017-06-02 06:44:03 -0700936 static_cast<double>(call_stats.recv_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -0800937 }
938 }
hbosd82f5122016-12-09 04:12:39 -0800939 candidate_pair_stats->requests_received =
940 static_cast<uint64_t>(info.recv_ping_requests);
hbose448dd52016-12-12 01:22:53 -0800941 candidate_pair_stats->requests_sent = static_cast<uint64_t>(
942 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -0700943 candidate_pair_stats->responses_received =
944 static_cast<uint64_t>(info.recv_ping_responses);
945 candidate_pair_stats->responses_sent =
946 static_cast<uint64_t>(info.sent_ping_responses);
hbose448dd52016-12-12 01:22:53 -0800947 RTC_DCHECK_GE(info.sent_ping_requests_total,
948 info.sent_ping_requests_before_first_response);
949 candidate_pair_stats->consent_requests_sent = static_cast<uint64_t>(
950 info.sent_ping_requests_total -
951 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -0700952
953 report->AddStats(std::move(candidate_pair_stats));
hbosab9f6e42016-10-07 02:18:47 -0700954 }
955 }
956 }
957}
958
hbos09bc1282016-11-08 06:29:22 -0800959void RTCStatsCollector::ProduceMediaStreamAndTrackStats_s(
960 int64_t timestamp_us, RTCStatsReport* report) const {
961 RTC_DCHECK(signaling_thread_->IsCurrent());
hbos9e302742017-01-20 02:47:10 -0800962 RTC_DCHECK(track_media_info_map_);
963 ProduceMediaStreamAndTrackStats(timestamp_us,
964 *track_media_info_map_,
965 pc_->local_streams(),
966 true,
967 report);
968 ProduceMediaStreamAndTrackStats(timestamp_us,
969 *track_media_info_map_,
970 pc_->remote_streams(),
971 false,
972 report);
hbos09bc1282016-11-08 06:29:22 -0800973}
974
hbos6ab97ce2016-10-03 14:16:56 -0700975void RTCStatsCollector::ProducePeerConnectionStats_s(
976 int64_t timestamp_us, RTCStatsReport* report) const {
hbosc82f2e12016-09-05 01:36:50 -0700977 RTC_DCHECK(signaling_thread_->IsCurrent());
hbosd565b732016-08-30 14:04:35 -0700978 std::unique_ptr<RTCPeerConnectionStats> stats(
hbos0e6758d2016-08-31 07:57:36 -0700979 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us));
hbos82ebe022016-11-14 01:41:09 -0800980 stats->data_channels_opened = internal_record_.data_channels_opened;
981 stats->data_channels_closed = internal_record_.data_channels_closed;
hbos6ab97ce2016-10-03 14:16:56 -0700982 report->AddStats(std::move(stats));
hbosd565b732016-08-30 14:04:35 -0700983}
984
hbosdf6075a2016-12-19 04:58:02 -0800985void RTCStatsCollector::ProduceRTPStreamStats_n(
hbos6ded1902016-11-01 01:50:46 -0700986 int64_t timestamp_us, const SessionStats& session_stats,
hbos84abeb12017-01-16 06:16:44 -0800987 const TrackMediaInfoMap& track_media_info_map,
988 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800989 RTC_DCHECK(network_thread_->IsCurrent());
hbos6ded1902016-11-01 01:50:46 -0700990
991 // Audio
hbos84abeb12017-01-16 06:16:44 -0800992 if (track_media_info_map.voice_media_info()) {
hbos0adb8282016-11-23 02:32:06 -0800993 std::string transport_id = RTCTransportStatsIDFromBaseChannel(
994 session_stats.proxy_to_transport, *pc_->session()->voice_channel());
995 RTC_DCHECK(!transport_id.empty());
996 // Inbound
997 for (const cricket::VoiceReceiverInfo& voice_receiver_info :
hbos84abeb12017-01-16 06:16:44 -0800998 track_media_info_map.voice_media_info()->receivers) {
hbos0adb8282016-11-23 02:32:06 -0800999 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1000 // is fixed.
1001 if (voice_receiver_info.ssrc() == 0)
1002 continue;
1003 std::unique_ptr<RTCInboundRTPStreamStats> inbound_audio(
1004 new RTCInboundRTPStreamStats(
1005 RTCInboundRTPStreamStatsIDFromSSRC(
1006 true, voice_receiver_info.ssrc()),
1007 timestamp_us));
1008 SetInboundRTPStreamStatsFromVoiceReceiverInfo(
1009 voice_receiver_info, inbound_audio.get());
hbos84abeb12017-01-16 06:16:44 -08001010 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1011 track_media_info_map_->GetAudioTrack(voice_receiver_info);
1012 if (audio_track) {
1013 RTC_DCHECK(track_to_id_.find(audio_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001014 inbound_audio->track_id =
hbos9e302742017-01-20 02:47:10 -08001015 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1016 false,
1017 MediaStreamTrackInterface::kAudioKind,
1018 track_to_id_.find(audio_track.get())->second,
1019 voice_receiver_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001020 }
hbos0adb8282016-11-23 02:32:06 -08001021 inbound_audio->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001022 report->AddStats(std::move(inbound_audio));
1023 }
1024 // Outbound
1025 for (const cricket::VoiceSenderInfo& voice_sender_info :
hbos84abeb12017-01-16 06:16:44 -08001026 track_media_info_map.voice_media_info()->senders) {
hbos0adb8282016-11-23 02:32:06 -08001027 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1028 // is fixed.
1029 if (voice_sender_info.ssrc() == 0)
1030 continue;
1031 std::unique_ptr<RTCOutboundRTPStreamStats> outbound_audio(
1032 new RTCOutboundRTPStreamStats(
1033 RTCOutboundRTPStreamStatsIDFromSSRC(
1034 true, voice_sender_info.ssrc()),
1035 timestamp_us));
1036 SetOutboundRTPStreamStatsFromVoiceSenderInfo(
1037 voice_sender_info, outbound_audio.get());
hbos84abeb12017-01-16 06:16:44 -08001038 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1039 track_media_info_map_->GetAudioTrack(voice_sender_info);
1040 if (audio_track) {
1041 RTC_DCHECK(track_to_id_.find(audio_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001042 outbound_audio->track_id =
hbos9e302742017-01-20 02:47:10 -08001043 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1044 true,
1045 MediaStreamTrackInterface::kAudioKind,
1046 track_to_id_.find(audio_track.get())->second,
1047 voice_sender_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001048 }
hbos0adb8282016-11-23 02:32:06 -08001049 outbound_audio->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001050 report->AddStats(std::move(outbound_audio));
hbos6ded1902016-11-01 01:50:46 -07001051 }
1052 }
1053 // Video
hbos84abeb12017-01-16 06:16:44 -08001054 if (track_media_info_map.video_media_info()) {
hbos0adb8282016-11-23 02:32:06 -08001055 std::string transport_id = RTCTransportStatsIDFromBaseChannel(
1056 session_stats.proxy_to_transport, *pc_->session()->video_channel());
1057 RTC_DCHECK(!transport_id.empty());
1058 // Inbound
1059 for (const cricket::VideoReceiverInfo& video_receiver_info :
hbos84abeb12017-01-16 06:16:44 -08001060 track_media_info_map.video_media_info()->receivers) {
hbos0adb8282016-11-23 02:32:06 -08001061 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1062 // is fixed.
1063 if (video_receiver_info.ssrc() == 0)
1064 continue;
1065 std::unique_ptr<RTCInboundRTPStreamStats> inbound_video(
1066 new RTCInboundRTPStreamStats(
1067 RTCInboundRTPStreamStatsIDFromSSRC(
1068 false, video_receiver_info.ssrc()),
1069 timestamp_us));
1070 SetInboundRTPStreamStatsFromVideoReceiverInfo(
1071 video_receiver_info, inbound_video.get());
hbos84abeb12017-01-16 06:16:44 -08001072 rtc::scoped_refptr<VideoTrackInterface> video_track =
1073 track_media_info_map_->GetVideoTrack(video_receiver_info);
1074 if (video_track) {
1075 RTC_DCHECK(track_to_id_.find(video_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001076 inbound_video->track_id =
hbos9e302742017-01-20 02:47:10 -08001077 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1078 false,
1079 MediaStreamTrackInterface::kVideoKind,
1080 track_to_id_.find(video_track.get())->second,
1081 video_receiver_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001082 }
hbos0adb8282016-11-23 02:32:06 -08001083 inbound_video->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001084 report->AddStats(std::move(inbound_video));
1085 }
1086 // Outbound
1087 for (const cricket::VideoSenderInfo& video_sender_info :
hbos84abeb12017-01-16 06:16:44 -08001088 track_media_info_map.video_media_info()->senders) {
hbos0adb8282016-11-23 02:32:06 -08001089 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1090 // is fixed.
1091 if (video_sender_info.ssrc() == 0)
1092 continue;
1093 std::unique_ptr<RTCOutboundRTPStreamStats> outbound_video(
1094 new RTCOutboundRTPStreamStats(
1095 RTCOutboundRTPStreamStatsIDFromSSRC(
1096 false, video_sender_info.ssrc()),
1097 timestamp_us));
1098 SetOutboundRTPStreamStatsFromVideoSenderInfo(
1099 video_sender_info, outbound_video.get());
hbos84abeb12017-01-16 06:16:44 -08001100 rtc::scoped_refptr<VideoTrackInterface> video_track =
1101 track_media_info_map_->GetVideoTrack(video_sender_info);
1102 if (video_track) {
1103 RTC_DCHECK(track_to_id_.find(video_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001104 outbound_video->track_id =
hbos9e302742017-01-20 02:47:10 -08001105 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1106 true,
1107 MediaStreamTrackInterface::kVideoKind,
1108 track_to_id_.find(video_track.get())->second,
1109 video_sender_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001110 }
hbos0adb8282016-11-23 02:32:06 -08001111 outbound_video->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001112 report->AddStats(std::move(outbound_video));
hbos6ded1902016-11-01 01:50:46 -07001113 }
1114 }
1115}
1116
hbosdf6075a2016-12-19 04:58:02 -08001117void RTCStatsCollector::ProduceTransportStats_n(
hbos2fa7c672016-10-24 04:00:05 -07001118 int64_t timestamp_us, const SessionStats& session_stats,
1119 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1120 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -08001121 RTC_DCHECK(network_thread_->IsCurrent());
hbos2fa7c672016-10-24 04:00:05 -07001122 for (const auto& transport : session_stats.transport_stats) {
1123 // Get reference to RTCP channel, if it exists.
1124 std::string rtcp_transport_stats_id;
1125 for (const auto& channel_stats : transport.second.channel_stats) {
1126 if (channel_stats.component ==
1127 cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
1128 rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel(
1129 transport.second.transport_name, channel_stats.component);
1130 break;
1131 }
1132 }
1133
1134 // Get reference to local and remote certificates of this transport, if they
1135 // exist.
1136 const auto& certificate_stats_it = transport_cert_stats.find(
1137 transport.second.transport_name);
1138 RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());
1139 std::string local_certificate_id;
1140 if (certificate_stats_it->second.local) {
1141 local_certificate_id = RTCCertificateIDFromFingerprint(
1142 certificate_stats_it->second.local->fingerprint);
1143 }
1144 std::string remote_certificate_id;
1145 if (certificate_stats_it->second.remote) {
1146 remote_certificate_id = RTCCertificateIDFromFingerprint(
1147 certificate_stats_it->second.remote->fingerprint);
1148 }
1149
1150 // There is one transport stats for each channel.
1151 for (const auto& channel_stats : transport.second.channel_stats) {
1152 std::unique_ptr<RTCTransportStats> transport_stats(
1153 new RTCTransportStats(
1154 RTCTransportStatsIDFromTransportChannel(
1155 transport.second.transport_name, channel_stats.component),
1156 timestamp_us));
1157 transport_stats->bytes_sent = 0;
1158 transport_stats->bytes_received = 0;
hbos7064d592017-01-16 07:38:02 -08001159 transport_stats->dtls_state = DtlsTransportStateToRTCDtlsTransportState(
1160 channel_stats.dtls_state);
hbos2fa7c672016-10-24 04:00:05 -07001161 for (const cricket::ConnectionInfo& info :
1162 channel_stats.connection_infos) {
1163 *transport_stats->bytes_sent += info.sent_total_bytes;
1164 *transport_stats->bytes_received += info.recv_total_bytes;
1165 if (info.best_connection) {
hbos2fa7c672016-10-24 04:00:05 -07001166 transport_stats->selected_candidate_pair_id =
1167 RTCIceCandidatePairStatsIDFromConnectionInfo(info);
1168 }
1169 }
1170 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
1171 !rtcp_transport_stats_id.empty()) {
1172 transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id;
1173 }
1174 if (!local_certificate_id.empty())
1175 transport_stats->local_certificate_id = local_certificate_id;
1176 if (!remote_certificate_id.empty())
1177 transport_stats->remote_certificate_id = remote_certificate_id;
1178 report->AddStats(std::move(transport_stats));
1179 }
1180 }
1181}
1182
1183std::map<std::string, RTCStatsCollector::CertificateStatsPair>
hbosdf6075a2016-12-19 04:58:02 -08001184RTCStatsCollector::PrepareTransportCertificateStats_n(
hbos2fa7c672016-10-24 04:00:05 -07001185 const SessionStats& session_stats) const {
hbosdf6075a2016-12-19 04:58:02 -08001186 RTC_DCHECK(network_thread_->IsCurrent());
hbos2fa7c672016-10-24 04:00:05 -07001187 std::map<std::string, CertificateStatsPair> transport_cert_stats;
1188 for (const auto& transport_stats : session_stats.transport_stats) {
1189 CertificateStatsPair certificate_stats_pair;
1190 rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
1191 if (pc_->session()->GetLocalCertificate(
1192 transport_stats.second.transport_name, &local_certificate)) {
1193 certificate_stats_pair.local =
1194 local_certificate->ssl_certificate().GetStats();
1195 }
1196 std::unique_ptr<rtc::SSLCertificate> remote_certificate =
1197 pc_->session()->GetRemoteSSLCertificate(
1198 transport_stats.second.transport_name);
1199 if (remote_certificate) {
1200 certificate_stats_pair.remote = remote_certificate->GetStats();
1201 }
1202 transport_cert_stats.insert(
1203 std::make_pair(transport_stats.second.transport_name,
1204 std::move(certificate_stats_pair)));
1205 }
1206 return transport_cert_stats;
1207}
1208
hbos84abeb12017-01-16 06:16:44 -08001209std::unique_ptr<TrackMediaInfoMap>
1210RTCStatsCollector::PrepareTrackMediaInfoMap_s() const {
hbosdf6075a2016-12-19 04:58:02 -08001211 RTC_DCHECK(signaling_thread_->IsCurrent());
hbos84abeb12017-01-16 06:16:44 -08001212 std::unique_ptr<cricket::VoiceMediaInfo> voice_media_info;
hbos0adb8282016-11-23 02:32:06 -08001213 if (pc_->session()->voice_channel()) {
hbos84abeb12017-01-16 06:16:44 -08001214 voice_media_info.reset(new cricket::VoiceMediaInfo());
1215 if (!pc_->session()->voice_channel()->GetStats(voice_media_info.get())) {
1216 voice_media_info.reset();
hbos0adb8282016-11-23 02:32:06 -08001217 }
1218 }
hbos84abeb12017-01-16 06:16:44 -08001219 std::unique_ptr<cricket::VideoMediaInfo> video_media_info;
hbos0adb8282016-11-23 02:32:06 -08001220 if (pc_->session()->video_channel()) {
hbos84abeb12017-01-16 06:16:44 -08001221 video_media_info.reset(new cricket::VideoMediaInfo());
1222 if (!pc_->session()->video_channel()->GetStats(video_media_info.get())) {
1223 video_media_info.reset();
hbos0adb8282016-11-23 02:32:06 -08001224 }
1225 }
hbos84abeb12017-01-16 06:16:44 -08001226 std::unique_ptr<TrackMediaInfoMap> track_media_info_map(
1227 new TrackMediaInfoMap(std::move(voice_media_info),
1228 std::move(video_media_info),
1229 pc_->GetSenders(),
1230 pc_->GetReceivers()));
1231 return track_media_info_map;
1232}
1233
1234std::map<MediaStreamTrackInterface*, std::string>
1235RTCStatsCollector::PrepareTrackToID_s() const {
1236 RTC_DCHECK(signaling_thread_->IsCurrent());
1237 std::map<MediaStreamTrackInterface*, std::string> track_to_id;
hbos7b0c6fa2017-07-12 16:22:34 -07001238 for (auto sender : pc_->GetSenders()) {
1239 auto track = sender->track();
1240 if (track)
1241 track_to_id[track.get()] = track->id();
1242 }
1243 for (auto receiver : pc_->GetReceivers()) {
1244 auto track = receiver->track();
1245 if (track)
1246 track_to_id[track.get()] = track->id();
hbos84abeb12017-01-16 06:16:44 -08001247 }
1248 return track_to_id;
hbos0adb8282016-11-23 02:32:06 -08001249}
1250
hbos82ebe022016-11-14 01:41:09 -08001251void RTCStatsCollector::OnDataChannelCreated(DataChannel* channel) {
1252 channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
1253 channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
1254}
1255
1256void RTCStatsCollector::OnDataChannelOpened(DataChannel* channel) {
1257 RTC_DCHECK(signaling_thread_->IsCurrent());
1258 bool result = internal_record_.opened_data_channels.insert(
1259 reinterpret_cast<uintptr_t>(channel)).second;
1260 ++internal_record_.data_channels_opened;
1261 RTC_DCHECK(result);
1262}
1263
1264void RTCStatsCollector::OnDataChannelClosed(DataChannel* channel) {
1265 RTC_DCHECK(signaling_thread_->IsCurrent());
1266 // Only channels that have been fully opened (and have increased the
1267 // |data_channels_opened_| counter) increase the closed counter.
hbos5bf9def2017-03-20 03:14:14 -07001268 if (internal_record_.opened_data_channels.erase(
1269 reinterpret_cast<uintptr_t>(channel))) {
hbos82ebe022016-11-14 01:41:09 -08001270 ++internal_record_.data_channels_closed;
1271 }
1272}
1273
hboscc555c52016-10-18 12:48:31 -07001274const char* CandidateTypeToRTCIceCandidateTypeForTesting(
1275 const std::string& type) {
1276 return CandidateTypeToRTCIceCandidateType(type);
1277}
1278
1279const char* DataStateToRTCDataChannelStateForTesting(
1280 DataChannelInterface::DataState state) {
1281 return DataStateToRTCDataChannelState(state);
1282}
1283
hbosd565b732016-08-30 14:04:35 -07001284} // namespace webrtc