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" |
20 #include "webrtc/p2p/base/candidate.h" | 22 #include "webrtc/p2p/base/candidate.h" |
21 #include "webrtc/p2p/base/p2pconstants.h" | 23 #include "webrtc/p2p/base/p2pconstants.h" |
22 #include "webrtc/p2p/base/port.h" | 24 #include "webrtc/p2p/base/port.h" |
23 | 25 |
24 namespace webrtc { | 26 namespace webrtc { |
25 | 27 |
26 namespace { | 28 namespace { |
27 | 29 |
28 std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) { | 30 std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) { |
29 return "RTCCertificate_" + fingerprint; | 31 return "RTCCertificate_" + fingerprint; |
30 } | 32 } |
31 | 33 |
32 std::string RTCIceCandidatePairStatsIDFromConnectionInfo( | 34 std::string RTCIceCandidatePairStatsIDFromConnectionInfo( |
33 const cricket::ConnectionInfo& info) { | 35 const cricket::ConnectionInfo& info) { |
34 return "RTCIceCandidatePair_" + info.local_candidate.id() + "_" + | 36 return "RTCIceCandidatePair_" + info.local_candidate.id() + "_" + |
35 info.remote_candidate.id(); | 37 info.remote_candidate.id(); |
36 } | 38 } |
37 | 39 |
38 std::string RTCTransportStatsIDFromTransportChannel( | 40 std::string RTCTransportStatsIDFromTransportChannel( |
39 const std::string& transport_name, int channel_component) { | 41 const std::string& transport_name, int channel_component) { |
40 return "RTCTransport_" + transport_name + "_" + | 42 return "RTCTransport_" + transport_name + "_" + |
41 rtc::ToString<>(channel_component); | 43 rtc::ToString<>(channel_component); |
42 } | 44 } |
43 | 45 |
| 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 |
44 const char* CandidateTypeToRTCIceCandidateType(const std::string& type) { | 61 const char* CandidateTypeToRTCIceCandidateType(const std::string& type) { |
45 if (type == cricket::LOCAL_PORT_TYPE) | 62 if (type == cricket::LOCAL_PORT_TYPE) |
46 return RTCIceCandidateType::kHost; | 63 return RTCIceCandidateType::kHost; |
47 if (type == cricket::STUN_PORT_TYPE) | 64 if (type == cricket::STUN_PORT_TYPE) |
48 return RTCIceCandidateType::kSrflx; | 65 return RTCIceCandidateType::kSrflx; |
49 if (type == cricket::PRFLX_PORT_TYPE) | 66 if (type == cricket::PRFLX_PORT_TYPE) |
50 return RTCIceCandidateType::kPrflx; | 67 return RTCIceCandidateType::kPrflx; |
51 if (type == cricket::RELAY_PORT_TYPE) | 68 if (type == cricket::RELAY_PORT_TYPE) |
52 return RTCIceCandidateType::kRelay; | 69 return RTCIceCandidateType::kRelay; |
53 RTC_NOTREACHED(); | 70 RTC_NOTREACHED(); |
(...skipping 10 matching lines...) Expand all Loading... |
64 case DataChannelInterface::kClosing: | 81 case DataChannelInterface::kClosing: |
65 return RTCDataChannelState::kClosing; | 82 return RTCDataChannelState::kClosing; |
66 case DataChannelInterface::kClosed: | 83 case DataChannelInterface::kClosed: |
67 return RTCDataChannelState::kClosed; | 84 return RTCDataChannelState::kClosed; |
68 default: | 85 default: |
69 RTC_NOTREACHED(); | 86 RTC_NOTREACHED(); |
70 return nullptr; | 87 return nullptr; |
71 } | 88 } |
72 } | 89 } |
73 | 90 |
| 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 |
74 void ProduceCertificateStatsFromSSLCertificateStats( | 132 void ProduceCertificateStatsFromSSLCertificateStats( |
75 int64_t timestamp_us, const rtc::SSLCertificateStats& certificate_stats, | 133 int64_t timestamp_us, const rtc::SSLCertificateStats& certificate_stats, |
76 RTCStatsReport* report) { | 134 RTCStatsReport* report) { |
77 RTCCertificateStats* prev_certificate_stats = nullptr; | 135 RTCCertificateStats* prev_certificate_stats = nullptr; |
78 for (const rtc::SSLCertificateStats* s = &certificate_stats; s; | 136 for (const rtc::SSLCertificateStats* s = &certificate_stats; s; |
79 s = s->issuer.get()) { | 137 s = s->issuer.get()) { |
80 RTCCertificateStats* certificate_stats = new RTCCertificateStats( | 138 RTCCertificateStats* certificate_stats = new RTCCertificateStats( |
81 RTCCertificateIDFromFingerprint(s->fingerprint), timestamp_us); | 139 RTCCertificateIDFromFingerprint(s->fingerprint), timestamp_us); |
82 certificate_stats->fingerprint = s->fingerprint; | 140 certificate_stats->fingerprint = s->fingerprint; |
83 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm; | 141 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 } | 235 } |
178 | 236 |
179 void RTCStatsCollector::ClearCachedStatsReport() { | 237 void RTCStatsCollector::ClearCachedStatsReport() { |
180 RTC_DCHECK(signaling_thread_->IsCurrent()); | 238 RTC_DCHECK(signaling_thread_->IsCurrent()); |
181 cached_report_ = nullptr; | 239 cached_report_ = nullptr; |
182 } | 240 } |
183 | 241 |
184 void RTCStatsCollector::ProducePartialResultsOnSignalingThread( | 242 void RTCStatsCollector::ProducePartialResultsOnSignalingThread( |
185 int64_t timestamp_us) { | 243 int64_t timestamp_us) { |
186 RTC_DCHECK(signaling_thread_->IsCurrent()); | 244 RTC_DCHECK(signaling_thread_->IsCurrent()); |
187 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); | 245 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( |
| 246 timestamp_us); |
188 | 247 |
189 SessionStats session_stats; | 248 SessionStats session_stats; |
190 if (pc_->session()->GetTransportStats(&session_stats)) { | 249 if (pc_->session()->GetTransportStats(&session_stats)) { |
191 std::map<std::string, CertificateStatsPair> transport_cert_stats = | 250 std::map<std::string, CertificateStatsPair> transport_cert_stats = |
192 PrepareTransportCertificateStats_s(session_stats); | 251 PrepareTransportCertificateStats_s(session_stats); |
193 | 252 |
194 ProduceCertificateStats_s( | 253 ProduceCertificateStats_s( |
195 timestamp_us, transport_cert_stats, report.get()); | 254 timestamp_us, transport_cert_stats, report.get()); |
196 ProduceIceCandidateAndPairStats_s( | 255 ProduceIceCandidateAndPairStats_s( |
197 timestamp_us, session_stats, report.get()); | 256 timestamp_us, session_stats, report.get()); |
| 257 ProduceRTPStreamStats_s( |
| 258 timestamp_us, session_stats, report.get()); |
198 ProduceTransportStats_s( | 259 ProduceTransportStats_s( |
199 timestamp_us, session_stats, transport_cert_stats, report.get()); | 260 timestamp_us, session_stats, transport_cert_stats, report.get()); |
200 } | 261 } |
201 ProduceDataChannelStats_s(timestamp_us, report.get()); | 262 ProduceDataChannelStats_s(timestamp_us, report.get()); |
202 ProducePeerConnectionStats_s(timestamp_us, report.get()); | 263 ProducePeerConnectionStats_s(timestamp_us, report.get()); |
203 | 264 |
204 AddPartialResults(report); | 265 AddPartialResults(report); |
205 } | 266 } |
206 | 267 |
207 void RTCStatsCollector::ProducePartialResultsOnWorkerThread( | 268 void RTCStatsCollector::ProducePartialResultsOnWorkerThread( |
208 int64_t timestamp_us) { | 269 int64_t timestamp_us) { |
209 RTC_DCHECK(worker_thread_->IsCurrent()); | 270 RTC_DCHECK(worker_thread_->IsCurrent()); |
210 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); | 271 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( |
| 272 timestamp_us); |
211 | 273 |
212 // TODO(hbos): Gather stats on worker thread. | 274 // 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. |
213 | 281 |
214 AddPartialResults(report); | 282 AddPartialResults(report); |
215 } | 283 } |
216 | 284 |
217 void RTCStatsCollector::ProducePartialResultsOnNetworkThread( | 285 void RTCStatsCollector::ProducePartialResultsOnNetworkThread( |
218 int64_t timestamp_us) { | 286 int64_t timestamp_us) { |
219 RTC_DCHECK(network_thread_->IsCurrent()); | 287 RTC_DCHECK(network_thread_->IsCurrent()); |
220 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); | 288 rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( |
| 289 timestamp_us); |
221 | 290 |
222 // TODO(hbos): Gather stats on network thread. | 291 // 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. |
223 | 298 |
224 AddPartialResults(report); | 299 AddPartialResults(report); |
225 } | 300 } |
226 | 301 |
227 void RTCStatsCollector::AddPartialResults( | 302 void RTCStatsCollector::AddPartialResults( |
228 const rtc::scoped_refptr<RTCStatsReport>& partial_report) { | 303 const rtc::scoped_refptr<RTCStatsReport>& partial_report) { |
229 if (!signaling_thread_->IsCurrent()) { | 304 if (!signaling_thread_->IsCurrent()) { |
230 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, | 305 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |
231 rtc::Bind(&RTCStatsCollector::AddPartialResults_s, | 306 rtc::Bind(&RTCStatsCollector::AddPartialResults_s, |
232 rtc::scoped_refptr<RTCStatsCollector>(this), | 307 rtc::scoped_refptr<RTCStatsCollector>(this), |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 // crbug.com/633550 | 405 // crbug.com/633550 |
331 candidate_pair_stats->writable = info.writable; | 406 candidate_pair_stats->writable = info.writable; |
332 candidate_pair_stats->bytes_sent = | 407 candidate_pair_stats->bytes_sent = |
333 static_cast<uint64_t>(info.sent_total_bytes); | 408 static_cast<uint64_t>(info.sent_total_bytes); |
334 candidate_pair_stats->bytes_received = | 409 candidate_pair_stats->bytes_received = |
335 static_cast<uint64_t>(info.recv_total_bytes); | 410 static_cast<uint64_t>(info.recv_total_bytes); |
336 // TODO(hbos): The |info.rtt| measurement is smoothed. It shouldn't be | 411 // TODO(hbos): The |info.rtt| measurement is smoothed. It shouldn't be |
337 // smoothed according to the spec. crbug.com/633550. See | 412 // smoothed according to the spec. crbug.com/633550. See |
338 // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-curr
entrtt | 413 // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-curr
entrtt |
339 candidate_pair_stats->current_rtt = | 414 candidate_pair_stats->current_rtt = |
340 static_cast<double>(info.rtt) / 1000.0; | 415 static_cast<double>(info.rtt) / rtc::kNumMillisecsPerSec; |
341 candidate_pair_stats->requests_sent = | 416 candidate_pair_stats->requests_sent = |
342 static_cast<uint64_t>(info.sent_ping_requests_total); | 417 static_cast<uint64_t>(info.sent_ping_requests_total); |
343 candidate_pair_stats->responses_received = | 418 candidate_pair_stats->responses_received = |
344 static_cast<uint64_t>(info.recv_ping_responses); | 419 static_cast<uint64_t>(info.recv_ping_responses); |
345 candidate_pair_stats->responses_sent = | 420 candidate_pair_stats->responses_sent = |
346 static_cast<uint64_t>(info.sent_ping_responses); | 421 static_cast<uint64_t>(info.sent_ping_responses); |
347 | 422 |
348 report->AddStats(std::move(candidate_pair_stats)); | 423 report->AddStats(std::move(candidate_pair_stats)); |
349 } | 424 } |
350 } | 425 } |
(...skipping 16 matching lines...) Expand all Loading... |
367 // There is always just one |RTCPeerConnectionStats| so its |id| can be a | 442 // There is always just one |RTCPeerConnectionStats| so its |id| can be a |
368 // constant. | 443 // constant. |
369 std::unique_ptr<RTCPeerConnectionStats> stats( | 444 std::unique_ptr<RTCPeerConnectionStats> stats( |
370 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us)); | 445 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us)); |
371 stats->data_channels_opened = data_channels_opened; | 446 stats->data_channels_opened = data_channels_opened; |
372 stats->data_channels_closed = static_cast<uint32_t>(data_channels.size()) - | 447 stats->data_channels_closed = static_cast<uint32_t>(data_channels.size()) - |
373 data_channels_opened; | 448 data_channels_opened; |
374 report->AddStats(std::move(stats)); | 449 report->AddStats(std::move(stats)); |
375 } | 450 } |
376 | 451 |
| 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 |
377 void RTCStatsCollector::ProduceTransportStats_s( | 509 void RTCStatsCollector::ProduceTransportStats_s( |
378 int64_t timestamp_us, const SessionStats& session_stats, | 510 int64_t timestamp_us, const SessionStats& session_stats, |
379 const std::map<std::string, CertificateStatsPair>& transport_cert_stats, | 511 const std::map<std::string, CertificateStatsPair>& transport_cert_stats, |
380 RTCStatsReport* report) const { | 512 RTCStatsReport* report) const { |
381 RTC_DCHECK(signaling_thread_->IsCurrent()); | 513 RTC_DCHECK(signaling_thread_->IsCurrent()); |
382 for (const auto& transport : session_stats.transport_stats) { | 514 for (const auto& transport : session_stats.transport_stats) { |
383 // Get reference to RTCP channel, if it exists. | 515 // Get reference to RTCP channel, if it exists. |
384 std::string rtcp_transport_stats_id; | 516 std::string rtcp_transport_stats_id; |
385 for (const auto& channel_stats : transport.second.channel_stats) { | 517 for (const auto& channel_stats : transport.second.channel_stats) { |
386 if (channel_stats.component == | 518 if (channel_stats.component == |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
470 const std::string& type) { | 602 const std::string& type) { |
471 return CandidateTypeToRTCIceCandidateType(type); | 603 return CandidateTypeToRTCIceCandidateType(type); |
472 } | 604 } |
473 | 605 |
474 const char* DataStateToRTCDataChannelStateForTesting( | 606 const char* DataStateToRTCDataChannelStateForTesting( |
475 DataChannelInterface::DataState state) { | 607 DataChannelInterface::DataState state) { |
476 return DataStateToRTCDataChannelState(state); | 608 return DataStateToRTCDataChannelState(state); |
477 } | 609 } |
478 | 610 |
479 } // namespace webrtc | 611 } // namespace webrtc |
OLD | NEW |