 Chromium Code Reviews
 Chromium Code Reviews Issue 2456463002:
  RTCOutboundRTPStreamStats added.  (Closed)
    
  
    Issue 2456463002:
  RTCOutboundRTPStreamStats added.  (Closed) 
  | Index: webrtc/api/rtcstatscollector.cc | 
| diff --git a/webrtc/api/rtcstatscollector.cc b/webrtc/api/rtcstatscollector.cc | 
| index 1c87dacbb16beb037e13f9eecbcf86503b576de9..45c3c403aedacaa5799f4f221210cccebe099ffb 100644 | 
| --- a/webrtc/api/rtcstatscollector.cc | 
| +++ b/webrtc/api/rtcstatscollector.cc | 
| @@ -17,6 +17,8 @@ | 
| #include "webrtc/api/peerconnection.h" | 
| #include "webrtc/api/webrtcsession.h" | 
| #include "webrtc/base/checks.h" | 
| +#include "webrtc/base/timeutils.h" | 
| +#include "webrtc/media/base/mediachannel.h" | 
| #include "webrtc/p2p/base/candidate.h" | 
| #include "webrtc/p2p/base/p2pconstants.h" | 
| #include "webrtc/p2p/base/port.h" | 
| @@ -41,6 +43,21 @@ std::string RTCTransportStatsIDFromTransportChannel( | 
| rtc::ToString<>(channel_component); | 
| } | 
| +std::string RTCTransportStatsIDFromBaseChannel( | 
| + const ProxyTransportMap& proxy_to_transport, | 
| + const cricket::BaseChannel& base_channel) { | 
| + auto proxy_it = proxy_to_transport.find(base_channel.content_name()); | 
| + if (proxy_it == proxy_to_transport.cend()) | 
| + return ""; | 
| + return RTCTransportStatsIDFromTransportChannel( | 
| + proxy_it->second, cricket::ICE_CANDIDATE_COMPONENT_RTP); | 
| +} | 
| + | 
| +std::string RTCOutboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) { | 
| + return audio ? "RTCOutboundRTPAudioStream_" + rtc::ToString<>(ssrc) | 
| + : "RTCOutboundRTPVideoStream_" + rtc::ToString<>(ssrc); | 
| +} | 
| + | 
| const char* CandidateTypeToRTCIceCandidateType(const std::string& type) { | 
| if (type == cricket::LOCAL_PORT_TYPE) | 
| return RTCIceCandidateType::kHost; | 
| @@ -71,6 +88,49 @@ const char* DataStateToRTCDataChannelState( | 
| } | 
| } | 
| +void SetOutboundRTPStreamStatsFromMediaSenderInfo( | 
| + const cricket::MediaSenderInfo& media_sender_info, | 
| + RTCOutboundRTPStreamStats* outbound_stats) { | 
| + RTC_DCHECK(outbound_stats); | 
| + outbound_stats->ssrc = rtc::ToString<>(media_sender_info.ssrc()); | 
| + // TODO(hbos): Support the remote case. crbug.com/657856 | 
| + outbound_stats->is_remote = false; | 
| + // TODO(hbos): Set |codec_id| when we have |RTCCodecStats|. Maybe relevant: | 
| + // |media_sender_info.codec_name|. crbug.com/657854, 657856, 659117 | 
| + outbound_stats->packets_sent = | 
| + static_cast<uint32_t>(media_sender_info.packets_sent); | 
| + outbound_stats->bytes_sent = | 
| + static_cast<uint64_t>(media_sender_info.bytes_sent); | 
| + outbound_stats->round_trip_time = | 
| + static_cast<double>(media_sender_info.rtt_ms) / rtc::kNumMillisecsPerSec; | 
| +} | 
| + | 
| +void SetOutboundRTPStreamStatsFromVoiceSenderInfo( | 
| + const cricket::VoiceSenderInfo& voice_sender_info, | 
| + RTCOutboundRTPStreamStats* outbound_stats) { | 
| + SetOutboundRTPStreamStatsFromMediaSenderInfo( | 
| + voice_sender_info, outbound_stats); | 
| + outbound_stats->media_type = "audio"; | 
| + // |fir_count|, |pli_count|, |nack_count| and |sli_count| are only valid for | 
| + // video and are purposefully left undefined for audio. | 
| 
hbos
2016/10/26 10:26:11
Is this true? Even for NACK?
FIR and SLI are docu
 
Taylor Brandstetter
2016/10/27 21:44:36
NACK seems relevant to audio, PLI doesn't. I'll ma
 
hbos
2016/10/28 09:42:37
Acknowledged.
 | 
| +} | 
| + | 
| +void SetOutboundRTPStreamStatsFromVideoSenderInfo( | 
| + const cricket::VideoSenderInfo& video_sender_info, | 
| + RTCOutboundRTPStreamStats* outbound_stats) { | 
| + SetOutboundRTPStreamStatsFromMediaSenderInfo( | 
| + video_sender_info, outbound_stats); | 
| + outbound_stats->media_type = "video"; | 
| + outbound_stats->fir_count = | 
| + static_cast<uint32_t>(video_sender_info.firs_rcvd); | 
| + outbound_stats->pli_count = | 
| + static_cast<uint32_t>(video_sender_info.plis_rcvd); | 
| + outbound_stats->nack_count = | 
| + static_cast<uint32_t>(video_sender_info.nacks_rcvd); | 
| + outbound_stats->target_bitrate = | 
| + static_cast<double>(video_sender_info.preferred_bitrate); | 
| 
hbos
2016/10/26 10:26:11
Is this the correct value? There is also bandwidth
 
Taylor Brandstetter
2016/10/27 21:44:36
I came to the same conclusion; it should be target
 
hbos
2016/10/28 09:42:37
Done. Note that this means that all video-RTCOutbo
 
Taylor Brandstetter
2016/10/28 17:31:34
Wait, that doesn't seem right. I didn't realize ta
 
hbos
2016/10/31 09:21:01
That will be easy to surface but I'll do it in a s
 | 
| +} | 
| + | 
| } // namespace | 
| rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create( | 
| @@ -140,7 +200,8 @@ void RTCStatsCollector::ClearCachedStatsReport() { | 
| void RTCStatsCollector::ProducePartialResultsOnSignalingThread( | 
| int64_t timestamp_us) { | 
| RTC_DCHECK(signaling_thread_->IsCurrent()); | 
| - rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); | 
| + rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( | 
| + timestamp_us); | 
| SessionStats session_stats; | 
| if (pc_->session()->GetTransportStats(&session_stats)) { | 
| @@ -151,6 +212,8 @@ void RTCStatsCollector::ProducePartialResultsOnSignalingThread( | 
| timestamp_us, transport_cert_stats, report.get()); | 
| ProduceIceCandidateAndPairStats_s( | 
| timestamp_us, session_stats, report.get()); | 
| + ProduceRTPStreamStats_s( | 
| + timestamp_us, session_stats, report.get()); | 
| ProduceTransportStats_s( | 
| timestamp_us, session_stats, transport_cert_stats, report.get()); | 
| } | 
| @@ -163,9 +226,16 @@ void RTCStatsCollector::ProducePartialResultsOnSignalingThread( | 
| void RTCStatsCollector::ProducePartialResultsOnWorkerThread( | 
| int64_t timestamp_us) { | 
| RTC_DCHECK(worker_thread_->IsCurrent()); | 
| - rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); | 
| + rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( | 
| + timestamp_us); | 
| // TODO(hbos): Gather stats on worker thread. | 
| + // pc_->session()'s channels are owned by the signaling thread but there are | 
| + // some stats that are gathered on the worker thread. Instead of a synchronous | 
| + // invoke on "s->w" we could to the "w" work here asynchronously if it wasn't | 
| + // for the ownership issue. Synchronous invokes in other places makes it | 
| + // difficult to introduce locks without introducing deadlocks and the channels | 
| + // are not reference counted. | 
| AddPartialResults(report); | 
| } | 
| @@ -173,9 +243,16 @@ void RTCStatsCollector::ProducePartialResultsOnWorkerThread( | 
| void RTCStatsCollector::ProducePartialResultsOnNetworkThread( | 
| int64_t timestamp_us) { | 
| RTC_DCHECK(network_thread_->IsCurrent()); | 
| - rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); | 
| + rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create( | 
| + timestamp_us); | 
| // TODO(hbos): Gather stats on network thread. | 
| + // pc_->session()'s channels are owned by the signaling thread but there are | 
| + // some stats that are gathered on the network thread. Instead of a | 
| + // synchronous invoke on "s->n" we could to the "n" work here asynchronously | 
| + // if it wasn't for the ownership issue. Synchronous invokes in other places | 
| + // makes it difficult to introduce locks without introducing deadlocks and the | 
| + // channels are not reference counted. | 
| AddPartialResults(report); | 
| } | 
| @@ -312,7 +389,7 @@ void RTCStatsCollector::ProduceIceCandidateAndPairStats_s( | 
| // smoothed according to the spec. crbug.com/633550. See | 
| // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-currentrtt | 
| candidate_pair_stats->current_rtt = | 
| - static_cast<double>(info.rtt) / 1000.0; | 
| + static_cast<double>(info.rtt) / rtc::kNumMillisecsPerSec; | 
| candidate_pair_stats->requests_sent = | 
| static_cast<uint64_t>(info.sent_ping_requests_total); | 
| candidate_pair_stats->responses_received = | 
| @@ -376,6 +453,63 @@ void RTCStatsCollector::ProducePeerConnectionStats_s( | 
| report->AddStats(std::move(stats)); | 
| } | 
| +void RTCStatsCollector::ProduceRTPStreamStats_s( | 
| + int64_t timestamp_us, const SessionStats& session_stats, | 
| + RTCStatsReport* report) const { | 
| + RTC_DCHECK(signaling_thread_->IsCurrent()); | 
| + | 
| + // Audio | 
| + if (pc_->session()->voice_channel()) { | 
| + cricket::VoiceMediaInfo voice_media_info; | 
| + if (pc_->session()->voice_channel()->GetStats(&voice_media_info)) { | 
| + std::string transport_id = RTCTransportStatsIDFromBaseChannel( | 
| + session_stats.proxy_to_transport, *pc_->session()->voice_channel()); | 
| + for (const cricket::VoiceSenderInfo& voice_sender_info : | 
| + voice_media_info.senders) { | 
| + // TODO(nisse): SSRC == 0 currently means none. Delete check when that | 
| + // is fixed. | 
| + if (voice_sender_info.ssrc() == 0) | 
| + continue; | 
| + std::unique_ptr<RTCOutboundRTPStreamStats> outbound_audio( | 
| + new RTCOutboundRTPStreamStats( | 
| + RTCOutboundRTPStreamStatsIDFromSSRC( | 
| + true, voice_sender_info.ssrc()), | 
| + timestamp_us)); | 
| + SetOutboundRTPStreamStatsFromVoiceSenderInfo( | 
| + voice_sender_info, outbound_audio.get()); | 
| + if (!transport_id.empty()) | 
| + outbound_audio->transport_id = transport_id; | 
| + report->AddStats(std::move(outbound_audio)); | 
| + } | 
| + } | 
| + } | 
| + // Video | 
| + if (pc_->session()->video_channel()) { | 
| + cricket::VideoMediaInfo video_media_info; | 
| + if (pc_->session()->video_channel()->GetStats(&video_media_info)) { | 
| + std::string transport_id = RTCTransportStatsIDFromBaseChannel( | 
| + session_stats.proxy_to_transport, *pc_->session()->video_channel()); | 
| + for (const cricket::VideoSenderInfo& video_sender_info : | 
| + video_media_info.senders) { | 
| + // TODO(nisse): SSRC == 0 currently means none. Delete check when that | 
| + // is fixed. | 
| + if (video_sender_info.ssrc() == 0) | 
| + continue; | 
| + std::unique_ptr<RTCOutboundRTPStreamStats> outbound_video( | 
| + new RTCOutboundRTPStreamStats( | 
| + RTCOutboundRTPStreamStatsIDFromSSRC( | 
| + false, video_sender_info.ssrc()), | 
| + timestamp_us)); | 
| + SetOutboundRTPStreamStatsFromVideoSenderInfo( | 
| + video_sender_info, outbound_video.get()); | 
| + if (!transport_id.empty()) | 
| + outbound_video->transport_id = transport_id; | 
| + report->AddStats(std::move(outbound_video)); | 
| + } | 
| + } | 
| + } | 
| +} | 
| + | 
| void RTCStatsCollector::ProduceTransportStats_s( | 
| int64_t timestamp_us, const SessionStats& session_stats, | 
| const std::map<std::string, CertificateStatsPair>& transport_cert_stats, |