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( |