Chromium Code Reviews| Index: webrtc/api/rtcstatscollector.cc |
| diff --git a/webrtc/api/rtcstatscollector.cc b/webrtc/api/rtcstatscollector.cc |
| index cf97057c1b6884595618b3083beeacad5727f93d..c54619ef5d189e77723c0f540c79a73977668bd3 100644 |
| --- a/webrtc/api/rtcstatscollector.cc |
| +++ b/webrtc/api/rtcstatscollector.cc |
| @@ -29,6 +29,11 @@ namespace webrtc { |
| namespace { |
| +// If the track is associated with multiple SSRCs, the |uint32_t| is the first |
| +// one in the group, used as an identifier for that group. The SSRCs are listed |
| +// in ||Voice/Video][Sender/Receiver]Info::ssrcs()|. |
| +typedef std::map<MediaStreamTrackInterface*, uint32_t> TracksToSsrcs; |
|
pthatcher1
2017/01/03 19:29:00
I'd prefer you just use std::map<MediaStreamTrackI
|
| + |
| std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) { |
| return "RTCCertificate_" + fingerprint; |
| } |
| @@ -54,8 +59,9 @@ std::string RTCIceCandidatePairStatsIDFromConnectionInfo( |
| } |
| std::string RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface( |
| - const MediaStreamTrackInterface& track) { |
| - return "RTCMediaStreamTrack_" + track.id(); |
| + const MediaStreamTrackInterface& track, bool is_local) { |
| + return (is_local ? "RTCMediaStreamTrack_local_" : |
| + "RTCMediaStreamTrack_remote_") + track.id(); |
| } |
| std::string RTCTransportStatsIDFromTransportChannel( |
| @@ -280,10 +286,73 @@ const std::string& ProduceIceCandidateStats( |
| return stats->id(); |
| } |
| +TracksToSsrcs GetTracksToSsrcs( |
| + const std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders) { |
| + TracksToSsrcs tracks_to_ssrcs; |
|
pthatcher1
2017/01/03 19:28:59
I think a better name would be "track_to_ssrc".
|
| + for (const rtc::scoped_refptr<RtpSenderInterface>& sender : senders) { |
| + if (!sender->track()) |
| + continue; |
|
pthatcher1
2017/01/03 19:28:59
{}s please
|
| + if (sender->ssrc() != 0) { |
|
pthatcher1
2017/01/03 19:28:59
Why not do another early continue?
if (!sender->s
|
| + // TODO(hbos): What if multiple |RtpSenderInterface| have the same track |
| + // attached yielding multiple SSRCs groups? Only one of them would |
| + // currently be used. crbug.com/659137 |
|
hta-webrtc
2017/01/02 15:29:46
This is supposed to be allowed, and the track is t
|
| + // TODO(hbos): What if |GetParameters().encodings.size() > 1| yields |
| + // multiple SSRC groups per sender? crbug.com/659137 |
| + tracks_to_ssrcs[sender->track().get()] = sender->ssrc(); |
|
hta-webrtc
2017/01/02 15:29:46
If you DCHECK(!tracks_to_ssrcs.is_member(sender->t
|
| + } |
| + } |
| + return tracks_to_ssrcs; |
| +} |
| +// TODO(hbos,deadbeef): With template argument |T| for both |RtpSenderInterface| |
| +// and |RtpReceiverInterface| this function should be able to cover both sender |
| +// and receiver cases. But the |RtpSenderInterface| needs to be updated first, |
| +// when this comment was written it could have an |ssrc()| and still not a value |
| +// for |GetParameters().encodings[0].ssrc|. |
| +TracksToSsrcs GetTracksToSsrcs( |
| + const std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers) { |
| + TracksToSsrcs tracks_to_ssrcs; |
| + for (const rtc::scoped_refptr<RtpReceiverInterface>& receiver : receivers) { |
| + if (!receiver->track()) |
|
Taylor Brandstetter
2017/01/04 00:36:56
A receiver should always have a track; you can DCH
|
| + continue; |
|
pthatcher1
2017/01/03 19:29:00
{}s please
|
| + RTC_DCHECK( |
| + tracks_to_ssrcs.find(receiver->track().get()) == tracks_to_ssrcs.end()); |
| + RtpParameters parameters = receiver->GetParameters(); |
| + if (parameters.encodings.empty()) |
| + continue; |
|
pthatcher1
2017/01/03 19:28:59
{}s please
|
| + RTC_DCHECK_EQ(1u, parameters.encodings.size()); |
|
pthatcher1
2017/01/03 19:29:00
This is going to explode as soon as we implement G
Taylor Brandstetter
2017/01/04 00:36:56
In that case the DCHECK would be redundant since "
|
| + rtc::Optional<uint32_t> ssrc = parameters.encodings[0].ssrc; |
| + if (ssrc) |
| + tracks_to_ssrcs[receiver->track().get()] = *ssrc; |
|
pthatcher1
2017/01/03 19:28:59
{}s please
|
| + } |
| + return tracks_to_ssrcs; |
| +} |
| + |
| +// |T| can be any |MediaSenderInfo| or |MediaReceiverInfo|. |
| +template<typename T> |
| +const T* GetMediaInfoFromSsrc(const std::vector<T>& infos, uint32_t ssrc) { |
|
pthatcher1
2017/01/03 19:28:59
Sounds more like "BySsrc" than "FromSsrc"
Or why
|
| + for (const T& info : infos) { |
| + if (info.ssrc() == ssrc) |
| + return &info; |
|
pthatcher1
2017/01/03 19:28:59
{}s please
|
| + } |
| + return nullptr; |
| +} |
| + |
| +std::vector<std::string> StringSsrcsFromSsrcs( |
| + const std::vector<uint32_t>& ssrcs) { |
|
pthatcher1
2017/01/03 19:28:59
Why not just call this ToStrings? You could even
|
| + std::vector<std::string> string_ssrcs; |
| + for (uint32_t ssrc : ssrcs) { |
| + string_ssrcs.push_back(rtc::ToString<>(ssrc)); |
| + } |
| + return string_ssrcs; |
| +} |
| + |
| void ProduceMediaStreamAndTrackStats( |
| int64_t timestamp_us, |
| rtc::scoped_refptr<StreamCollectionInterface> streams, |
| bool is_local, |
| + const TracksToSsrcs& tracks_to_ssrcs, |
| + const rtc::Optional<cricket::VoiceMediaInfo>& voice_info, |
| + const rtc::Optional<cricket::VideoMediaInfo>& video_info, |
| RTCStatsReport* report) { |
| // TODO(hbos): When "AddTrack" is implemented we should iterate tracks to |
| // find which streams exist, not iterate streams to find tracks. |
| @@ -306,17 +375,33 @@ void ProduceMediaStreamAndTrackStats( |
| for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track : |
| stream->GetAudioTracks()) { |
| std::string id = RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface( |
| - *audio_track.get()); |
| - if (report->Get(id)) { |
| - // Skip track, stats already exist for it. |
| - continue; |
| - } |
|
pthatcher1
2017/01/03 19:29:00
So why don't we skip this any more?
|
| + *audio_track.get(), is_local); |
| std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats( |
| new RTCMediaStreamTrackStats(id, timestamp_us)); |
| stream_stats->track_ids->push_back(audio_track_stats->id()); |
| SetMediaStreamTrackStatsFromMediaStreamTrackInterface( |
| *audio_track.get(), |
| audio_track_stats.get()); |
| + TracksToSsrcs::const_iterator it = tracks_to_ssrcs.find( |
| + audio_track.get()); |
| + if (it != tracks_to_ssrcs.end() && voice_info) { |
| + uint32_t ssrc = it->second; |
| + if (is_local) { |
| + const cricket::VoiceSenderInfo* sender_info = |
| + GetMediaInfoFromSsrc(voice_info->senders, ssrc); |
| + if (sender_info) { |
| + audio_track_stats->ssrc_ids = StringSsrcsFromSsrcs( |
| + sender_info->ssrcs()); |
| + } |
| + } else { |
| + const cricket::VoiceReceiverInfo* receiver_info = |
| + GetMediaInfoFromSsrc(voice_info->receivers, ssrc); |
| + if (receiver_info) { |
| + audio_track_stats->ssrc_ids = StringSsrcsFromSsrcs( |
| + receiver_info->ssrcs()); |
| + } |
| + } |
| + } |
| audio_track_stats->remote_source = !is_local; |
| audio_track_stats->detached = false; |
| int signal_level; |
| @@ -344,17 +429,33 @@ void ProduceMediaStreamAndTrackStats( |
| for (const rtc::scoped_refptr<VideoTrackInterface>& video_track : |
| stream->GetVideoTracks()) { |
| std::string id = RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface( |
| - *video_track.get()); |
| - if (report->Get(id)) { |
| - // Skip track, stats already exist for it. |
| - continue; |
| - } |
| + *video_track.get(), is_local); |
| std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats( |
| new RTCMediaStreamTrackStats(id, timestamp_us)); |
| stream_stats->track_ids->push_back(video_track_stats->id()); |
| SetMediaStreamTrackStatsFromMediaStreamTrackInterface( |
| *video_track.get(), |
| video_track_stats.get()); |
| + TracksToSsrcs::const_iterator it = tracks_to_ssrcs.find( |
| + video_track.get()); |
| + if (it != tracks_to_ssrcs.end() && video_info) { |
| + uint32_t ssrc = it->second; |
| + if (is_local) { |
| + const cricket::VideoSenderInfo* sender_info = |
| + GetMediaInfoFromSsrc(video_info->senders, ssrc); |
| + if (sender_info) { |
| + video_track_stats->ssrc_ids = StringSsrcsFromSsrcs( |
| + sender_info->ssrcs()); |
| + } |
| + } else { |
| + const cricket::VideoReceiverInfo* receiver_info = |
| + GetMediaInfoFromSsrc(video_info->receivers, ssrc); |
| + if (receiver_info) { |
| + video_track_stats->ssrc_ids = StringSsrcsFromSsrcs( |
| + receiver_info->ssrcs()); |
| + } |
| + } |
| + } |
| video_track_stats->remote_source = !is_local; |
| video_track_stats->detached = false; |
| if (video_track->GetSource()) { |
| @@ -427,9 +528,6 @@ void RTCStatsCollector::GetStatsReport( |
| num_pending_partial_reports_ = 3; |
| partial_report_timestamp_us_ = cache_now_us; |
| - invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |
| - rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnSignalingThread, |
| - rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |
| // TODO(hbos): No stats are gathered by |
| // |ProducePartialResultsOnWorkerThread|, remove it. |
| @@ -437,8 +535,9 @@ void RTCStatsCollector::GetStatsReport( |
| rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnWorkerThread, |
| rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |
| - // Prepare |channel_names_| and |media_info_| for use in |
| - // |ProducePartialResultsOnNetworkThread|. |
| + // Prepare |channel_names_| and |media_info_|. These are read in |
|
hta-webrtc
2017/01/02 15:29:46
Do you mean channel_name_pairs_?
|
| + // |ProducePartialResultsOnNetworkThread|, and |media_info_| is also used in |
| + // |ProducePartialResultsOnSignalingThread|. |
| channel_name_pairs_.reset(new ChannelNamePairs()); |
| if (pc_->session()->voice_channel()) { |
| channel_name_pairs_->voice = rtc::Optional<ChannelNamePair>( |
| @@ -459,6 +558,7 @@ void RTCStatsCollector::GetStatsReport( |
| invoker_.AsyncInvoke<void>(RTC_FROM_HERE, network_thread_, |
| rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread, |
| rtc::scoped_refptr<RTCStatsCollector>(this), timestamp_us)); |
| + ProducePartialResultsOnSignalingThread(timestamp_us); |
|
pthatcher1
2017/01/03 19:28:59
Should you DCHECK that you're on the signaling thr
Taylor Brandstetter
2017/01/04 00:36:56
ProducePartialResultsOnSignalingThread does this.
|
| } |
| } |
| @@ -702,9 +802,21 @@ void RTCStatsCollector::ProduceMediaStreamAndTrackStats_s( |
| int64_t timestamp_us, RTCStatsReport* report) const { |
| RTC_DCHECK(signaling_thread_->IsCurrent()); |
| ProduceMediaStreamAndTrackStats( |
| - timestamp_us, pc_->local_streams(), true, report); |
| + timestamp_us, |
| + pc_->local_streams(), |
| + true, |
| + GetTracksToSsrcs(pc_->GetSenders()), |
| + media_info_->voice, |
| + media_info_->video, |
| + report); |
| ProduceMediaStreamAndTrackStats( |
| - timestamp_us, pc_->remote_streams(), false, report); |
| + timestamp_us, |
| + pc_->remote_streams(), |
| + false, |
| + GetTracksToSsrcs(pc_->GetReceivers()), |
| + media_info_->voice, |
| + media_info_->video, |
| + report); |
| } |
| void RTCStatsCollector::ProducePeerConnectionStats_s( |