OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/api/rtcstatscollector.h" | 11 #include "webrtc/api/rtcstatscollector.h" |
12 | 12 |
13 #include <memory> | 13 #include <memory> |
14 #include <utility> | 14 #include <utility> |
15 #include <vector> | 15 #include <vector> |
16 | 16 |
17 #include "webrtc/api/peerconnection.h" | 17 #include "webrtc/api/peerconnection.h" |
18 #include "webrtc/api/webrtcsession.h" | 18 #include "webrtc/api/webrtcsession.h" |
19 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
20 #include "webrtc/base/timeutils.h" | |
21 #include "webrtc/media/base/mediachannel.h" | |
22 #include "webrtc/p2p/base/candidate.h" | 20 #include "webrtc/p2p/base/candidate.h" |
23 #include "webrtc/p2p/base/p2pconstants.h" | 21 #include "webrtc/p2p/base/p2pconstants.h" |
24 #include "webrtc/p2p/base/port.h" | 22 #include "webrtc/p2p/base/port.h" |
25 | 23 |
26 namespace webrtc { | 24 namespace webrtc { |
27 | 25 |
28 namespace { | 26 namespace { |
29 | 27 |
30 std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) { | 28 std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) { |
31 return "RTCCertificate_" + fingerprint; | 29 return "RTCCertificate_" + fingerprint; |
32 } | 30 } |
33 | 31 |
34 std::string RTCIceCandidatePairStatsIDFromConnectionInfo( | 32 std::string RTCIceCandidatePairStatsIDFromConnectionInfo( |
35 const cricket::ConnectionInfo& info) { | 33 const cricket::ConnectionInfo& info) { |
36 return "RTCIceCandidatePair_" + info.local_candidate.id() + "_" + | 34 return "RTCIceCandidatePair_" + info.local_candidate.id() + "_" + |
37 info.remote_candidate.id(); | 35 info.remote_candidate.id(); |
38 } | 36 } |
39 | 37 |
40 std::string RTCTransportStatsIDFromTransportChannel( | 38 std::string RTCTransportStatsIDFromTransportChannel( |
41 const std::string& transport_name, int channel_component) { | 39 const std::string& transport_name, int channel_component) { |
42 return "RTCTransport_" + transport_name + "_" + | 40 return "RTCTransport_" + transport_name + "_" + |
43 rtc::ToString<>(channel_component); | 41 rtc::ToString<>(channel_component); |
44 } | 42 } |
45 | 43 |
46 std::string RTCTransportStatsIDFromBaseChannel( | |
47 const ProxyTransportMap& proxy_to_transport, | |
48 const cricket::BaseChannel& base_channel) { | |
49 auto proxy_it = proxy_to_transport.find(base_channel.content_name()); | |
50 if (proxy_it == proxy_to_transport.cend()) | |
51 return ""; | |
52 return RTCTransportStatsIDFromTransportChannel( | |
53 proxy_it->second, cricket::ICE_CANDIDATE_COMPONENT_RTP); | |
54 } | |
55 | |
56 std::string RTCOutboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) { | |
57 return audio ? "RTCOutboundRTPAudioStream_" + rtc::ToString<>(ssrc) | |
58 : "RTCOutboundRTPVideoStream_" + rtc::ToString<>(ssrc); | |
59 } | |
60 | |
61 const char* CandidateTypeToRTCIceCandidateType(const std::string& type) { | 44 const char* CandidateTypeToRTCIceCandidateType(const std::string& type) { |
62 if (type == cricket::LOCAL_PORT_TYPE) | 45 if (type == cricket::LOCAL_PORT_TYPE) |
63 return RTCIceCandidateType::kHost; | 46 return RTCIceCandidateType::kHost; |
64 if (type == cricket::STUN_PORT_TYPE) | 47 if (type == cricket::STUN_PORT_TYPE) |
65 return RTCIceCandidateType::kSrflx; | 48 return RTCIceCandidateType::kSrflx; |
66 if (type == cricket::PRFLX_PORT_TYPE) | 49 if (type == cricket::PRFLX_PORT_TYPE) |
67 return RTCIceCandidateType::kPrflx; | 50 return RTCIceCandidateType::kPrflx; |
68 if (type == cricket::RELAY_PORT_TYPE) | 51 if (type == cricket::RELAY_PORT_TYPE) |
69 return RTCIceCandidateType::kRelay; | 52 return RTCIceCandidateType::kRelay; |
70 RTC_NOTREACHED(); | 53 RTC_NOTREACHED(); |
(...skipping 10 matching lines...) Expand all Loading... |
81 case DataChannelInterface::kClosing: | 64 case DataChannelInterface::kClosing: |
82 return RTCDataChannelState::kClosing; | 65 return RTCDataChannelState::kClosing; |
83 case DataChannelInterface::kClosed: | 66 case DataChannelInterface::kClosed: |
84 return RTCDataChannelState::kClosed; | 67 return RTCDataChannelState::kClosed; |
85 default: | 68 default: |
86 RTC_NOTREACHED(); | 69 RTC_NOTREACHED(); |
87 return nullptr; | 70 return nullptr; |
88 } | 71 } |
89 } | 72 } |
90 | 73 |
91 void SetOutboundRTPStreamStatsFromMediaSenderInfo( | |
92 const cricket::MediaSenderInfo& media_sender_info, | |
93 RTCOutboundRTPStreamStats* outbound_stats) { | |
94 RTC_DCHECK(outbound_stats); | |
95 outbound_stats->ssrc = rtc::ToString<>(media_sender_info.ssrc()); | |
96 // TODO(hbos): Support the remote case. crbug.com/657856 | |
97 outbound_stats->is_remote = false; | |
98 // TODO(hbos): Set |codec_id| when we have |RTCCodecStats|. Maybe relevant: | |
99 // |media_sender_info.codec_name|. crbug.com/657854, 657856, 659117 | |
100 outbound_stats->packets_sent = | |
101 static_cast<uint32_t>(media_sender_info.packets_sent); | |
102 outbound_stats->bytes_sent = | |
103 static_cast<uint64_t>(media_sender_info.bytes_sent); | |
104 outbound_stats->round_trip_time = | |
105 static_cast<double>(media_sender_info.rtt_ms) / rtc::kNumMillisecsPerSec; | |
106 } | |
107 | |
108 void SetOutboundRTPStreamStatsFromVoiceSenderInfo( | |
109 const cricket::VoiceSenderInfo& voice_sender_info, | |
110 RTCOutboundRTPStreamStats* outbound_audio) { | |
111 SetOutboundRTPStreamStatsFromMediaSenderInfo( | |
112 voice_sender_info, outbound_audio); | |
113 outbound_audio->media_type = "audio"; | |
114 // |fir_count|, |pli_count| and |sli_count| are only valid for video and are | |
115 // purposefully left undefined for audio. | |
116 } | |
117 | |
118 void SetOutboundRTPStreamStatsFromVideoSenderInfo( | |
119 const cricket::VideoSenderInfo& video_sender_info, | |
120 RTCOutboundRTPStreamStats* outbound_video) { | |
121 SetOutboundRTPStreamStatsFromMediaSenderInfo( | |
122 video_sender_info, outbound_video); | |
123 outbound_video->media_type = "video"; | |
124 outbound_video->fir_count = | |
125 static_cast<uint32_t>(video_sender_info.firs_rcvd); | |
126 outbound_video->pli_count = | |
127 static_cast<uint32_t>(video_sender_info.plis_rcvd); | |
128 outbound_video->nack_count = | |
129 static_cast<uint32_t>(video_sender_info.nacks_rcvd); | |
130 } | |
131 | |
132 void ProduceCertificateStatsFromSSLCertificateStats( | 74 void ProduceCertificateStatsFromSSLCertificateStats( |
133 int64_t timestamp_us, const rtc::SSLCertificateStats& certificate_stats, | 75 int64_t timestamp_us, const rtc::SSLCertificateStats& certificate_stats, |
134 RTCStatsReport* report) { | 76 RTCStatsReport* report) { |
135 RTCCertificateStats* prev_certificate_stats = nullptr; | 77 RTCCertificateStats* prev_certificate_stats = nullptr; |
136 for (const rtc::SSLCertificateStats* s = &certificate_stats; s; | 78 for (const rtc::SSLCertificateStats* s = &certificate_stats; s; |
137 s = s->issuer.get()) { | 79 s = s->issuer.get()) { |
138 RTCCertificateStats* certificate_stats = new RTCCertificateStats( | 80 RTCCertificateStats* certificate_stats = new RTCCertificateStats( |
139 RTCCertificateIDFromFingerprint(s->fingerprint), timestamp_us); | 81 RTCCertificateIDFromFingerprint(s->fingerprint), timestamp_us); |
140 certificate_stats->fingerprint = s->fingerprint; | 82 certificate_stats->fingerprint = s->fingerprint; |
141 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm; | 83 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 } | 177 } |
236 | 178 |
237 void RTCStatsCollector::ClearCachedStatsReport() { | 179 void RTCStatsCollector::ClearCachedStatsReport() { |
238 RTC_DCHECK(signaling_thread_->IsCurrent()); | 180 RTC_DCHECK(signaling_thread_->IsCurrent()); |
239 cached_report_ = nullptr; | 181 cached_report_ = nullptr; |
240 } | 182 } |
241 | 183 |
242 void RTCStatsCollector::ProducePartialResultsOnSignalingThread( | 184 void RTCStatsCollector::ProducePartialResultsOnSignalingThread( |
243 int64_t timestamp_us) { | 185 int64_t timestamp_us) { |
244 RTC_DCHECK(signaling_thread_->IsCurrent()); | 186 RTC_DCHECK(signaling_thread_->IsCurrent()); |
245 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( | 187 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
246 timestamp_us); | |
247 | 188 |
248 SessionStats session_stats; | 189 SessionStats session_stats; |
249 if (pc_->session()->GetTransportStats(&session_stats)) { | 190 if (pc_->session()->GetTransportStats(&session_stats)) { |
250 std::map<std::string, CertificateStatsPair> transport_cert_stats = | 191 std::map<std::string, CertificateStatsPair> transport_cert_stats = |
251 PrepareTransportCertificateStats_s(session_stats); | 192 PrepareTransportCertificateStats_s(session_stats); |
252 | 193 |
253 ProduceCertificateStats_s( | 194 ProduceCertificateStats_s( |
254 timestamp_us, transport_cert_stats, report.get()); | 195 timestamp_us, transport_cert_stats, report.get()); |
255 ProduceIceCandidateAndPairStats_s( | 196 ProduceIceCandidateAndPairStats_s( |
256 timestamp_us, session_stats, report.get()); | 197 timestamp_us, session_stats, report.get()); |
257 ProduceRTPStreamStats_s( | |
258 timestamp_us, session_stats, report.get()); | |
259 ProduceTransportStats_s( | 198 ProduceTransportStats_s( |
260 timestamp_us, session_stats, transport_cert_stats, report.get()); | 199 timestamp_us, session_stats, transport_cert_stats, report.get()); |
261 } | 200 } |
262 ProduceDataChannelStats_s(timestamp_us, report.get()); | 201 ProduceDataChannelStats_s(timestamp_us, report.get()); |
263 ProducePeerConnectionStats_s(timestamp_us, report.get()); | 202 ProducePeerConnectionStats_s(timestamp_us, report.get()); |
264 | 203 |
265 AddPartialResults(report); | 204 AddPartialResults(report); |
266 } | 205 } |
267 | 206 |
268 void RTCStatsCollector::ProducePartialResultsOnWorkerThread( | 207 void RTCStatsCollector::ProducePartialResultsOnWorkerThread( |
269 int64_t timestamp_us) { | 208 int64_t timestamp_us) { |
270 RTC_DCHECK(worker_thread_->IsCurrent()); | 209 RTC_DCHECK(worker_thread_->IsCurrent()); |
271 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( | 210 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
272 timestamp_us); | |
273 | 211 |
274 // TODO(hbos): Gather stats on worker thread. | 212 // TODO(hbos): Gather stats on worker thread. |
275 // pc_->session()'s channels are owned by the signaling thread but there are | |
276 // some stats that are gathered on the worker thread. Instead of a synchronous | |
277 // invoke on "s->w" we could to the "w" work here asynchronously if it wasn't | |
278 // for the ownership issue. Synchronous invokes in other places makes it | |
279 // difficult to introduce locks without introducing deadlocks and the channels | |
280 // are not reference counted. | |
281 | 213 |
282 AddPartialResults(report); | 214 AddPartialResults(report); |
283 } | 215 } |
284 | 216 |
285 void RTCStatsCollector::ProducePartialResultsOnNetworkThread( | 217 void RTCStatsCollector::ProducePartialResultsOnNetworkThread( |
286 int64_t timestamp_us) { | 218 int64_t timestamp_us) { |
287 RTC_DCHECK(network_thread_->IsCurrent()); | 219 RTC_DCHECK(network_thread_->IsCurrent()); |
288 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( | 220 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
289 timestamp_us); | |
290 | 221 |
291 // TODO(hbos): Gather stats on network thread. | 222 // TODO(hbos): Gather stats on network thread. |
292 // pc_->session()'s channels are owned by the signaling thread but there are | |
293 // some stats that are gathered on the network thread. Instead of a | |
294 // synchronous invoke on "s->n" we could to the "n" work here asynchronously | |
295 // if it wasn't for the ownership issue. Synchronous invokes in other places | |
296 // makes it difficult to introduce locks without introducing deadlocks and the | |
297 // channels are not reference counted. | |
298 | 223 |
299 AddPartialResults(report); | 224 AddPartialResults(report); |
300 } | 225 } |
301 | 226 |
302 void RTCStatsCollector::AddPartialResults( | 227 void RTCStatsCollector::AddPartialResults( |
303 const rtc::scoped_refptr<RTCStatsReport>& partial_report) { | 228 const rtc::scoped_refptr<RTCStatsReport>& partial_report) { |
304 if (!signaling_thread_->IsCurrent()) { | 229 if (!signaling_thread_->IsCurrent()) { |
305 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, | 230 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |
306 rtc::Bind(&RTCStatsCollector::AddPartialResults_s, | 231 rtc::Bind(&RTCStatsCollector::AddPartialResults_s, |
307 rtc::scoped_refptr<RTCStatsCollector>(this), | 232 rtc::scoped_refptr<RTCStatsCollector>(this), |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 // crbug.com/633550 | 330 // crbug.com/633550 |
406 candidate_pair_stats->writable = info.writable; | 331 candidate_pair_stats->writable = info.writable; |
407 candidate_pair_stats->bytes_sent = | 332 candidate_pair_stats->bytes_sent = |
408 static_cast<uint64_t>(info.sent_total_bytes); | 333 static_cast<uint64_t>(info.sent_total_bytes); |
409 candidate_pair_stats->bytes_received = | 334 candidate_pair_stats->bytes_received = |
410 static_cast<uint64_t>(info.recv_total_bytes); | 335 static_cast<uint64_t>(info.recv_total_bytes); |
411 // TODO(hbos): The |info.rtt| measurement is smoothed. It shouldn't be | 336 // TODO(hbos): The |info.rtt| measurement is smoothed. It shouldn't be |
412 // smoothed according to the spec. crbug.com/633550. See | 337 // smoothed according to the spec. crbug.com/633550. See |
413 // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-curr
entrtt | 338 // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-curr
entrtt |
414 candidate_pair_stats->current_rtt = | 339 candidate_pair_stats->current_rtt = |
415 static_cast<double>(info.rtt) / rtc::kNumMillisecsPerSec; | 340 static_cast<double>(info.rtt) / 1000.0; |
416 candidate_pair_stats->requests_sent = | 341 candidate_pair_stats->requests_sent = |
417 static_cast<uint64_t>(info.sent_ping_requests_total); | 342 static_cast<uint64_t>(info.sent_ping_requests_total); |
418 candidate_pair_stats->responses_received = | 343 candidate_pair_stats->responses_received = |
419 static_cast<uint64_t>(info.recv_ping_responses); | 344 static_cast<uint64_t>(info.recv_ping_responses); |
420 candidate_pair_stats->responses_sent = | 345 candidate_pair_stats->responses_sent = |
421 static_cast<uint64_t>(info.sent_ping_responses); | 346 static_cast<uint64_t>(info.sent_ping_responses); |
422 | 347 |
423 report->AddStats(std::move(candidate_pair_stats)); | 348 report->AddStats(std::move(candidate_pair_stats)); |
424 } | 349 } |
425 } | 350 } |
(...skipping 16 matching lines...) Expand all Loading... |
442 // There is always just one |RTCPeerConnectionStats| so its |id| can be a | 367 // There is always just one |RTCPeerConnectionStats| so its |id| can be a |
443 // constant. | 368 // constant. |
444 std::unique_ptr<RTCPeerConnectionStats> stats( | 369 std::unique_ptr<RTCPeerConnectionStats> stats( |
445 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us)); | 370 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us)); |
446 stats->data_channels_opened = data_channels_opened; | 371 stats->data_channels_opened = data_channels_opened; |
447 stats->data_channels_closed = static_cast<uint32_t>(data_channels.size()) - | 372 stats->data_channels_closed = static_cast<uint32_t>(data_channels.size()) - |
448 data_channels_opened; | 373 data_channels_opened; |
449 report->AddStats(std::move(stats)); | 374 report->AddStats(std::move(stats)); |
450 } | 375 } |
451 | 376 |
452 void RTCStatsCollector::ProduceRTPStreamStats_s( | |
453 int64_t timestamp_us, const SessionStats& session_stats, | |
454 RTCStatsReport* report) const { | |
455 RTC_DCHECK(signaling_thread_->IsCurrent()); | |
456 | |
457 // Audio | |
458 if (pc_->session()->voice_channel()) { | |
459 cricket::VoiceMediaInfo voice_media_info; | |
460 if (pc_->session()->voice_channel()->GetStats(&voice_media_info)) { | |
461 std::string transport_id = RTCTransportStatsIDFromBaseChannel( | |
462 session_stats.proxy_to_transport, *pc_->session()->voice_channel()); | |
463 for (const cricket::VoiceSenderInfo& voice_sender_info : | |
464 voice_media_info.senders) { | |
465 // TODO(nisse): SSRC == 0 currently means none. Delete check when that | |
466 // is fixed. | |
467 if (voice_sender_info.ssrc() == 0) | |
468 continue; | |
469 std::unique_ptr<RTCOutboundRTPStreamStats> outbound_audio( | |
470 new RTCOutboundRTPStreamStats( | |
471 RTCOutboundRTPStreamStatsIDFromSSRC( | |
472 true, voice_sender_info.ssrc()), | |
473 timestamp_us)); | |
474 SetOutboundRTPStreamStatsFromVoiceSenderInfo( | |
475 voice_sender_info, outbound_audio.get()); | |
476 if (!transport_id.empty()) | |
477 outbound_audio->transport_id = transport_id; | |
478 report->AddStats(std::move(outbound_audio)); | |
479 } | |
480 } | |
481 } | |
482 // Video | |
483 if (pc_->session()->video_channel()) { | |
484 cricket::VideoMediaInfo video_media_info; | |
485 if (pc_->session()->video_channel()->GetStats(&video_media_info)) { | |
486 std::string transport_id = RTCTransportStatsIDFromBaseChannel( | |
487 session_stats.proxy_to_transport, *pc_->session()->video_channel()); | |
488 for (const cricket::VideoSenderInfo& video_sender_info : | |
489 video_media_info.senders) { | |
490 // TODO(nisse): SSRC == 0 currently means none. Delete check when that | |
491 // is fixed. | |
492 if (video_sender_info.ssrc() == 0) | |
493 continue; | |
494 std::unique_ptr<RTCOutboundRTPStreamStats> outbound_video( | |
495 new RTCOutboundRTPStreamStats( | |
496 RTCOutboundRTPStreamStatsIDFromSSRC( | |
497 false, video_sender_info.ssrc()), | |
498 timestamp_us)); | |
499 SetOutboundRTPStreamStatsFromVideoSenderInfo( | |
500 video_sender_info, outbound_video.get()); | |
501 if (!transport_id.empty()) | |
502 outbound_video->transport_id = transport_id; | |
503 report->AddStats(std::move(outbound_video)); | |
504 } | |
505 } | |
506 } | |
507 } | |
508 | |
509 void RTCStatsCollector::ProduceTransportStats_s( | 377 void RTCStatsCollector::ProduceTransportStats_s( |
510 int64_t timestamp_us, const SessionStats& session_stats, | 378 int64_t timestamp_us, const SessionStats& session_stats, |
511 const std::map<std::string, CertificateStatsPair>& transport_cert_stats, | 379 const std::map<std::string, CertificateStatsPair>& transport_cert_stats, |
512 RTCStatsReport* report) const { | 380 RTCStatsReport* report) const { |
513 RTC_DCHECK(signaling_thread_->IsCurrent()); | 381 RTC_DCHECK(signaling_thread_->IsCurrent()); |
514 for (const auto& transport : session_stats.transport_stats) { | 382 for (const auto& transport : session_stats.transport_stats) { |
515 // Get reference to RTCP channel, if it exists. | 383 // Get reference to RTCP channel, if it exists. |
516 std::string rtcp_transport_stats_id; | 384 std::string rtcp_transport_stats_id; |
517 for (const auto& channel_stats : transport.second.channel_stats) { | 385 for (const auto& channel_stats : transport.second.channel_stats) { |
518 if (channel_stats.component == | 386 if (channel_stats.component == |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
602 const std::string& type) { | 470 const std::string& type) { |
603 return CandidateTypeToRTCIceCandidateType(type); | 471 return CandidateTypeToRTCIceCandidateType(type); |
604 } | 472 } |
605 | 473 |
606 const char* DataStateToRTCDataChannelStateForTesting( | 474 const char* DataStateToRTCDataChannelStateForTesting( |
607 DataChannelInterface::DataState state) { | 475 DataChannelInterface::DataState state) { |
608 return DataStateToRTCDataChannelState(state); | 476 return DataStateToRTCDataChannelState(state); |
609 } | 477 } |
610 | 478 |
611 } // namespace webrtc | 479 } // namespace webrtc |
OLD | NEW |