| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* |  | 
| 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 |  | 
| 11 #include "webrtc/api/rtcstatscollector.h" |  | 
| 12 |  | 
| 13 #include <memory> |  | 
| 14 #include <utility> |  | 
| 15 #include <vector> |  | 
| 16 |  | 
| 17 #include "webrtc/api/peerconnection.h" |  | 
| 18 #include "webrtc/api/peerconnectioninterface.h" |  | 
| 19 #include "webrtc/api/mediastreaminterface.h" |  | 
| 20 #include "webrtc/api/webrtcsession.h" |  | 
| 21 #include "webrtc/base/checks.h" |  | 
| 22 #include "webrtc/base/timeutils.h" |  | 
| 23 #include "webrtc/media/base/mediachannel.h" |  | 
| 24 #include "webrtc/p2p/base/candidate.h" |  | 
| 25 #include "webrtc/p2p/base/p2pconstants.h" |  | 
| 26 #include "webrtc/p2p/base/port.h" |  | 
| 27 |  | 
| 28 namespace webrtc { |  | 
| 29 |  | 
| 30 namespace { |  | 
| 31 |  | 
| 32 std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) { |  | 
| 33   return "RTCCertificate_" + fingerprint; |  | 
| 34 } |  | 
| 35 |  | 
| 36 std::string RTCCodecStatsIDFromDirectionMediaAndPayload( |  | 
| 37     bool inbound, bool audio, uint32_t payload_type) { |  | 
| 38   // TODO(hbos): When we are able to handle multiple m= lines of the same media |  | 
| 39   // type (and multiple BaseChannels for the same type is possible?) this needs |  | 
| 40   // to be updated to differentiate the transport being used, and stats need to |  | 
| 41   // be collected for all of them. crbug.com/659117 |  | 
| 42   if (inbound) { |  | 
| 43     return audio ? "RTCCodec_InboundAudio_" + rtc::ToString<>(payload_type) |  | 
| 44                  : "RTCCodec_InboundVideo_" + rtc::ToString<>(payload_type); |  | 
| 45   } |  | 
| 46   return audio ? "RTCCodec_OutboundAudio_" + rtc::ToString<>(payload_type) |  | 
| 47                : "RTCCodec_OutboundVideo_" + rtc::ToString<>(payload_type); |  | 
| 48 } |  | 
| 49 |  | 
| 50 std::string RTCIceCandidatePairStatsIDFromConnectionInfo( |  | 
| 51     const cricket::ConnectionInfo& info) { |  | 
| 52   return "RTCIceCandidatePair_" + info.local_candidate.id() + "_" + |  | 
| 53       info.remote_candidate.id(); |  | 
| 54 } |  | 
| 55 |  | 
| 56 std::string RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface( |  | 
| 57     const MediaStreamTrackInterface& track) { |  | 
| 58   return "RTCMediaStreamTrack_" + track.id(); |  | 
| 59 } |  | 
| 60 |  | 
| 61 std::string RTCTransportStatsIDFromTransportChannel( |  | 
| 62     const std::string& transport_name, int channel_component) { |  | 
| 63   return "RTCTransport_" + transport_name + "_" + |  | 
| 64       rtc::ToString<>(channel_component); |  | 
| 65 } |  | 
| 66 |  | 
| 67 std::string RTCTransportStatsIDFromBaseChannel( |  | 
| 68     const ProxyTransportMap& proxy_to_transport, |  | 
| 69     const cricket::BaseChannel& base_channel) { |  | 
| 70   auto proxy_it = proxy_to_transport.find(base_channel.content_name()); |  | 
| 71   if (proxy_it == proxy_to_transport.cend()) |  | 
| 72     return ""; |  | 
| 73   return RTCTransportStatsIDFromTransportChannel( |  | 
| 74       proxy_it->second, cricket::ICE_CANDIDATE_COMPONENT_RTP); |  | 
| 75 } |  | 
| 76 |  | 
| 77 std::string RTCInboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) { |  | 
| 78   return audio ? "RTCInboundRTPAudioStream_" + rtc::ToString<>(ssrc) |  | 
| 79                : "RTCInboundRTPVideoStream_" + rtc::ToString<>(ssrc); |  | 
| 80 } |  | 
| 81 |  | 
| 82 std::string RTCOutboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) { |  | 
| 83   return audio ? "RTCOutboundRTPAudioStream_" + rtc::ToString<>(ssrc) |  | 
| 84                : "RTCOutboundRTPVideoStream_" + rtc::ToString<>(ssrc); |  | 
| 85 } |  | 
| 86 |  | 
| 87 const char* CandidateTypeToRTCIceCandidateType(const std::string& type) { |  | 
| 88   if (type == cricket::LOCAL_PORT_TYPE) |  | 
| 89     return RTCIceCandidateType::kHost; |  | 
| 90   if (type == cricket::STUN_PORT_TYPE) |  | 
| 91     return RTCIceCandidateType::kSrflx; |  | 
| 92   if (type == cricket::PRFLX_PORT_TYPE) |  | 
| 93     return RTCIceCandidateType::kPrflx; |  | 
| 94   if (type == cricket::RELAY_PORT_TYPE) |  | 
| 95     return RTCIceCandidateType::kRelay; |  | 
| 96   RTC_NOTREACHED(); |  | 
| 97   return nullptr; |  | 
| 98 } |  | 
| 99 |  | 
| 100 const char* DataStateToRTCDataChannelState( |  | 
| 101     DataChannelInterface::DataState state) { |  | 
| 102   switch (state) { |  | 
| 103     case DataChannelInterface::kConnecting: |  | 
| 104       return RTCDataChannelState::kConnecting; |  | 
| 105     case DataChannelInterface::kOpen: |  | 
| 106       return RTCDataChannelState::kOpen; |  | 
| 107     case DataChannelInterface::kClosing: |  | 
| 108       return RTCDataChannelState::kClosing; |  | 
| 109     case DataChannelInterface::kClosed: |  | 
| 110       return RTCDataChannelState::kClosed; |  | 
| 111     default: |  | 
| 112       RTC_NOTREACHED(); |  | 
| 113       return nullptr; |  | 
| 114   } |  | 
| 115 } |  | 
| 116 |  | 
| 117 std::unique_ptr<RTCCodecStats> CodecStatsFromRtpCodecParameters( |  | 
| 118     uint64_t timestamp_us, bool inbound, bool audio, |  | 
| 119     const RtpCodecParameters& codec_params) { |  | 
| 120   RTC_DCHECK_GE(codec_params.payload_type, 0); |  | 
| 121   RTC_DCHECK_LE(codec_params.payload_type, 127); |  | 
| 122   uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type); |  | 
| 123   std::unique_ptr<RTCCodecStats> codec_stats(new RTCCodecStats( |  | 
| 124       RTCCodecStatsIDFromDirectionMediaAndPayload(inbound, audio, payload_type), |  | 
| 125       timestamp_us)); |  | 
| 126   codec_stats->payload_type = payload_type; |  | 
| 127   codec_stats->codec = (audio ? "audio/" : "video/") + codec_params.mime_type; |  | 
| 128   codec_stats->clock_rate = static_cast<uint32_t>(codec_params.clock_rate); |  | 
| 129   return codec_stats; |  | 
| 130 } |  | 
| 131 |  | 
| 132 void SetMediaStreamTrackStatsFromMediaStreamTrackInterface( |  | 
| 133     const MediaStreamTrackInterface& track, |  | 
| 134     RTCMediaStreamTrackStats* track_stats) { |  | 
| 135   track_stats->track_identifier = track.id(); |  | 
| 136   track_stats->ended = (track.state() == MediaStreamTrackInterface::kEnded); |  | 
| 137 } |  | 
| 138 |  | 
| 139 // Provides the media independent counters (both audio and video). |  | 
| 140 void SetInboundRTPStreamStatsFromMediaReceiverInfo( |  | 
| 141     const cricket::MediaReceiverInfo& media_receiver_info, |  | 
| 142     RTCInboundRTPStreamStats* inbound_stats) { |  | 
| 143   RTC_DCHECK(inbound_stats); |  | 
| 144   inbound_stats->ssrc = rtc::ToString<>(media_receiver_info.ssrc()); |  | 
| 145   // TODO(hbos): Support the remote case. crbug.com/657855 |  | 
| 146   inbound_stats->is_remote = false; |  | 
| 147   // TODO(hbos): Set |codec_id| when we have |RTCCodecStats|. Maybe relevant: |  | 
| 148   // |media_receiver_info.codec_name|. crbug.com/657854, 657855, 659117 |  | 
| 149   inbound_stats->packets_received = |  | 
| 150       static_cast<uint32_t>(media_receiver_info.packets_rcvd); |  | 
| 151   inbound_stats->bytes_received = |  | 
| 152       static_cast<uint64_t>(media_receiver_info.bytes_rcvd); |  | 
| 153   inbound_stats->packets_lost = |  | 
| 154       static_cast<uint32_t>(media_receiver_info.packets_lost); |  | 
| 155   inbound_stats->fraction_lost = |  | 
| 156       static_cast<double>(media_receiver_info.fraction_lost); |  | 
| 157 } |  | 
| 158 |  | 
| 159 void SetInboundRTPStreamStatsFromVoiceReceiverInfo( |  | 
| 160     const cricket::VoiceReceiverInfo& voice_receiver_info, |  | 
| 161     RTCInboundRTPStreamStats* inbound_audio) { |  | 
| 162   SetInboundRTPStreamStatsFromMediaReceiverInfo( |  | 
| 163       voice_receiver_info, inbound_audio); |  | 
| 164   inbound_audio->media_type = "audio"; |  | 
| 165   inbound_audio->jitter = |  | 
| 166       static_cast<double>(voice_receiver_info.jitter_ms) / |  | 
| 167           rtc::kNumMillisecsPerSec; |  | 
| 168   // |fir_count|, |pli_count| and |sli_count| are only valid for video and are |  | 
| 169   // purposefully left undefined for audio. |  | 
| 170 } |  | 
| 171 |  | 
| 172 void SetInboundRTPStreamStatsFromVideoReceiverInfo( |  | 
| 173     const cricket::VideoReceiverInfo& video_receiver_info, |  | 
| 174     RTCInboundRTPStreamStats* inbound_video) { |  | 
| 175   SetInboundRTPStreamStatsFromMediaReceiverInfo( |  | 
| 176       video_receiver_info, inbound_video); |  | 
| 177   inbound_video->media_type = "video"; |  | 
| 178   inbound_video->fir_count = |  | 
| 179       static_cast<uint32_t>(video_receiver_info.firs_sent); |  | 
| 180   inbound_video->pli_count = |  | 
| 181       static_cast<uint32_t>(video_receiver_info.plis_sent); |  | 
| 182   inbound_video->nack_count = |  | 
| 183       static_cast<uint32_t>(video_receiver_info.nacks_sent); |  | 
| 184 } |  | 
| 185 |  | 
| 186 // Provides the media independent counters (both audio and video). |  | 
| 187 void SetOutboundRTPStreamStatsFromMediaSenderInfo( |  | 
| 188     const cricket::MediaSenderInfo& media_sender_info, |  | 
| 189     RTCOutboundRTPStreamStats* outbound_stats) { |  | 
| 190   RTC_DCHECK(outbound_stats); |  | 
| 191   outbound_stats->ssrc = rtc::ToString<>(media_sender_info.ssrc()); |  | 
| 192   // TODO(hbos): Support the remote case. crbug.com/657856 |  | 
| 193   outbound_stats->is_remote = false; |  | 
| 194   // TODO(hbos): Set |codec_id| when we have |RTCCodecStats|. Maybe relevant: |  | 
| 195   // |media_sender_info.codec_name|. crbug.com/657854, 657856, 659117 |  | 
| 196   outbound_stats->packets_sent = |  | 
| 197       static_cast<uint32_t>(media_sender_info.packets_sent); |  | 
| 198   outbound_stats->bytes_sent = |  | 
| 199       static_cast<uint64_t>(media_sender_info.bytes_sent); |  | 
| 200   outbound_stats->round_trip_time = |  | 
| 201       static_cast<double>(media_sender_info.rtt_ms) / rtc::kNumMillisecsPerSec; |  | 
| 202 } |  | 
| 203 |  | 
| 204 void SetOutboundRTPStreamStatsFromVoiceSenderInfo( |  | 
| 205     const cricket::VoiceSenderInfo& voice_sender_info, |  | 
| 206     RTCOutboundRTPStreamStats* outbound_audio) { |  | 
| 207   SetOutboundRTPStreamStatsFromMediaSenderInfo( |  | 
| 208       voice_sender_info, outbound_audio); |  | 
| 209   outbound_audio->media_type = "audio"; |  | 
| 210   // |fir_count|, |pli_count| and |sli_count| are only valid for video and are |  | 
| 211   // purposefully left undefined for audio. |  | 
| 212 } |  | 
| 213 |  | 
| 214 void SetOutboundRTPStreamStatsFromVideoSenderInfo( |  | 
| 215     const cricket::VideoSenderInfo& video_sender_info, |  | 
| 216     RTCOutboundRTPStreamStats* outbound_video) { |  | 
| 217   SetOutboundRTPStreamStatsFromMediaSenderInfo( |  | 
| 218       video_sender_info, outbound_video); |  | 
| 219   outbound_video->media_type = "video"; |  | 
| 220   outbound_video->fir_count = |  | 
| 221       static_cast<uint32_t>(video_sender_info.firs_rcvd); |  | 
| 222   outbound_video->pli_count = |  | 
| 223       static_cast<uint32_t>(video_sender_info.plis_rcvd); |  | 
| 224   outbound_video->nack_count = |  | 
| 225       static_cast<uint32_t>(video_sender_info.nacks_rcvd); |  | 
| 226 } |  | 
| 227 |  | 
| 228 void ProduceCertificateStatsFromSSLCertificateStats( |  | 
| 229     int64_t timestamp_us, const rtc::SSLCertificateStats& certificate_stats, |  | 
| 230     RTCStatsReport* report) { |  | 
| 231   RTCCertificateStats* prev_certificate_stats = nullptr; |  | 
| 232   for (const rtc::SSLCertificateStats* s = &certificate_stats; s; |  | 
| 233        s = s->issuer.get()) { |  | 
| 234     RTCCertificateStats* certificate_stats = new RTCCertificateStats( |  | 
| 235         RTCCertificateIDFromFingerprint(s->fingerprint), timestamp_us); |  | 
| 236     certificate_stats->fingerprint = s->fingerprint; |  | 
| 237     certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm; |  | 
| 238     certificate_stats->base64_certificate = s->base64_certificate; |  | 
| 239     if (prev_certificate_stats) |  | 
| 240       prev_certificate_stats->issuer_certificate_id = certificate_stats->id(); |  | 
| 241     report->AddStats(std::unique_ptr<RTCCertificateStats>(certificate_stats)); |  | 
| 242     prev_certificate_stats = certificate_stats; |  | 
| 243   } |  | 
| 244 } |  | 
| 245 |  | 
| 246 const std::string& ProduceIceCandidateStats( |  | 
| 247     int64_t timestamp_us, const cricket::Candidate& candidate, bool is_local, |  | 
| 248     RTCStatsReport* report) { |  | 
| 249   const std::string& id = "RTCIceCandidate_" + candidate.id(); |  | 
| 250   const RTCStats* stats = report->Get(id); |  | 
| 251   if (!stats) { |  | 
| 252     std::unique_ptr<RTCIceCandidateStats> candidate_stats; |  | 
| 253     if (is_local) |  | 
| 254       candidate_stats.reset(new RTCLocalIceCandidateStats(id, timestamp_us)); |  | 
| 255     else |  | 
| 256       candidate_stats.reset(new RTCRemoteIceCandidateStats(id, timestamp_us)); |  | 
| 257     candidate_stats->ip = candidate.address().ipaddr().ToString(); |  | 
| 258     candidate_stats->port = static_cast<int32_t>(candidate.address().port()); |  | 
| 259     candidate_stats->protocol = candidate.protocol(); |  | 
| 260     candidate_stats->candidate_type = CandidateTypeToRTCIceCandidateType( |  | 
| 261         candidate.type()); |  | 
| 262     candidate_stats->priority = static_cast<int32_t>(candidate.priority()); |  | 
| 263 |  | 
| 264     stats = candidate_stats.get(); |  | 
| 265     report->AddStats(std::move(candidate_stats)); |  | 
| 266   } |  | 
| 267   RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType |  | 
| 268                                         : RTCRemoteIceCandidateStats::kType); |  | 
| 269   return stats->id(); |  | 
| 270 } |  | 
| 271 |  | 
| 272 void ProduceMediaStreamAndTrackStats( |  | 
| 273     int64_t timestamp_us, |  | 
| 274     rtc::scoped_refptr<StreamCollectionInterface> streams, |  | 
| 275     bool is_local, |  | 
| 276     RTCStatsReport* report) { |  | 
| 277   // TODO(hbos): When "AddTrack" is implemented we should iterate tracks to |  | 
| 278   // find which streams exist, not iterate streams to find tracks. |  | 
| 279   // crbug.com/659137 |  | 
| 280   // TODO(hbos): Return stats of detached tracks. We have to perform stats |  | 
| 281   // gathering at the time of detachment to get accurate stats and timestamps. |  | 
| 282   // crbug.com/659137 |  | 
| 283   if (!streams) |  | 
| 284     return; |  | 
| 285   for (size_t i = 0; i < streams->count(); ++i) { |  | 
| 286     MediaStreamInterface* stream = streams->at(i); |  | 
| 287 |  | 
| 288     std::unique_ptr<RTCMediaStreamStats> stream_stats( |  | 
| 289         new RTCMediaStreamStats("RTCMediaStream_" + stream->label(), |  | 
| 290                                 timestamp_us)); |  | 
| 291     stream_stats->stream_identifier = stream->label(); |  | 
| 292     stream_stats->track_ids = std::vector<std::string>(); |  | 
| 293     // Audio Tracks |  | 
| 294     for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track : |  | 
| 295          stream->GetAudioTracks()) { |  | 
| 296       std::string id = RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface( |  | 
| 297         *audio_track.get()); |  | 
| 298       if (report->Get(id)) { |  | 
| 299         // Skip track, stats already exist for it. |  | 
| 300         continue; |  | 
| 301       } |  | 
| 302       std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats( |  | 
| 303           new RTCMediaStreamTrackStats(id, timestamp_us)); |  | 
| 304       stream_stats->track_ids->push_back(audio_track_stats->id()); |  | 
| 305       SetMediaStreamTrackStatsFromMediaStreamTrackInterface( |  | 
| 306           *audio_track.get(), |  | 
| 307           audio_track_stats.get()); |  | 
| 308       audio_track_stats->remote_source = !is_local; |  | 
| 309       audio_track_stats->detached = false; |  | 
| 310       int signal_level; |  | 
| 311       if (audio_track->GetSignalLevel(&signal_level)) { |  | 
| 312         // Convert signal level from [0,32767] int to [0,1] double. |  | 
| 313         RTC_DCHECK_GE(signal_level, 0); |  | 
| 314         RTC_DCHECK_LE(signal_level, 32767); |  | 
| 315         audio_track_stats->audio_level = signal_level / 32767.0; |  | 
| 316       } |  | 
| 317       if (audio_track->GetAudioProcessor()) { |  | 
| 318         AudioProcessorInterface::AudioProcessorStats audio_processor_stats; |  | 
| 319         audio_track->GetAudioProcessor()->GetStats(&audio_processor_stats); |  | 
| 320         audio_track_stats->echo_return_loss = static_cast<double>( |  | 
| 321             audio_processor_stats.echo_return_loss); |  | 
| 322         audio_track_stats->echo_return_loss_enhancement = static_cast<double>( |  | 
| 323             audio_processor_stats.echo_return_loss_enhancement); |  | 
| 324       } |  | 
| 325       report->AddStats(std::move(audio_track_stats)); |  | 
| 326     } |  | 
| 327     // Video Tracks |  | 
| 328     for (const rtc::scoped_refptr<VideoTrackInterface>& video_track : |  | 
| 329          stream->GetVideoTracks()) { |  | 
| 330       std::string id = RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface( |  | 
| 331           *video_track.get()); |  | 
| 332       if (report->Get(id)) { |  | 
| 333         // Skip track, stats already exist for it. |  | 
| 334         continue; |  | 
| 335       } |  | 
| 336       std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats( |  | 
| 337           new RTCMediaStreamTrackStats(id, timestamp_us)); |  | 
| 338       stream_stats->track_ids->push_back(video_track_stats->id()); |  | 
| 339       SetMediaStreamTrackStatsFromMediaStreamTrackInterface( |  | 
| 340           *video_track.get(), |  | 
| 341           video_track_stats.get()); |  | 
| 342       video_track_stats->remote_source = !is_local; |  | 
| 343       video_track_stats->detached = false; |  | 
| 344       if (video_track->GetSource()) { |  | 
| 345         VideoTrackSourceInterface::Stats video_track_source_stats; |  | 
| 346         if (video_track->GetSource()->GetStats(&video_track_source_stats)) { |  | 
| 347           video_track_stats->frame_width = static_cast<uint32_t>( |  | 
| 348               video_track_source_stats.input_width); |  | 
| 349           video_track_stats->frame_height = static_cast<uint32_t>( |  | 
| 350               video_track_source_stats.input_height); |  | 
| 351         } |  | 
| 352       } |  | 
| 353       report->AddStats(std::move(video_track_stats)); |  | 
| 354     } |  | 
| 355     report->AddStats(std::move(stream_stats)); |  | 
| 356   } |  | 
| 357 } |  | 
| 358 |  | 
| 359 }  // namespace |  | 
| 360 |  | 
| 361 rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create( |  | 
| 362     PeerConnection* pc, int64_t cache_lifetime_us) { |  | 
| 363   return rtc::scoped_refptr<RTCStatsCollector>( |  | 
| 364       new rtc::RefCountedObject<RTCStatsCollector>(pc, cache_lifetime_us)); |  | 
| 365 } |  | 
| 366 |  | 
| 367 RTCStatsCollector::RTCStatsCollector(PeerConnection* pc, |  | 
| 368                                      int64_t cache_lifetime_us) |  | 
| 369     : pc_(pc), |  | 
| 370       signaling_thread_(pc->session()->signaling_thread()), |  | 
| 371       worker_thread_(pc->session()->worker_thread()), |  | 
| 372       network_thread_(pc->session()->network_thread()), |  | 
| 373       num_pending_partial_reports_(0), |  | 
| 374       partial_report_timestamp_us_(0), |  | 
| 375       cache_timestamp_us_(0), |  | 
| 376       cache_lifetime_us_(cache_lifetime_us) { |  | 
| 377   RTC_DCHECK(pc_); |  | 
| 378   RTC_DCHECK(signaling_thread_); |  | 
| 379   RTC_DCHECK(worker_thread_); |  | 
| 380   RTC_DCHECK(network_thread_); |  | 
| 381   RTC_DCHECK_GE(cache_lifetime_us_, 0); |  | 
| 382   pc_->SignalDataChannelCreated.connect( |  | 
| 383       this, &RTCStatsCollector::OnDataChannelCreated); |  | 
| 384 } |  | 
| 385 |  | 
| 386 void RTCStatsCollector::GetStatsReport( |  | 
| 387     rtc::scoped_refptr<RTCStatsCollectorCallback> callback) { |  | 
| 388   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 389   RTC_DCHECK(callback); |  | 
| 390   callbacks_.push_back(callback); |  | 
| 391 |  | 
| 392   // "Now" using a monotonically increasing timer. |  | 
| 393   int64_t cache_now_us = rtc::TimeMicros(); |  | 
| 394   if (cached_report_ && |  | 
| 395       cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) { |  | 
| 396     // We have a fresh cached report to deliver. |  | 
| 397     DeliverCachedReport(); |  | 
| 398   } else if (!num_pending_partial_reports_) { |  | 
| 399     // Only start gathering stats if we're not already gathering stats. In the |  | 
| 400     // case of already gathering stats, |callback_| will be invoked when there |  | 
| 401     // are no more pending partial reports. |  | 
| 402 |  | 
| 403     // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970, |  | 
| 404     // UTC), in microseconds. The system clock could be modified and is not |  | 
| 405     // necessarily monotonically increasing. |  | 
| 406     int64_t timestamp_us = rtc::TimeUTCMicros(); |  | 
| 407 |  | 
| 408     num_pending_partial_reports_ = 3; |  | 
| 409     partial_report_timestamp_us_ = cache_now_us; |  | 
| 410     invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |  | 
| 411         rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnSignalingThread, |  | 
| 412             rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |  | 
| 413     invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, |  | 
| 414         rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnWorkerThread, |  | 
| 415             rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |  | 
| 416     invoker_.AsyncInvoke<void>(RTC_FROM_HERE, network_thread_, |  | 
| 417         rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread, |  | 
| 418             rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |  | 
| 419   } |  | 
| 420 } |  | 
| 421 |  | 
| 422 void RTCStatsCollector::ClearCachedStatsReport() { |  | 
| 423   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 424   cached_report_ = nullptr; |  | 
| 425 } |  | 
| 426 |  | 
| 427 void RTCStatsCollector::ProducePartialResultsOnSignalingThread( |  | 
| 428     int64_t timestamp_us) { |  | 
| 429   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 430   rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( |  | 
| 431       timestamp_us); |  | 
| 432 |  | 
| 433   SessionStats session_stats; |  | 
| 434   if (pc_->session()->GetTransportStats(&session_stats)) { |  | 
| 435     std::map<std::string, CertificateStatsPair> transport_cert_stats = |  | 
| 436         PrepareTransportCertificateStats(session_stats); |  | 
| 437     MediaInfo media_info = PrepareMediaInfo(session_stats); |  | 
| 438 |  | 
| 439     ProduceCertificateStats_s( |  | 
| 440         timestamp_us, transport_cert_stats, report.get()); |  | 
| 441     ProduceCodecStats_s( |  | 
| 442         timestamp_us, media_info, report.get()); |  | 
| 443     ProduceIceCandidateAndPairStats_s( |  | 
| 444         timestamp_us, session_stats, report.get()); |  | 
| 445     ProduceRTPStreamStats_s( |  | 
| 446         timestamp_us, session_stats, media_info, report.get()); |  | 
| 447     ProduceTransportStats_s( |  | 
| 448         timestamp_us, session_stats, transport_cert_stats, report.get()); |  | 
| 449   } |  | 
| 450   ProduceDataChannelStats_s(timestamp_us, report.get()); |  | 
| 451   ProduceMediaStreamAndTrackStats_s(timestamp_us, report.get()); |  | 
| 452   ProducePeerConnectionStats_s(timestamp_us, report.get()); |  | 
| 453 |  | 
| 454   AddPartialResults(report); |  | 
| 455 } |  | 
| 456 |  | 
| 457 void RTCStatsCollector::ProducePartialResultsOnWorkerThread( |  | 
| 458     int64_t timestamp_us) { |  | 
| 459   RTC_DCHECK(worker_thread_->IsCurrent()); |  | 
| 460   rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( |  | 
| 461       timestamp_us); |  | 
| 462 |  | 
| 463   // TODO(hbos): Gather stats on worker thread. |  | 
| 464   // pc_->session()'s channels are owned by the signaling thread but there are |  | 
| 465   // some stats that are gathered on the worker thread. Instead of a synchronous |  | 
| 466   // invoke on "s->w" we could to the "w" work here asynchronously if it wasn't |  | 
| 467   // for the ownership issue. Synchronous invokes in other places makes it |  | 
| 468   // difficult to introduce locks without introducing deadlocks and the channels |  | 
| 469   // are not reference counted. |  | 
| 470 |  | 
| 471   AddPartialResults(report); |  | 
| 472 } |  | 
| 473 |  | 
| 474 void RTCStatsCollector::ProducePartialResultsOnNetworkThread( |  | 
| 475     int64_t timestamp_us) { |  | 
| 476   RTC_DCHECK(network_thread_->IsCurrent()); |  | 
| 477   rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( |  | 
| 478       timestamp_us); |  | 
| 479 |  | 
| 480   // TODO(hbos): Gather stats on network thread. |  | 
| 481   // pc_->session()'s channels are owned by the signaling thread but there are |  | 
| 482   // some stats that are gathered on the network thread. Instead of a |  | 
| 483   // synchronous invoke on "s->n" we could to the "n" work here asynchronously |  | 
| 484   // if it wasn't for the ownership issue. Synchronous invokes in other places |  | 
| 485   // makes it difficult to introduce locks without introducing deadlocks and the |  | 
| 486   // channels are not reference counted. |  | 
| 487 |  | 
| 488   AddPartialResults(report); |  | 
| 489 } |  | 
| 490 |  | 
| 491 void RTCStatsCollector::AddPartialResults( |  | 
| 492     const rtc::scoped_refptr<RTCStatsReport>& partial_report) { |  | 
| 493   if (!signaling_thread_->IsCurrent()) { |  | 
| 494     invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |  | 
| 495         rtc::Bind(&RTCStatsCollector::AddPartialResults_s, |  | 
| 496                   rtc::scoped_refptr<RTCStatsCollector>(this), |  | 
| 497                   partial_report)); |  | 
| 498     return; |  | 
| 499   } |  | 
| 500   AddPartialResults_s(partial_report); |  | 
| 501 } |  | 
| 502 |  | 
| 503 void RTCStatsCollector::AddPartialResults_s( |  | 
| 504     rtc::scoped_refptr<RTCStatsReport> partial_report) { |  | 
| 505   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 506   RTC_DCHECK_GT(num_pending_partial_reports_, 0); |  | 
| 507   if (!partial_report_) |  | 
| 508     partial_report_ = partial_report; |  | 
| 509   else |  | 
| 510     partial_report_->TakeMembersFrom(partial_report); |  | 
| 511   --num_pending_partial_reports_; |  | 
| 512   if (!num_pending_partial_reports_) { |  | 
| 513     cache_timestamp_us_ = partial_report_timestamp_us_; |  | 
| 514     cached_report_ = partial_report_; |  | 
| 515     partial_report_ = nullptr; |  | 
| 516     DeliverCachedReport(); |  | 
| 517   } |  | 
| 518 } |  | 
| 519 |  | 
| 520 void RTCStatsCollector::DeliverCachedReport() { |  | 
| 521   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 522   RTC_DCHECK(!callbacks_.empty()); |  | 
| 523   RTC_DCHECK(cached_report_); |  | 
| 524   for (const rtc::scoped_refptr<RTCStatsCollectorCallback>& callback : |  | 
| 525        callbacks_) { |  | 
| 526     callback->OnStatsDelivered(cached_report_); |  | 
| 527   } |  | 
| 528   callbacks_.clear(); |  | 
| 529 } |  | 
| 530 |  | 
| 531 void RTCStatsCollector::ProduceCertificateStats_s( |  | 
| 532     int64_t timestamp_us, |  | 
| 533     const std::map<std::string, CertificateStatsPair>& transport_cert_stats, |  | 
| 534     RTCStatsReport* report) const { |  | 
| 535   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 536   for (const auto& transport_cert_stats_pair : transport_cert_stats) { |  | 
| 537     if (transport_cert_stats_pair.second.local) { |  | 
| 538       ProduceCertificateStatsFromSSLCertificateStats( |  | 
| 539           timestamp_us, *transport_cert_stats_pair.second.local.get(), report); |  | 
| 540     } |  | 
| 541     if (transport_cert_stats_pair.second.remote) { |  | 
| 542       ProduceCertificateStatsFromSSLCertificateStats( |  | 
| 543           timestamp_us, *transport_cert_stats_pair.second.remote.get(), report); |  | 
| 544     } |  | 
| 545   } |  | 
| 546 } |  | 
| 547 |  | 
| 548 void RTCStatsCollector::ProduceCodecStats_s( |  | 
| 549     int64_t timestamp_us, const MediaInfo& media_info, |  | 
| 550     RTCStatsReport* report) const { |  | 
| 551   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 552   // Audio |  | 
| 553   if (media_info.voice) { |  | 
| 554     // Inbound |  | 
| 555     for (const auto& pair : media_info.voice->receive_codecs) { |  | 
| 556       report->AddStats(CodecStatsFromRtpCodecParameters( |  | 
| 557           timestamp_us, true, true, pair.second)); |  | 
| 558     } |  | 
| 559     // Outbound |  | 
| 560     for (const auto& pair : media_info.voice->send_codecs) { |  | 
| 561       report->AddStats(CodecStatsFromRtpCodecParameters( |  | 
| 562           timestamp_us, false, true, pair.second)); |  | 
| 563     } |  | 
| 564   } |  | 
| 565   // Video |  | 
| 566   if (media_info.video) { |  | 
| 567     // Inbound |  | 
| 568     for (const auto& pair : media_info.video->receive_codecs) { |  | 
| 569       report->AddStats(CodecStatsFromRtpCodecParameters( |  | 
| 570           timestamp_us, true, false, pair.second)); |  | 
| 571     } |  | 
| 572     // Outbound |  | 
| 573     for (const auto& pair : media_info.video->send_codecs) { |  | 
| 574       report->AddStats(CodecStatsFromRtpCodecParameters( |  | 
| 575           timestamp_us, false, false, pair.second)); |  | 
| 576     } |  | 
| 577   } |  | 
| 578 } |  | 
| 579 |  | 
| 580 void RTCStatsCollector::ProduceDataChannelStats_s( |  | 
| 581     int64_t timestamp_us, RTCStatsReport* report) const { |  | 
| 582   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 583   for (const rtc::scoped_refptr<DataChannel>& data_channel : |  | 
| 584        pc_->sctp_data_channels()) { |  | 
| 585     std::unique_ptr<RTCDataChannelStats> data_channel_stats( |  | 
| 586         new RTCDataChannelStats( |  | 
| 587             "RTCDataChannel_" + rtc::ToString<>(data_channel->id()), |  | 
| 588             timestamp_us)); |  | 
| 589     data_channel_stats->label = data_channel->label(); |  | 
| 590     data_channel_stats->protocol = data_channel->protocol(); |  | 
| 591     data_channel_stats->datachannelid = data_channel->id(); |  | 
| 592     data_channel_stats->state = |  | 
| 593         DataStateToRTCDataChannelState(data_channel->state()); |  | 
| 594     data_channel_stats->messages_sent = data_channel->messages_sent(); |  | 
| 595     data_channel_stats->bytes_sent = data_channel->bytes_sent(); |  | 
| 596     data_channel_stats->messages_received = data_channel->messages_received(); |  | 
| 597     data_channel_stats->bytes_received = data_channel->bytes_received(); |  | 
| 598     report->AddStats(std::move(data_channel_stats)); |  | 
| 599   } |  | 
| 600 } |  | 
| 601 |  | 
| 602 void RTCStatsCollector::ProduceIceCandidateAndPairStats_s( |  | 
| 603       int64_t timestamp_us, const SessionStats& session_stats, |  | 
| 604       RTCStatsReport* report) const { |  | 
| 605   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 606   for (const auto& transport_stats : session_stats.transport_stats) { |  | 
| 607     for (const auto& channel_stats : transport_stats.second.channel_stats) { |  | 
| 608       std::string transport_id = RTCTransportStatsIDFromTransportChannel( |  | 
| 609           transport_stats.second.transport_name, channel_stats.component); |  | 
| 610       for (const cricket::ConnectionInfo& info : |  | 
| 611            channel_stats.connection_infos) { |  | 
| 612         std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats( |  | 
| 613             new RTCIceCandidatePairStats( |  | 
| 614                 RTCIceCandidatePairStatsIDFromConnectionInfo(info), |  | 
| 615                 timestamp_us)); |  | 
| 616 |  | 
| 617         candidate_pair_stats->transport_id = transport_id; |  | 
| 618         // TODO(hbos): There could be other candidates that are not paired with |  | 
| 619         // anything. We don't have a complete list. Local candidates come from |  | 
| 620         // Port objects, and prflx candidates (both local and remote) are only |  | 
| 621         // stored in candidate pairs. crbug.com/632723 |  | 
| 622         candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats( |  | 
| 623             timestamp_us, info.local_candidate, true, report); |  | 
| 624         candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats( |  | 
| 625             timestamp_us, info.remote_candidate, false, report); |  | 
| 626         // TODO(hbos): This writable is different than the spec. It goes to |  | 
| 627         // false after a certain amount of time without a response passes. |  | 
| 628         // crbug.com/633550 |  | 
| 629         candidate_pair_stats->writable = info.writable; |  | 
| 630         candidate_pair_stats->bytes_sent = |  | 
| 631             static_cast<uint64_t>(info.sent_total_bytes); |  | 
| 632         candidate_pair_stats->bytes_received = |  | 
| 633             static_cast<uint64_t>(info.recv_total_bytes); |  | 
| 634         // TODO(hbos): The |info.rtt| measurement is smoothed. It shouldn't be |  | 
| 635         // smoothed according to the spec. crbug.com/633550. See |  | 
| 636         // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-curr
     entrtt |  | 
| 637         candidate_pair_stats->current_rtt = |  | 
| 638             static_cast<double>(info.rtt) / rtc::kNumMillisecsPerSec; |  | 
| 639         candidate_pair_stats->requests_received = |  | 
| 640             static_cast<uint64_t>(info.recv_ping_requests); |  | 
| 641         candidate_pair_stats->requests_sent = |  | 
| 642             static_cast<uint64_t>(info.sent_ping_requests_total); |  | 
| 643         candidate_pair_stats->responses_received = |  | 
| 644             static_cast<uint64_t>(info.recv_ping_responses); |  | 
| 645         candidate_pair_stats->responses_sent = |  | 
| 646             static_cast<uint64_t>(info.sent_ping_responses); |  | 
| 647 |  | 
| 648         report->AddStats(std::move(candidate_pair_stats)); |  | 
| 649       } |  | 
| 650     } |  | 
| 651   } |  | 
| 652 } |  | 
| 653 |  | 
| 654 void RTCStatsCollector::ProduceMediaStreamAndTrackStats_s( |  | 
| 655     int64_t timestamp_us, RTCStatsReport* report) const { |  | 
| 656   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 657   ProduceMediaStreamAndTrackStats( |  | 
| 658       timestamp_us, pc_->local_streams(), true, report); |  | 
| 659   ProduceMediaStreamAndTrackStats( |  | 
| 660       timestamp_us, pc_->remote_streams(), false, report); |  | 
| 661 } |  | 
| 662 |  | 
| 663 void RTCStatsCollector::ProducePeerConnectionStats_s( |  | 
| 664     int64_t timestamp_us, RTCStatsReport* report) const { |  | 
| 665   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 666   std::unique_ptr<RTCPeerConnectionStats> stats( |  | 
| 667     new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us)); |  | 
| 668   stats->data_channels_opened = internal_record_.data_channels_opened; |  | 
| 669   stats->data_channels_closed = internal_record_.data_channels_closed; |  | 
| 670   report->AddStats(std::move(stats)); |  | 
| 671 } |  | 
| 672 |  | 
| 673 void RTCStatsCollector::ProduceRTPStreamStats_s( |  | 
| 674     int64_t timestamp_us, const SessionStats& session_stats, |  | 
| 675     const MediaInfo& media_info, RTCStatsReport* report) const { |  | 
| 676   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 677 |  | 
| 678   // Audio |  | 
| 679   if (media_info.voice) { |  | 
| 680     std::string transport_id = RTCTransportStatsIDFromBaseChannel( |  | 
| 681         session_stats.proxy_to_transport, *pc_->session()->voice_channel()); |  | 
| 682     RTC_DCHECK(!transport_id.empty()); |  | 
| 683     // Inbound |  | 
| 684     for (const cricket::VoiceReceiverInfo& voice_receiver_info : |  | 
| 685          media_info.voice->receivers) { |  | 
| 686       // TODO(nisse): SSRC == 0 currently means none. Delete check when that |  | 
| 687       // is fixed. |  | 
| 688       if (voice_receiver_info.ssrc() == 0) |  | 
| 689         continue; |  | 
| 690       std::unique_ptr<RTCInboundRTPStreamStats> inbound_audio( |  | 
| 691           new RTCInboundRTPStreamStats( |  | 
| 692               RTCInboundRTPStreamStatsIDFromSSRC( |  | 
| 693                   true, voice_receiver_info.ssrc()), |  | 
| 694               timestamp_us)); |  | 
| 695       SetInboundRTPStreamStatsFromVoiceReceiverInfo( |  | 
| 696           voice_receiver_info, inbound_audio.get()); |  | 
| 697       inbound_audio->transport_id = transport_id; |  | 
| 698       if (voice_receiver_info.codec_payload_type) { |  | 
| 699         inbound_audio->codec_id = |  | 
| 700             RTCCodecStatsIDFromDirectionMediaAndPayload( |  | 
| 701                 true, true, *voice_receiver_info.codec_payload_type); |  | 
| 702       } |  | 
| 703       report->AddStats(std::move(inbound_audio)); |  | 
| 704     } |  | 
| 705     // Outbound |  | 
| 706     for (const cricket::VoiceSenderInfo& voice_sender_info : |  | 
| 707          media_info.voice->senders) { |  | 
| 708       // TODO(nisse): SSRC == 0 currently means none. Delete check when that |  | 
| 709       // is fixed. |  | 
| 710       if (voice_sender_info.ssrc() == 0) |  | 
| 711         continue; |  | 
| 712       std::unique_ptr<RTCOutboundRTPStreamStats> outbound_audio( |  | 
| 713           new RTCOutboundRTPStreamStats( |  | 
| 714               RTCOutboundRTPStreamStatsIDFromSSRC( |  | 
| 715                   true, voice_sender_info.ssrc()), |  | 
| 716               timestamp_us)); |  | 
| 717       SetOutboundRTPStreamStatsFromVoiceSenderInfo( |  | 
| 718           voice_sender_info, outbound_audio.get()); |  | 
| 719       outbound_audio->transport_id = transport_id; |  | 
| 720       if (voice_sender_info.codec_payload_type) { |  | 
| 721         outbound_audio->codec_id = |  | 
| 722             RTCCodecStatsIDFromDirectionMediaAndPayload( |  | 
| 723                 false, true, *voice_sender_info.codec_payload_type); |  | 
| 724       } |  | 
| 725       report->AddStats(std::move(outbound_audio)); |  | 
| 726     } |  | 
| 727   } |  | 
| 728   // Video |  | 
| 729   if (media_info.video) { |  | 
| 730     std::string transport_id = RTCTransportStatsIDFromBaseChannel( |  | 
| 731         session_stats.proxy_to_transport, *pc_->session()->video_channel()); |  | 
| 732     RTC_DCHECK(!transport_id.empty()); |  | 
| 733     // Inbound |  | 
| 734     for (const cricket::VideoReceiverInfo& video_receiver_info : |  | 
| 735          media_info.video->receivers) { |  | 
| 736       // TODO(nisse): SSRC == 0 currently means none. Delete check when that |  | 
| 737       // is fixed. |  | 
| 738       if (video_receiver_info.ssrc() == 0) |  | 
| 739         continue; |  | 
| 740       std::unique_ptr<RTCInboundRTPStreamStats> inbound_video( |  | 
| 741           new RTCInboundRTPStreamStats( |  | 
| 742               RTCInboundRTPStreamStatsIDFromSSRC( |  | 
| 743                   false, video_receiver_info.ssrc()), |  | 
| 744               timestamp_us)); |  | 
| 745       SetInboundRTPStreamStatsFromVideoReceiverInfo( |  | 
| 746           video_receiver_info, inbound_video.get()); |  | 
| 747       inbound_video->transport_id = transport_id; |  | 
| 748       if (video_receiver_info.codec_payload_type) { |  | 
| 749         inbound_video->codec_id = |  | 
| 750             RTCCodecStatsIDFromDirectionMediaAndPayload( |  | 
| 751                 true, false, *video_receiver_info.codec_payload_type); |  | 
| 752       } |  | 
| 753       report->AddStats(std::move(inbound_video)); |  | 
| 754     } |  | 
| 755     // Outbound |  | 
| 756     for (const cricket::VideoSenderInfo& video_sender_info : |  | 
| 757          media_info.video->senders) { |  | 
| 758       // TODO(nisse): SSRC == 0 currently means none. Delete check when that |  | 
| 759       // is fixed. |  | 
| 760       if (video_sender_info.ssrc() == 0) |  | 
| 761         continue; |  | 
| 762       std::unique_ptr<RTCOutboundRTPStreamStats> outbound_video( |  | 
| 763           new RTCOutboundRTPStreamStats( |  | 
| 764               RTCOutboundRTPStreamStatsIDFromSSRC( |  | 
| 765                   false, video_sender_info.ssrc()), |  | 
| 766               timestamp_us)); |  | 
| 767       SetOutboundRTPStreamStatsFromVideoSenderInfo( |  | 
| 768           video_sender_info, outbound_video.get()); |  | 
| 769       outbound_video->transport_id = transport_id; |  | 
| 770       if (video_sender_info.codec_payload_type) { |  | 
| 771         outbound_video->codec_id = |  | 
| 772             RTCCodecStatsIDFromDirectionMediaAndPayload( |  | 
| 773                 false, false, *video_sender_info.codec_payload_type); |  | 
| 774       } |  | 
| 775       report->AddStats(std::move(outbound_video)); |  | 
| 776     } |  | 
| 777   } |  | 
| 778 } |  | 
| 779 |  | 
| 780 void RTCStatsCollector::ProduceTransportStats_s( |  | 
| 781     int64_t timestamp_us, const SessionStats& session_stats, |  | 
| 782     const std::map<std::string, CertificateStatsPair>& transport_cert_stats, |  | 
| 783     RTCStatsReport* report) const { |  | 
| 784   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 785   for (const auto& transport : session_stats.transport_stats) { |  | 
| 786     // Get reference to RTCP channel, if it exists. |  | 
| 787     std::string rtcp_transport_stats_id; |  | 
| 788     for (const auto& channel_stats : transport.second.channel_stats) { |  | 
| 789       if (channel_stats.component == |  | 
| 790           cricket::ICE_CANDIDATE_COMPONENT_RTCP) { |  | 
| 791         rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel( |  | 
| 792             transport.second.transport_name, channel_stats.component); |  | 
| 793         break; |  | 
| 794       } |  | 
| 795     } |  | 
| 796 |  | 
| 797     // Get reference to local and remote certificates of this transport, if they |  | 
| 798     // exist. |  | 
| 799     const auto& certificate_stats_it = transport_cert_stats.find( |  | 
| 800         transport.second.transport_name); |  | 
| 801     RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend()); |  | 
| 802     std::string local_certificate_id; |  | 
| 803     if (certificate_stats_it->second.local) { |  | 
| 804       local_certificate_id = RTCCertificateIDFromFingerprint( |  | 
| 805           certificate_stats_it->second.local->fingerprint); |  | 
| 806     } |  | 
| 807     std::string remote_certificate_id; |  | 
| 808     if (certificate_stats_it->second.remote) { |  | 
| 809       remote_certificate_id = RTCCertificateIDFromFingerprint( |  | 
| 810           certificate_stats_it->second.remote->fingerprint); |  | 
| 811     } |  | 
| 812 |  | 
| 813     // There is one transport stats for each channel. |  | 
| 814     for (const auto& channel_stats : transport.second.channel_stats) { |  | 
| 815       std::unique_ptr<RTCTransportStats> transport_stats( |  | 
| 816           new RTCTransportStats( |  | 
| 817               RTCTransportStatsIDFromTransportChannel( |  | 
| 818                   transport.second.transport_name, channel_stats.component), |  | 
| 819               timestamp_us)); |  | 
| 820       transport_stats->bytes_sent = 0; |  | 
| 821       transport_stats->bytes_received = 0; |  | 
| 822       transport_stats->active_connection = false; |  | 
| 823       for (const cricket::ConnectionInfo& info : |  | 
| 824            channel_stats.connection_infos) { |  | 
| 825         *transport_stats->bytes_sent += info.sent_total_bytes; |  | 
| 826         *transport_stats->bytes_received += info.recv_total_bytes; |  | 
| 827         if (info.best_connection) { |  | 
| 828           transport_stats->active_connection = true; |  | 
| 829           transport_stats->selected_candidate_pair_id = |  | 
| 830               RTCIceCandidatePairStatsIDFromConnectionInfo(info); |  | 
| 831         } |  | 
| 832       } |  | 
| 833       if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP && |  | 
| 834           !rtcp_transport_stats_id.empty()) { |  | 
| 835         transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id; |  | 
| 836       } |  | 
| 837       if (!local_certificate_id.empty()) |  | 
| 838         transport_stats->local_certificate_id = local_certificate_id; |  | 
| 839       if (!remote_certificate_id.empty()) |  | 
| 840         transport_stats->remote_certificate_id = remote_certificate_id; |  | 
| 841       report->AddStats(std::move(transport_stats)); |  | 
| 842     } |  | 
| 843   } |  | 
| 844 } |  | 
| 845 |  | 
| 846 std::map<std::string, RTCStatsCollector::CertificateStatsPair> |  | 
| 847 RTCStatsCollector::PrepareTransportCertificateStats( |  | 
| 848     const SessionStats& session_stats) const { |  | 
| 849   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 850   std::map<std::string, CertificateStatsPair> transport_cert_stats; |  | 
| 851   for (const auto& transport_stats : session_stats.transport_stats) { |  | 
| 852     CertificateStatsPair certificate_stats_pair; |  | 
| 853     rtc::scoped_refptr<rtc::RTCCertificate> local_certificate; |  | 
| 854     if (pc_->session()->GetLocalCertificate( |  | 
| 855         transport_stats.second.transport_name, &local_certificate)) { |  | 
| 856       certificate_stats_pair.local = |  | 
| 857           local_certificate->ssl_certificate().GetStats(); |  | 
| 858     } |  | 
| 859     std::unique_ptr<rtc::SSLCertificate> remote_certificate = |  | 
| 860         pc_->session()->GetRemoteSSLCertificate( |  | 
| 861             transport_stats.second.transport_name); |  | 
| 862     if (remote_certificate) { |  | 
| 863       certificate_stats_pair.remote = remote_certificate->GetStats(); |  | 
| 864     } |  | 
| 865     transport_cert_stats.insert( |  | 
| 866         std::make_pair(transport_stats.second.transport_name, |  | 
| 867                        std::move(certificate_stats_pair))); |  | 
| 868   } |  | 
| 869   return transport_cert_stats; |  | 
| 870 } |  | 
| 871 |  | 
| 872 RTCStatsCollector::MediaInfo RTCStatsCollector::PrepareMediaInfo( |  | 
| 873     const SessionStats& session_stats) const { |  | 
| 874   MediaInfo media_info; |  | 
| 875   if (pc_->session()->voice_channel()) { |  | 
| 876     cricket::VoiceMediaInfo voice_media_info; |  | 
| 877     if (pc_->session()->voice_channel()->GetStats(&voice_media_info)) { |  | 
| 878       media_info.voice = rtc::Optional<cricket::VoiceMediaInfo>( |  | 
| 879           std::move(voice_media_info)); |  | 
| 880     } |  | 
| 881   } |  | 
| 882   if (pc_->session()->video_channel()) { |  | 
| 883     cricket::VideoMediaInfo video_media_info; |  | 
| 884     if (pc_->session()->video_channel()->GetStats(&video_media_info)) { |  | 
| 885       media_info.video = rtc::Optional<cricket::VideoMediaInfo>( |  | 
| 886           std::move(video_media_info)); |  | 
| 887     } |  | 
| 888   } |  | 
| 889   return media_info; |  | 
| 890 } |  | 
| 891 |  | 
| 892 void RTCStatsCollector::OnDataChannelCreated(DataChannel* channel) { |  | 
| 893   channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened); |  | 
| 894   channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed); |  | 
| 895 } |  | 
| 896 |  | 
| 897 void RTCStatsCollector::OnDataChannelOpened(DataChannel* channel) { |  | 
| 898   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 899   bool result = internal_record_.opened_data_channels.insert( |  | 
| 900       reinterpret_cast<uintptr_t>(channel)).second; |  | 
| 901   ++internal_record_.data_channels_opened; |  | 
| 902   RTC_DCHECK(result); |  | 
| 903 } |  | 
| 904 |  | 
| 905 void RTCStatsCollector::OnDataChannelClosed(DataChannel* channel) { |  | 
| 906   RTC_DCHECK(signaling_thread_->IsCurrent()); |  | 
| 907   // Only channels that have been fully opened (and have increased the |  | 
| 908   // |data_channels_opened_| counter) increase the closed counter. |  | 
| 909   if (internal_record_.opened_data_channels.find( |  | 
| 910           reinterpret_cast<uintptr_t>(channel)) != |  | 
| 911       internal_record_.opened_data_channels.end()) { |  | 
| 912     ++internal_record_.data_channels_closed; |  | 
| 913   } |  | 
| 914 } |  | 
| 915 |  | 
| 916 const char* CandidateTypeToRTCIceCandidateTypeForTesting( |  | 
| 917     const std::string& type) { |  | 
| 918   return CandidateTypeToRTCIceCandidateType(type); |  | 
| 919 } |  | 
| 920 |  | 
| 921 const char* DataStateToRTCDataChannelStateForTesting( |  | 
| 922     DataChannelInterface::DataState state) { |  | 
| 923   return DataStateToRTCDataChannelState(state); |  | 
| 924 } |  | 
| 925 |  | 
| 926 }  // namespace webrtc |  | 
| OLD | NEW | 
|---|