blob: 5c506e47781db71f0a7c4fad1d94770258c65202 [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;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700427 audio_track_stats->total_samples_received =
428 voice_receiver_info.total_samples_received;
zsteine76bd3a2017-07-14 12:17:49 -0700429 audio_track_stats->total_samples_duration =
430 voice_receiver_info.total_output_duration;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700431 audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
hbos9e302742017-01-20 02:47:10 -0800432 return audio_track_stats;
433}
434
435std::unique_ptr<RTCMediaStreamTrackStats>
436ProduceMediaStreamTrackStatsFromVideoSenderInfo(
437 int64_t timestamp_us,
438 const VideoTrackInterface& video_track,
439 const cricket::VideoSenderInfo& video_sender_info) {
440 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
441 new RTCMediaStreamTrackStats(
442 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
443 true, MediaStreamTrackInterface::kVideoKind, video_track.id(),
444 video_sender_info.ssrc()),
445 timestamp_us,
446 RTCMediaStreamTrackKind::kVideo));
447 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
448 video_track, video_track_stats.get());
449 video_track_stats->remote_source = false;
450 video_track_stats->detached = false;
451 video_track_stats->frame_width = static_cast<uint32_t>(
452 video_sender_info.send_frame_width);
453 video_track_stats->frame_height = static_cast<uint32_t>(
454 video_sender_info.send_frame_height);
hbosfefe0762017-01-20 06:14:25 -0800455 // TODO(hbos): Will reduce this by frames dropped due to congestion control
456 // when available. crbug.com/659137
457 video_track_stats->frames_sent = video_sender_info.frames_encoded;
hbos9e302742017-01-20 02:47:10 -0800458 return video_track_stats;
459}
460
461std::unique_ptr<RTCMediaStreamTrackStats>
462ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
463 int64_t timestamp_us,
464 const VideoTrackInterface& video_track,
465 const cricket::VideoReceiverInfo& video_receiver_info) {
466 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
467 new RTCMediaStreamTrackStats(
468 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
469 false, MediaStreamTrackInterface::kVideoKind, video_track.id(),
470 video_receiver_info.ssrc()),
471 timestamp_us,
472 RTCMediaStreamTrackKind::kVideo));
473 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
474 video_track, video_track_stats.get());
475 video_track_stats->remote_source = true;
476 video_track_stats->detached = false;
477 if (video_receiver_info.frame_width > 0 &&
478 video_receiver_info.frame_height > 0) {
479 video_track_stats->frame_width = static_cast<uint32_t>(
480 video_receiver_info.frame_width);
481 video_track_stats->frame_height = static_cast<uint32_t>(
482 video_receiver_info.frame_height);
483 }
hbos42f6d2f2017-01-20 03:56:50 -0800484 video_track_stats->frames_received = video_receiver_info.frames_received;
hbosf64941f2017-01-20 07:39:09 -0800485 // TODO(hbos): When we support receiving simulcast, this should be the total
486 // number of frames correctly decoded, independent of which SSRC it was
487 // received from. Since we don't support that, this is correct and is the same
488 // value as "RTCInboundRTPStreamStats.framesDecoded". crbug.com/659137
489 video_track_stats->frames_decoded = video_receiver_info.frames_decoded;
hbos50cfe1f2017-01-23 07:21:55 -0800490 RTC_DCHECK_GE(video_receiver_info.frames_received,
491 video_receiver_info.frames_rendered);
492 video_track_stats->frames_dropped = video_receiver_info.frames_received -
493 video_receiver_info.frames_rendered;
hbos9e302742017-01-20 02:47:10 -0800494 return video_track_stats;
495}
496
hbos09bc1282016-11-08 06:29:22 -0800497void ProduceMediaStreamAndTrackStats(
498 int64_t timestamp_us,
hbos9e302742017-01-20 02:47:10 -0800499 const TrackMediaInfoMap& track_media_info_map,
hbos09bc1282016-11-08 06:29:22 -0800500 rtc::scoped_refptr<StreamCollectionInterface> streams,
501 bool is_local,
502 RTCStatsReport* report) {
503 // TODO(hbos): When "AddTrack" is implemented we should iterate tracks to
504 // find which streams exist, not iterate streams to find tracks.
505 // crbug.com/659137
506 // TODO(hbos): Return stats of detached tracks. We have to perform stats
507 // gathering at the time of detachment to get accurate stats and timestamps.
508 // crbug.com/659137
509 if (!streams)
510 return;
511 for (size_t i = 0; i < streams->count(); ++i) {
512 MediaStreamInterface* stream = streams->at(i);
513
514 std::unique_ptr<RTCMediaStreamStats> stream_stats(
hbos02d2a922016-12-21 01:29:05 -0800515 new RTCMediaStreamStats(
516 (is_local ? "RTCMediaStream_local_" : "RTCMediaStream_remote_") +
517 stream->label(), timestamp_us));
hbos09bc1282016-11-08 06:29:22 -0800518 stream_stats->stream_identifier = stream->label();
519 stream_stats->track_ids = std::vector<std::string>();
hbos9e302742017-01-20 02:47:10 -0800520 // The track stats are per-attachment to the connection. There can be one
521 // for receiving (remote) tracks and multiple attachments for sending
522 // (local) tracks.
523 if (is_local) {
524 // Local Audio Tracks
525 for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track :
526 stream->GetAudioTracks()) {
527 const std::vector<cricket::VoiceSenderInfo*>* voice_sender_infos =
528 track_media_info_map.GetVoiceSenderInfos(*audio_track);
529 if (!voice_sender_infos) {
530 continue;
hbos9a394f02016-12-14 07:58:22 -0800531 }
hbos9e302742017-01-20 02:47:10 -0800532 for (const auto& voice_sender_info : *voice_sender_infos) {
533 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
534 ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
535 timestamp_us, *audio_track, *voice_sender_info);
536 stream_stats->track_ids->push_back(audio_track_stats->id());
537 report->AddStats(std::move(audio_track_stats));
hbos9a394f02016-12-14 07:58:22 -0800538 }
hbos09bc1282016-11-08 06:29:22 -0800539 }
hbos9e302742017-01-20 02:47:10 -0800540 // Local Video Tracks
541 for (const rtc::scoped_refptr<VideoTrackInterface>& video_track :
542 stream->GetVideoTracks()) {
543 const std::vector<cricket::VideoSenderInfo*>* video_sender_infos =
544 track_media_info_map.GetVideoSenderInfos(*video_track);
545 if (!video_sender_infos) {
546 continue;
547 }
548 for (const auto& video_sender_info : *video_sender_infos) {
549 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
550 ProduceMediaStreamTrackStatsFromVideoSenderInfo(
551 timestamp_us, *video_track, *video_sender_info);
552 stream_stats->track_ids->push_back(video_track_stats->id());
553 report->AddStats(std::move(video_track_stats));
hbos09bc1282016-11-08 06:29:22 -0800554 }
555 }
hbos9e302742017-01-20 02:47:10 -0800556 } else {
557 // Remote Audio Tracks
558 for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track :
559 stream->GetAudioTracks()) {
560 const cricket::VoiceReceiverInfo* voice_receiver_info =
561 track_media_info_map.GetVoiceReceiverInfo(*audio_track);
562 if (!voice_receiver_info) {
563 continue;
564 }
565 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
566 ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
567 timestamp_us, *audio_track, *voice_receiver_info);
568 stream_stats->track_ids->push_back(audio_track_stats->id());
569 report->AddStats(std::move(audio_track_stats));
570 }
571 // Remote Video Tracks
572 for (const rtc::scoped_refptr<VideoTrackInterface>& video_track :
573 stream->GetVideoTracks()) {
574 const cricket::VideoReceiverInfo* video_receiver_info =
575 track_media_info_map.GetVideoReceiverInfo(*video_track);
576 if (!video_receiver_info) {
577 continue;
578 }
579 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
580 ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
581 timestamp_us, *video_track, *video_receiver_info);
582 stream_stats->track_ids->push_back(video_track_stats->id());
583 report->AddStats(std::move(video_track_stats));
584 }
hbos09bc1282016-11-08 06:29:22 -0800585 }
586 report->AddStats(std::move(stream_stats));
587 }
588}
589
hboscc555c52016-10-18 12:48:31 -0700590} // namespace
591
hbosc82f2e12016-09-05 01:36:50 -0700592rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
593 PeerConnection* pc, int64_t cache_lifetime_us) {
594 return rtc::scoped_refptr<RTCStatsCollector>(
595 new rtc::RefCountedObject<RTCStatsCollector>(pc, cache_lifetime_us));
596}
597
598RTCStatsCollector::RTCStatsCollector(PeerConnection* pc,
599 int64_t cache_lifetime_us)
hbosd565b732016-08-30 14:04:35 -0700600 : pc_(pc),
hbosc82f2e12016-09-05 01:36:50 -0700601 signaling_thread_(pc->session()->signaling_thread()),
602 worker_thread_(pc->session()->worker_thread()),
603 network_thread_(pc->session()->network_thread()),
604 num_pending_partial_reports_(0),
605 partial_report_timestamp_us_(0),
hbos0e6758d2016-08-31 07:57:36 -0700606 cache_timestamp_us_(0),
607 cache_lifetime_us_(cache_lifetime_us) {
hbosd565b732016-08-30 14:04:35 -0700608 RTC_DCHECK(pc_);
hbosc82f2e12016-09-05 01:36:50 -0700609 RTC_DCHECK(signaling_thread_);
610 RTC_DCHECK(worker_thread_);
611 RTC_DCHECK(network_thread_);
hbos0e6758d2016-08-31 07:57:36 -0700612 RTC_DCHECK_GE(cache_lifetime_us_, 0);
hbos82ebe022016-11-14 01:41:09 -0800613 pc_->SignalDataChannelCreated.connect(
614 this, &RTCStatsCollector::OnDataChannelCreated);
hbosd565b732016-08-30 14:04:35 -0700615}
616
hbosb78306a2016-12-19 05:06:57 -0800617RTCStatsCollector::~RTCStatsCollector() {
618 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
619}
620
hbosc82f2e12016-09-05 01:36:50 -0700621void RTCStatsCollector::GetStatsReport(
622 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
623 RTC_DCHECK(signaling_thread_->IsCurrent());
624 RTC_DCHECK(callback);
625 callbacks_.push_back(callback);
626
hbos0e6758d2016-08-31 07:57:36 -0700627 // "Now" using a monotonically increasing timer.
628 int64_t cache_now_us = rtc::TimeMicros();
629 if (cached_report_ &&
630 cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) {
hbosc82f2e12016-09-05 01:36:50 -0700631 // We have a fresh cached report to deliver.
632 DeliverCachedReport();
633 } else if (!num_pending_partial_reports_) {
634 // Only start gathering stats if we're not already gathering stats. In the
635 // case of already gathering stats, |callback_| will be invoked when there
636 // are no more pending partial reports.
637
638 // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
639 // UTC), in microseconds. The system clock could be modified and is not
640 // necessarily monotonically increasing.
nissecdf37a92016-09-13 23:41:47 -0700641 int64_t timestamp_us = rtc::TimeUTCMicros();
hbosc82f2e12016-09-05 01:36:50 -0700642
hbosf415f8a2017-01-02 04:28:51 -0800643 num_pending_partial_reports_ = 2;
hbosc82f2e12016-09-05 01:36:50 -0700644 partial_report_timestamp_us_ = cache_now_us;
hbosdf6075a2016-12-19 04:58:02 -0800645
hbos84abeb12017-01-16 06:16:44 -0800646 // Prepare |channel_name_pairs_| for use in
hbosdf6075a2016-12-19 04:58:02 -0800647 // |ProducePartialResultsOnNetworkThread|.
648 channel_name_pairs_.reset(new ChannelNamePairs());
649 if (pc_->session()->voice_channel()) {
650 channel_name_pairs_->voice = rtc::Optional<ChannelNamePair>(
651 ChannelNamePair(pc_->session()->voice_channel()->content_name(),
652 pc_->session()->voice_channel()->transport_name()));
653 }
654 if (pc_->session()->video_channel()) {
655 channel_name_pairs_->video = rtc::Optional<ChannelNamePair>(
656 ChannelNamePair(pc_->session()->video_channel()->content_name(),
657 pc_->session()->video_channel()->transport_name()));
658 }
deadbeef953c2ce2017-01-09 14:53:41 -0800659 if (pc_->session()->rtp_data_channel()) {
660 channel_name_pairs_->data =
661 rtc::Optional<ChannelNamePair>(ChannelNamePair(
662 pc_->session()->rtp_data_channel()->content_name(),
663 pc_->session()->rtp_data_channel()->transport_name()));
664 }
665 if (pc_->session()->sctp_content_name()) {
hbosdf6075a2016-12-19 04:58:02 -0800666 channel_name_pairs_->data = rtc::Optional<ChannelNamePair>(
deadbeef953c2ce2017-01-09 14:53:41 -0800667 ChannelNamePair(*pc_->session()->sctp_content_name(),
668 *pc_->session()->sctp_transport_name()));
hbosdf6075a2016-12-19 04:58:02 -0800669 }
hbos84abeb12017-01-16 06:16:44 -0800670 // Prepare |track_media_info_map_| for use in
671 // |ProducePartialResultsOnNetworkThread| and
672 // |ProducePartialResultsOnSignalingThread|.
673 track_media_info_map_.reset(PrepareTrackMediaInfoMap_s().release());
674 // Prepare |track_to_id_| for use in |ProducePartialResultsOnNetworkThread|.
675 // This avoids a possible deadlock if |MediaStreamTrackInterface::id| is
676 // implemented to invoke on the signaling thread.
677 track_to_id_ = PrepareTrackToID_s();
hbosf415f8a2017-01-02 04:28:51 -0800678
stefanf79ade12017-06-02 06:44:03 -0700679 // Prepare |call_stats_| here since GetCallStats() will hop to the worker
680 // thread.
681 // TODO(holmer): To avoid the hop we could move BWE and BWE stats to the
682 // network thread, where it more naturally belongs.
683 call_stats_ = pc_->session()->GetCallStats();
684
685 invoker_.AsyncInvoke<void>(
686 RTC_FROM_HERE, network_thread_,
hbosc82f2e12016-09-05 01:36:50 -0700687 rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread,
stefanf79ade12017-06-02 06:44:03 -0700688 rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us));
hbosf415f8a2017-01-02 04:28:51 -0800689 ProducePartialResultsOnSignalingThread(timestamp_us);
hbos0e6758d2016-08-31 07:57:36 -0700690 }
hbosd565b732016-08-30 14:04:35 -0700691}
692
693void RTCStatsCollector::ClearCachedStatsReport() {
hbosc82f2e12016-09-05 01:36:50 -0700694 RTC_DCHECK(signaling_thread_->IsCurrent());
hbosd565b732016-08-30 14:04:35 -0700695 cached_report_ = nullptr;
696}
697
hbosb78306a2016-12-19 05:06:57 -0800698void RTCStatsCollector::WaitForPendingRequest() {
699 RTC_DCHECK(signaling_thread_->IsCurrent());
700 if (num_pending_partial_reports_) {
701 rtc::Thread::Current()->ProcessMessages(0);
702 while (num_pending_partial_reports_) {
703 rtc::Thread::Current()->SleepMs(1);
704 rtc::Thread::Current()->ProcessMessages(0);
705 }
706 }
707}
708
hbosc82f2e12016-09-05 01:36:50 -0700709void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
710 int64_t timestamp_us) {
711 RTC_DCHECK(signaling_thread_->IsCurrent());
hbos6ded1902016-11-01 01:50:46 -0700712 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(
713 timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -0700714
hboscc555c52016-10-18 12:48:31 -0700715 ProduceDataChannelStats_s(timestamp_us, report.get());
hbos09bc1282016-11-08 06:29:22 -0800716 ProduceMediaStreamAndTrackStats_s(timestamp_us, report.get());
hbos6ab97ce2016-10-03 14:16:56 -0700717 ProducePeerConnectionStats_s(timestamp_us, report.get());
hbosc82f2e12016-09-05 01:36:50 -0700718
719 AddPartialResults(report);
720}
721
hbosc82f2e12016-09-05 01:36:50 -0700722void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
723 int64_t timestamp_us) {
724 RTC_DCHECK(network_thread_->IsCurrent());
hbos6ded1902016-11-01 01:50:46 -0700725 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(
726 timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -0700727
hbosdf6075a2016-12-19 04:58:02 -0800728 std::unique_ptr<SessionStats> session_stats =
729 pc_->session()->GetStats(*channel_name_pairs_);
730 if (session_stats) {
731 std::map<std::string, CertificateStatsPair> transport_cert_stats =
732 PrepareTransportCertificateStats_n(*session_stats);
733
734 ProduceCertificateStats_n(
735 timestamp_us, transport_cert_stats, report.get());
736 ProduceCodecStats_n(
hbos84abeb12017-01-16 06:16:44 -0800737 timestamp_us, *track_media_info_map_, report.get());
stefanf79ade12017-06-02 06:44:03 -0700738 ProduceIceCandidateAndPairStats_n(timestamp_us, *session_stats,
739 track_media_info_map_->video_media_info(),
740 call_stats_, report.get());
hbosdf6075a2016-12-19 04:58:02 -0800741 ProduceRTPStreamStats_n(
hbos84abeb12017-01-16 06:16:44 -0800742 timestamp_us, *session_stats, *track_media_info_map_, report.get());
hbosdf6075a2016-12-19 04:58:02 -0800743 ProduceTransportStats_n(
744 timestamp_us, *session_stats, transport_cert_stats, report.get());
745 }
hbosc82f2e12016-09-05 01:36:50 -0700746
747 AddPartialResults(report);
748}
749
750void RTCStatsCollector::AddPartialResults(
751 const rtc::scoped_refptr<RTCStatsReport>& partial_report) {
752 if (!signaling_thread_->IsCurrent()) {
753 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
754 rtc::Bind(&RTCStatsCollector::AddPartialResults_s,
755 rtc::scoped_refptr<RTCStatsCollector>(this),
756 partial_report));
757 return;
758 }
759 AddPartialResults_s(partial_report);
760}
761
762void RTCStatsCollector::AddPartialResults_s(
763 rtc::scoped_refptr<RTCStatsReport> partial_report) {
764 RTC_DCHECK(signaling_thread_->IsCurrent());
765 RTC_DCHECK_GT(num_pending_partial_reports_, 0);
766 if (!partial_report_)
767 partial_report_ = partial_report;
768 else
769 partial_report_->TakeMembersFrom(partial_report);
770 --num_pending_partial_reports_;
771 if (!num_pending_partial_reports_) {
772 cache_timestamp_us_ = partial_report_timestamp_us_;
773 cached_report_ = partial_report_;
774 partial_report_ = nullptr;
hbos84abeb12017-01-16 06:16:44 -0800775 channel_name_pairs_.reset();
776 track_media_info_map_.reset();
777 track_to_id_.clear();
ehmaldonadoa26196b2017-07-18 03:30:29 -0700778 // Trace WebRTC Stats when getStats is called on Javascript.
779 // This allows access to WebRTC stats from trace logs. To enable them,
780 // select the "webrtc_stats" category when recording traces.
mbonadei3439c892017-08-14 23:48:03 -0700781 for (const RTCStats& stats : *cached_report_) {
782 for (const RTCStatsMemberInterface* member : stats.Members()) {
783 if (member->is_defined()) {
784 TRACE_EVENT_INSTANT2("webrtc_stats", "webrtc_stats",
785 "value", member->ValueToString(),
786 "type.name.id", GetStatTypeMemberNameAndId(
787 stats, member));
788 }
789 }
790 }
hbosc82f2e12016-09-05 01:36:50 -0700791 DeliverCachedReport();
792 }
793}
794
795void RTCStatsCollector::DeliverCachedReport() {
796 RTC_DCHECK(signaling_thread_->IsCurrent());
797 RTC_DCHECK(!callbacks_.empty());
798 RTC_DCHECK(cached_report_);
799 for (const rtc::scoped_refptr<RTCStatsCollectorCallback>& callback :
800 callbacks_) {
801 callback->OnStatsDelivered(cached_report_);
802 }
803 callbacks_.clear();
hbosd565b732016-08-30 14:04:35 -0700804}
805
hbosdf6075a2016-12-19 04:58:02 -0800806void RTCStatsCollector::ProduceCertificateStats_n(
hbos2fa7c672016-10-24 04:00:05 -0700807 int64_t timestamp_us,
808 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
hbos6ab97ce2016-10-03 14:16:56 -0700809 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800810 RTC_DCHECK(network_thread_->IsCurrent());
hbos02ba2112016-10-28 05:14:53 -0700811 for (const auto& transport_cert_stats_pair : transport_cert_stats) {
812 if (transport_cert_stats_pair.second.local) {
813 ProduceCertificateStatsFromSSLCertificateStats(
814 timestamp_us, *transport_cert_stats_pair.second.local.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -0700815 }
hbos02ba2112016-10-28 05:14:53 -0700816 if (transport_cert_stats_pair.second.remote) {
817 ProduceCertificateStatsFromSSLCertificateStats(
818 timestamp_us, *transport_cert_stats_pair.second.remote.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -0700819 }
820 }
821}
822
hbosdf6075a2016-12-19 04:58:02 -0800823void RTCStatsCollector::ProduceCodecStats_n(
hbos84abeb12017-01-16 06:16:44 -0800824 int64_t timestamp_us, const TrackMediaInfoMap& track_media_info_map,
hbos0adb8282016-11-23 02:32:06 -0800825 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800826 RTC_DCHECK(network_thread_->IsCurrent());
hbos0adb8282016-11-23 02:32:06 -0800827 // Audio
hbos84abeb12017-01-16 06:16:44 -0800828 if (track_media_info_map.voice_media_info()) {
hbos0adb8282016-11-23 02:32:06 -0800829 // Inbound
hbos84abeb12017-01-16 06:16:44 -0800830 for (const auto& pair :
831 track_media_info_map.voice_media_info()->receive_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800832 report->AddStats(CodecStatsFromRtpCodecParameters(
833 timestamp_us, true, true, pair.second));
834 }
835 // Outbound
hbos84abeb12017-01-16 06:16:44 -0800836 for (const auto& pair :
837 track_media_info_map.voice_media_info()->send_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800838 report->AddStats(CodecStatsFromRtpCodecParameters(
839 timestamp_us, false, true, pair.second));
840 }
841 }
842 // Video
hbos84abeb12017-01-16 06:16:44 -0800843 if (track_media_info_map.video_media_info()) {
hbos0adb8282016-11-23 02:32:06 -0800844 // Inbound
hbos84abeb12017-01-16 06:16:44 -0800845 for (const auto& pair :
846 track_media_info_map.video_media_info()->receive_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800847 report->AddStats(CodecStatsFromRtpCodecParameters(
848 timestamp_us, true, false, pair.second));
849 }
850 // Outbound
hbos84abeb12017-01-16 06:16:44 -0800851 for (const auto& pair :
852 track_media_info_map.video_media_info()->send_codecs) {
hbos0adb8282016-11-23 02:32:06 -0800853 report->AddStats(CodecStatsFromRtpCodecParameters(
854 timestamp_us, false, false, pair.second));
855 }
856 }
857}
858
hboscc555c52016-10-18 12:48:31 -0700859void RTCStatsCollector::ProduceDataChannelStats_s(
860 int64_t timestamp_us, RTCStatsReport* report) const {
861 RTC_DCHECK(signaling_thread_->IsCurrent());
862 for (const rtc::scoped_refptr<DataChannel>& data_channel :
863 pc_->sctp_data_channels()) {
864 std::unique_ptr<RTCDataChannelStats> data_channel_stats(
865 new RTCDataChannelStats(
866 "RTCDataChannel_" + rtc::ToString<>(data_channel->id()),
867 timestamp_us));
868 data_channel_stats->label = data_channel->label();
869 data_channel_stats->protocol = data_channel->protocol();
870 data_channel_stats->datachannelid = data_channel->id();
871 data_channel_stats->state =
872 DataStateToRTCDataChannelState(data_channel->state());
873 data_channel_stats->messages_sent = data_channel->messages_sent();
874 data_channel_stats->bytes_sent = data_channel->bytes_sent();
875 data_channel_stats->messages_received = data_channel->messages_received();
876 data_channel_stats->bytes_received = data_channel->bytes_received();
877 report->AddStats(std::move(data_channel_stats));
878 }
879}
880
hbosdf6075a2016-12-19 04:58:02 -0800881void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
stefanf79ade12017-06-02 06:44:03 -0700882 int64_t timestamp_us,
883 const SessionStats& session_stats,
884 const cricket::VideoMediaInfo* video_media_info,
885 const Call::Stats& call_stats,
886 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800887 RTC_DCHECK(network_thread_->IsCurrent());
hbosc47a0c32016-10-11 14:54:49 -0700888 for (const auto& transport_stats : session_stats.transport_stats) {
889 for (const auto& channel_stats : transport_stats.second.channel_stats) {
hbos0583b282016-11-30 01:50:14 -0800890 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
891 transport_stats.second.transport_name, channel_stats.component);
hbosc47a0c32016-10-11 14:54:49 -0700892 for (const cricket::ConnectionInfo& info :
893 channel_stats.connection_infos) {
hbosc47a0c32016-10-11 14:54:49 -0700894 std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
hbos2fa7c672016-10-24 04:00:05 -0700895 new RTCIceCandidatePairStats(
896 RTCIceCandidatePairStatsIDFromConnectionInfo(info),
897 timestamp_us));
hbosc47a0c32016-10-11 14:54:49 -0700898
hbos0583b282016-11-30 01:50:14 -0800899 candidate_pair_stats->transport_id = transport_id;
hbosab9f6e42016-10-07 02:18:47 -0700900 // TODO(hbos): There could be other candidates that are not paired with
901 // anything. We don't have a complete list. Local candidates come from
902 // Port objects, and prflx candidates (both local and remote) are only
903 // stored in candidate pairs. crbug.com/632723
hbos02ba2112016-10-28 05:14:53 -0700904 candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -0800905 timestamp_us, info.local_candidate, true, transport_id, report);
hbos02ba2112016-10-28 05:14:53 -0700906 candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -0800907 timestamp_us, info.remote_candidate, false, transport_id, report);
hbos06495bc2017-01-02 08:08:18 -0800908 candidate_pair_stats->state =
909 IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
910 candidate_pair_stats->priority = info.priority;
hbos92eaec62017-02-27 01:38:08 -0800911 candidate_pair_stats->nominated = info.nominated;
hbosc47a0c32016-10-11 14:54:49 -0700912 // TODO(hbos): This writable is different than the spec. It goes to
913 // false after a certain amount of time without a response passes.
914 // crbug.com/633550
915 candidate_pair_stats->writable = info.writable;
hbosc47a0c32016-10-11 14:54:49 -0700916 candidate_pair_stats->bytes_sent =
917 static_cast<uint64_t>(info.sent_total_bytes);
918 candidate_pair_stats->bytes_received =
919 static_cast<uint64_t>(info.recv_total_bytes);
hbosbf8d3e52017-02-28 06:34:47 -0800920 candidate_pair_stats->total_round_trip_time =
921 static_cast<double>(info.total_round_trip_time_ms) /
922 rtc::kNumMillisecsPerSec;
923 if (info.current_round_trip_time_ms) {
924 candidate_pair_stats->current_round_trip_time =
925 static_cast<double>(*info.current_round_trip_time_ms) /
926 rtc::kNumMillisecsPerSec;
927 }
stefanf79ade12017-06-02 06:44:03 -0700928 if (info.best_connection) {
hbos338f78a2017-02-07 06:41:21 -0800929 // The bandwidth estimations we have are for the selected candidate
930 // pair ("info.best_connection").
stefanf79ade12017-06-02 06:44:03 -0700931 RTC_DCHECK_GE(call_stats.send_bandwidth_bps, 0);
932 RTC_DCHECK_GE(call_stats.recv_bandwidth_bps, 0);
933 if (call_stats.send_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -0800934 candidate_pair_stats->available_outgoing_bitrate =
stefanf79ade12017-06-02 06:44:03 -0700935 static_cast<double>(call_stats.send_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -0800936 }
stefanf79ade12017-06-02 06:44:03 -0700937 if (call_stats.recv_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -0800938 candidate_pair_stats->available_incoming_bitrate =
stefanf79ade12017-06-02 06:44:03 -0700939 static_cast<double>(call_stats.recv_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -0800940 }
941 }
hbosd82f5122016-12-09 04:12:39 -0800942 candidate_pair_stats->requests_received =
943 static_cast<uint64_t>(info.recv_ping_requests);
hbose448dd52016-12-12 01:22:53 -0800944 candidate_pair_stats->requests_sent = static_cast<uint64_t>(
945 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -0700946 candidate_pair_stats->responses_received =
947 static_cast<uint64_t>(info.recv_ping_responses);
948 candidate_pair_stats->responses_sent =
949 static_cast<uint64_t>(info.sent_ping_responses);
hbose448dd52016-12-12 01:22:53 -0800950 RTC_DCHECK_GE(info.sent_ping_requests_total,
951 info.sent_ping_requests_before_first_response);
952 candidate_pair_stats->consent_requests_sent = static_cast<uint64_t>(
953 info.sent_ping_requests_total -
954 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -0700955
956 report->AddStats(std::move(candidate_pair_stats));
hbosab9f6e42016-10-07 02:18:47 -0700957 }
958 }
959 }
960}
961
hbos09bc1282016-11-08 06:29:22 -0800962void RTCStatsCollector::ProduceMediaStreamAndTrackStats_s(
963 int64_t timestamp_us, RTCStatsReport* report) const {
964 RTC_DCHECK(signaling_thread_->IsCurrent());
hbos9e302742017-01-20 02:47:10 -0800965 RTC_DCHECK(track_media_info_map_);
966 ProduceMediaStreamAndTrackStats(timestamp_us,
967 *track_media_info_map_,
968 pc_->local_streams(),
969 true,
970 report);
971 ProduceMediaStreamAndTrackStats(timestamp_us,
972 *track_media_info_map_,
973 pc_->remote_streams(),
974 false,
975 report);
hbos09bc1282016-11-08 06:29:22 -0800976}
977
hbos6ab97ce2016-10-03 14:16:56 -0700978void RTCStatsCollector::ProducePeerConnectionStats_s(
979 int64_t timestamp_us, RTCStatsReport* report) const {
hbosc82f2e12016-09-05 01:36:50 -0700980 RTC_DCHECK(signaling_thread_->IsCurrent());
hbosd565b732016-08-30 14:04:35 -0700981 std::unique_ptr<RTCPeerConnectionStats> stats(
hbos0e6758d2016-08-31 07:57:36 -0700982 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us));
hbos82ebe022016-11-14 01:41:09 -0800983 stats->data_channels_opened = internal_record_.data_channels_opened;
984 stats->data_channels_closed = internal_record_.data_channels_closed;
hbos6ab97ce2016-10-03 14:16:56 -0700985 report->AddStats(std::move(stats));
hbosd565b732016-08-30 14:04:35 -0700986}
987
hbosdf6075a2016-12-19 04:58:02 -0800988void RTCStatsCollector::ProduceRTPStreamStats_n(
hbos6ded1902016-11-01 01:50:46 -0700989 int64_t timestamp_us, const SessionStats& session_stats,
hbos84abeb12017-01-16 06:16:44 -0800990 const TrackMediaInfoMap& track_media_info_map,
991 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -0800992 RTC_DCHECK(network_thread_->IsCurrent());
hbos6ded1902016-11-01 01:50:46 -0700993
994 // Audio
hbos84abeb12017-01-16 06:16:44 -0800995 if (track_media_info_map.voice_media_info()) {
hbos0adb8282016-11-23 02:32:06 -0800996 std::string transport_id = RTCTransportStatsIDFromBaseChannel(
997 session_stats.proxy_to_transport, *pc_->session()->voice_channel());
998 RTC_DCHECK(!transport_id.empty());
999 // Inbound
1000 for (const cricket::VoiceReceiverInfo& voice_receiver_info :
hbos84abeb12017-01-16 06:16:44 -08001001 track_media_info_map.voice_media_info()->receivers) {
hbos0adb8282016-11-23 02:32:06 -08001002 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1003 // is fixed.
1004 if (voice_receiver_info.ssrc() == 0)
1005 continue;
1006 std::unique_ptr<RTCInboundRTPStreamStats> inbound_audio(
1007 new RTCInboundRTPStreamStats(
1008 RTCInboundRTPStreamStatsIDFromSSRC(
1009 true, voice_receiver_info.ssrc()),
1010 timestamp_us));
1011 SetInboundRTPStreamStatsFromVoiceReceiverInfo(
1012 voice_receiver_info, inbound_audio.get());
hbos84abeb12017-01-16 06:16:44 -08001013 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1014 track_media_info_map_->GetAudioTrack(voice_receiver_info);
1015 if (audio_track) {
1016 RTC_DCHECK(track_to_id_.find(audio_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001017 inbound_audio->track_id =
hbos9e302742017-01-20 02:47:10 -08001018 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1019 false,
1020 MediaStreamTrackInterface::kAudioKind,
1021 track_to_id_.find(audio_track.get())->second,
1022 voice_receiver_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001023 }
hbos0adb8282016-11-23 02:32:06 -08001024 inbound_audio->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001025 report->AddStats(std::move(inbound_audio));
1026 }
1027 // Outbound
1028 for (const cricket::VoiceSenderInfo& voice_sender_info :
hbos84abeb12017-01-16 06:16:44 -08001029 track_media_info_map.voice_media_info()->senders) {
hbos0adb8282016-11-23 02:32:06 -08001030 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1031 // is fixed.
1032 if (voice_sender_info.ssrc() == 0)
1033 continue;
1034 std::unique_ptr<RTCOutboundRTPStreamStats> outbound_audio(
1035 new RTCOutboundRTPStreamStats(
1036 RTCOutboundRTPStreamStatsIDFromSSRC(
1037 true, voice_sender_info.ssrc()),
1038 timestamp_us));
1039 SetOutboundRTPStreamStatsFromVoiceSenderInfo(
1040 voice_sender_info, outbound_audio.get());
hbos84abeb12017-01-16 06:16:44 -08001041 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1042 track_media_info_map_->GetAudioTrack(voice_sender_info);
1043 if (audio_track) {
1044 RTC_DCHECK(track_to_id_.find(audio_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001045 outbound_audio->track_id =
hbos9e302742017-01-20 02:47:10 -08001046 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1047 true,
1048 MediaStreamTrackInterface::kAudioKind,
1049 track_to_id_.find(audio_track.get())->second,
1050 voice_sender_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001051 }
hbos0adb8282016-11-23 02:32:06 -08001052 outbound_audio->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001053 report->AddStats(std::move(outbound_audio));
hbos6ded1902016-11-01 01:50:46 -07001054 }
1055 }
1056 // Video
hbos84abeb12017-01-16 06:16:44 -08001057 if (track_media_info_map.video_media_info()) {
hbos0adb8282016-11-23 02:32:06 -08001058 std::string transport_id = RTCTransportStatsIDFromBaseChannel(
1059 session_stats.proxy_to_transport, *pc_->session()->video_channel());
1060 RTC_DCHECK(!transport_id.empty());
1061 // Inbound
1062 for (const cricket::VideoReceiverInfo& video_receiver_info :
hbos84abeb12017-01-16 06:16:44 -08001063 track_media_info_map.video_media_info()->receivers) {
hbos0adb8282016-11-23 02:32:06 -08001064 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1065 // is fixed.
1066 if (video_receiver_info.ssrc() == 0)
1067 continue;
1068 std::unique_ptr<RTCInboundRTPStreamStats> inbound_video(
1069 new RTCInboundRTPStreamStats(
1070 RTCInboundRTPStreamStatsIDFromSSRC(
1071 false, video_receiver_info.ssrc()),
1072 timestamp_us));
1073 SetInboundRTPStreamStatsFromVideoReceiverInfo(
1074 video_receiver_info, inbound_video.get());
hbos84abeb12017-01-16 06:16:44 -08001075 rtc::scoped_refptr<VideoTrackInterface> video_track =
1076 track_media_info_map_->GetVideoTrack(video_receiver_info);
1077 if (video_track) {
1078 RTC_DCHECK(track_to_id_.find(video_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001079 inbound_video->track_id =
hbos9e302742017-01-20 02:47:10 -08001080 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1081 false,
1082 MediaStreamTrackInterface::kVideoKind,
1083 track_to_id_.find(video_track.get())->second,
1084 video_receiver_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001085 }
hbos0adb8282016-11-23 02:32:06 -08001086 inbound_video->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001087 report->AddStats(std::move(inbound_video));
1088 }
1089 // Outbound
1090 for (const cricket::VideoSenderInfo& video_sender_info :
hbos84abeb12017-01-16 06:16:44 -08001091 track_media_info_map.video_media_info()->senders) {
hbos0adb8282016-11-23 02:32:06 -08001092 // TODO(nisse): SSRC == 0 currently means none. Delete check when that
1093 // is fixed.
1094 if (video_sender_info.ssrc() == 0)
1095 continue;
1096 std::unique_ptr<RTCOutboundRTPStreamStats> outbound_video(
1097 new RTCOutboundRTPStreamStats(
1098 RTCOutboundRTPStreamStatsIDFromSSRC(
1099 false, video_sender_info.ssrc()),
1100 timestamp_us));
1101 SetOutboundRTPStreamStatsFromVideoSenderInfo(
1102 video_sender_info, outbound_video.get());
hbos84abeb12017-01-16 06:16:44 -08001103 rtc::scoped_refptr<VideoTrackInterface> video_track =
1104 track_media_info_map_->GetVideoTrack(video_sender_info);
1105 if (video_track) {
1106 RTC_DCHECK(track_to_id_.find(video_track.get()) != track_to_id_.end());
hbosb0ae9202017-01-27 06:35:16 -08001107 outbound_video->track_id =
hbos9e302742017-01-20 02:47:10 -08001108 RTCMediaStreamTrackStatsIDFromTrackKindIDAndSsrc(
1109 true,
1110 MediaStreamTrackInterface::kVideoKind,
1111 track_to_id_.find(video_track.get())->second,
1112 video_sender_info.ssrc());
hbos84abeb12017-01-16 06:16:44 -08001113 }
hbos0adb8282016-11-23 02:32:06 -08001114 outbound_video->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -08001115 report->AddStats(std::move(outbound_video));
hbos6ded1902016-11-01 01:50:46 -07001116 }
1117 }
1118}
1119
hbosdf6075a2016-12-19 04:58:02 -08001120void RTCStatsCollector::ProduceTransportStats_n(
hbos2fa7c672016-10-24 04:00:05 -07001121 int64_t timestamp_us, const SessionStats& session_stats,
1122 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1123 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -08001124 RTC_DCHECK(network_thread_->IsCurrent());
hbos2fa7c672016-10-24 04:00:05 -07001125 for (const auto& transport : session_stats.transport_stats) {
1126 // Get reference to RTCP channel, if it exists.
1127 std::string rtcp_transport_stats_id;
1128 for (const auto& channel_stats : transport.second.channel_stats) {
1129 if (channel_stats.component ==
1130 cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
1131 rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel(
1132 transport.second.transport_name, channel_stats.component);
1133 break;
1134 }
1135 }
1136
1137 // Get reference to local and remote certificates of this transport, if they
1138 // exist.
1139 const auto& certificate_stats_it = transport_cert_stats.find(
1140 transport.second.transport_name);
1141 RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());
1142 std::string local_certificate_id;
1143 if (certificate_stats_it->second.local) {
1144 local_certificate_id = RTCCertificateIDFromFingerprint(
1145 certificate_stats_it->second.local->fingerprint);
1146 }
1147 std::string remote_certificate_id;
1148 if (certificate_stats_it->second.remote) {
1149 remote_certificate_id = RTCCertificateIDFromFingerprint(
1150 certificate_stats_it->second.remote->fingerprint);
1151 }
1152
1153 // There is one transport stats for each channel.
1154 for (const auto& channel_stats : transport.second.channel_stats) {
1155 std::unique_ptr<RTCTransportStats> transport_stats(
1156 new RTCTransportStats(
1157 RTCTransportStatsIDFromTransportChannel(
1158 transport.second.transport_name, channel_stats.component),
1159 timestamp_us));
1160 transport_stats->bytes_sent = 0;
1161 transport_stats->bytes_received = 0;
hbos7064d592017-01-16 07:38:02 -08001162 transport_stats->dtls_state = DtlsTransportStateToRTCDtlsTransportState(
1163 channel_stats.dtls_state);
hbos2fa7c672016-10-24 04:00:05 -07001164 for (const cricket::ConnectionInfo& info :
1165 channel_stats.connection_infos) {
1166 *transport_stats->bytes_sent += info.sent_total_bytes;
1167 *transport_stats->bytes_received += info.recv_total_bytes;
1168 if (info.best_connection) {
hbos2fa7c672016-10-24 04:00:05 -07001169 transport_stats->selected_candidate_pair_id =
1170 RTCIceCandidatePairStatsIDFromConnectionInfo(info);
1171 }
1172 }
1173 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
1174 !rtcp_transport_stats_id.empty()) {
1175 transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id;
1176 }
1177 if (!local_certificate_id.empty())
1178 transport_stats->local_certificate_id = local_certificate_id;
1179 if (!remote_certificate_id.empty())
1180 transport_stats->remote_certificate_id = remote_certificate_id;
1181 report->AddStats(std::move(transport_stats));
1182 }
1183 }
1184}
1185
1186std::map<std::string, RTCStatsCollector::CertificateStatsPair>
hbosdf6075a2016-12-19 04:58:02 -08001187RTCStatsCollector::PrepareTransportCertificateStats_n(
hbos2fa7c672016-10-24 04:00:05 -07001188 const SessionStats& session_stats) const {
hbosdf6075a2016-12-19 04:58:02 -08001189 RTC_DCHECK(network_thread_->IsCurrent());
hbos2fa7c672016-10-24 04:00:05 -07001190 std::map<std::string, CertificateStatsPair> transport_cert_stats;
1191 for (const auto& transport_stats : session_stats.transport_stats) {
1192 CertificateStatsPair certificate_stats_pair;
1193 rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
1194 if (pc_->session()->GetLocalCertificate(
1195 transport_stats.second.transport_name, &local_certificate)) {
1196 certificate_stats_pair.local =
1197 local_certificate->ssl_certificate().GetStats();
1198 }
1199 std::unique_ptr<rtc::SSLCertificate> remote_certificate =
1200 pc_->session()->GetRemoteSSLCertificate(
1201 transport_stats.second.transport_name);
1202 if (remote_certificate) {
1203 certificate_stats_pair.remote = remote_certificate->GetStats();
1204 }
1205 transport_cert_stats.insert(
1206 std::make_pair(transport_stats.second.transport_name,
1207 std::move(certificate_stats_pair)));
1208 }
1209 return transport_cert_stats;
1210}
1211
hbos84abeb12017-01-16 06:16:44 -08001212std::unique_ptr<TrackMediaInfoMap>
1213RTCStatsCollector::PrepareTrackMediaInfoMap_s() const {
hbosdf6075a2016-12-19 04:58:02 -08001214 RTC_DCHECK(signaling_thread_->IsCurrent());
hbos84abeb12017-01-16 06:16:44 -08001215 std::unique_ptr<cricket::VoiceMediaInfo> voice_media_info;
hbos0adb8282016-11-23 02:32:06 -08001216 if (pc_->session()->voice_channel()) {
hbos84abeb12017-01-16 06:16:44 -08001217 voice_media_info.reset(new cricket::VoiceMediaInfo());
1218 if (!pc_->session()->voice_channel()->GetStats(voice_media_info.get())) {
1219 voice_media_info.reset();
hbos0adb8282016-11-23 02:32:06 -08001220 }
1221 }
hbos84abeb12017-01-16 06:16:44 -08001222 std::unique_ptr<cricket::VideoMediaInfo> video_media_info;
hbos0adb8282016-11-23 02:32:06 -08001223 if (pc_->session()->video_channel()) {
hbos84abeb12017-01-16 06:16:44 -08001224 video_media_info.reset(new cricket::VideoMediaInfo());
1225 if (!pc_->session()->video_channel()->GetStats(video_media_info.get())) {
1226 video_media_info.reset();
hbos0adb8282016-11-23 02:32:06 -08001227 }
1228 }
hbos84abeb12017-01-16 06:16:44 -08001229 std::unique_ptr<TrackMediaInfoMap> track_media_info_map(
1230 new TrackMediaInfoMap(std::move(voice_media_info),
1231 std::move(video_media_info),
1232 pc_->GetSenders(),
1233 pc_->GetReceivers()));
1234 return track_media_info_map;
1235}
1236
1237std::map<MediaStreamTrackInterface*, std::string>
1238RTCStatsCollector::PrepareTrackToID_s() const {
1239 RTC_DCHECK(signaling_thread_->IsCurrent());
1240 std::map<MediaStreamTrackInterface*, std::string> track_to_id;
hbos7b0c6fa2017-07-12 16:22:34 -07001241 for (auto sender : pc_->GetSenders()) {
1242 auto track = sender->track();
1243 if (track)
1244 track_to_id[track.get()] = track->id();
1245 }
1246 for (auto receiver : pc_->GetReceivers()) {
1247 auto track = receiver->track();
1248 if (track)
1249 track_to_id[track.get()] = track->id();
hbos84abeb12017-01-16 06:16:44 -08001250 }
1251 return track_to_id;
hbos0adb8282016-11-23 02:32:06 -08001252}
1253
hbos82ebe022016-11-14 01:41:09 -08001254void RTCStatsCollector::OnDataChannelCreated(DataChannel* channel) {
1255 channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
1256 channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
1257}
1258
1259void RTCStatsCollector::OnDataChannelOpened(DataChannel* channel) {
1260 RTC_DCHECK(signaling_thread_->IsCurrent());
1261 bool result = internal_record_.opened_data_channels.insert(
1262 reinterpret_cast<uintptr_t>(channel)).second;
1263 ++internal_record_.data_channels_opened;
1264 RTC_DCHECK(result);
1265}
1266
1267void RTCStatsCollector::OnDataChannelClosed(DataChannel* channel) {
1268 RTC_DCHECK(signaling_thread_->IsCurrent());
1269 // Only channels that have been fully opened (and have increased the
1270 // |data_channels_opened_| counter) increase the closed counter.
hbos5bf9def2017-03-20 03:14:14 -07001271 if (internal_record_.opened_data_channels.erase(
1272 reinterpret_cast<uintptr_t>(channel))) {
hbos82ebe022016-11-14 01:41:09 -08001273 ++internal_record_.data_channels_closed;
1274 }
1275}
1276
hboscc555c52016-10-18 12:48:31 -07001277const char* CandidateTypeToRTCIceCandidateTypeForTesting(
1278 const std::string& type) {
1279 return CandidateTypeToRTCIceCandidateType(type);
1280}
1281
1282const char* DataStateToRTCDataChannelStateForTesting(
1283 DataChannelInterface::DataState state) {
1284 return DataStateToRTCDataChannelState(state);
1285}
1286
hbosd565b732016-08-30 14:04:35 -07001287} // namespace webrtc