Prepare StatsCollector to work with RtpTransceivers
This changes the StatsCollector to handle stats from multiple MediaChannels of the same type (e.g., audio or video). Bug: webrtc:8764 Change-Id: I91ba50d10cf469420189a311acdafbf6f78579b2 Reviewed-on: https://webrtc-review.googlesource.com/49560 Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org> Commit-Queue: Steve Anton <steveanton@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22009}
This commit is contained in:
@ -4388,23 +4388,6 @@ bool PeerConnection::GetSslRole(const std::string& content_name,
|
||||
role);
|
||||
}
|
||||
|
||||
// TODO(steveanton): Eventually it'd be nice to store the channels as a single
|
||||
// vector of BaseChannel pointers instead of separate voice and video channel
|
||||
// vectors. At that point, this will become a simple getter.
|
||||
std::vector<cricket::BaseChannel*> PeerConnection::Channels() const {
|
||||
std::vector<cricket::BaseChannel*> channels;
|
||||
if (voice_channel()) {
|
||||
channels.push_back(voice_channel());
|
||||
}
|
||||
if (video_channel()) {
|
||||
channels.push_back(video_channel());
|
||||
}
|
||||
if (rtp_data_channel_) {
|
||||
channels.push_back(rtp_data_channel_);
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
|
||||
void PeerConnection::SetSessionError(SessionError error,
|
||||
const std::string& error_desc) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
|
||||
@ -225,7 +225,7 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
|
||||
std::vector<
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
||||
GetTransceiversForTesting() const override {
|
||||
GetTransceiversInternal() const override {
|
||||
return transceivers_;
|
||||
}
|
||||
|
||||
@ -723,9 +723,6 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
return transport_controller_.get();
|
||||
}
|
||||
|
||||
// Return all managed, non-null channels.
|
||||
std::vector<cricket::BaseChannel*> Channels() const;
|
||||
|
||||
// Non-const versions of local_description()/remote_description(), for use
|
||||
// internally.
|
||||
SessionDescriptionInterface* mutable_local_description() {
|
||||
|
||||
@ -76,8 +76,7 @@ class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper {
|
||||
}
|
||||
|
||||
cricket::VoiceChannel* voice_channel() {
|
||||
auto transceivers =
|
||||
GetInternalPeerConnection()->GetTransceiversForTesting();
|
||||
auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
|
||||
for (auto transceiver : transceivers) {
|
||||
if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
|
||||
return static_cast<cricket::VoiceChannel*>(
|
||||
@ -96,8 +95,7 @@ class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper {
|
||||
}
|
||||
|
||||
cricket::VideoChannel* video_channel() {
|
||||
auto transceivers =
|
||||
GetInternalPeerConnection()->GetTransceiversForTesting();
|
||||
auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
|
||||
for (auto transceiver : transceivers) {
|
||||
if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
|
||||
return static_cast<cricket::VideoChannel*>(
|
||||
|
||||
@ -196,7 +196,7 @@ class PeerConnectionIceBaseTest : public ::testing::Test {
|
||||
static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
|
||||
pc_wrapper_ptr->pc());
|
||||
PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
|
||||
for (auto transceiver : pc->GetTransceiversForTesting()) {
|
||||
for (auto transceiver : pc->GetTransceiversInternal()) {
|
||||
if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
|
||||
cricket::BaseChannel* channel = transceiver->internal()->channel();
|
||||
if (channel) {
|
||||
|
||||
@ -36,14 +36,13 @@ class PeerConnectionInternal : public PeerConnectionInterface {
|
||||
// Returns true if we were the initial offerer.
|
||||
virtual bool initial_offerer() const = 0;
|
||||
|
||||
// TODO(steveanton): Remove these.
|
||||
// TODO(steveanton): Remove these and replace with GetTransceiversInternal.
|
||||
virtual cricket::VoiceChannel* voice_channel() const = 0;
|
||||
virtual cricket::VideoChannel* video_channel() const = 0;
|
||||
|
||||
// Exposed for tests.
|
||||
virtual std::vector<
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
||||
GetTransceiversForTesting() const = 0;
|
||||
GetTransceiversInternal() const = 0;
|
||||
|
||||
// Get the id used as a media stream track's "id" field from ssrc.
|
||||
virtual bool GetLocalTrackIdBySsrc(uint32_t ssrc, std::string* track_id) = 0;
|
||||
|
||||
@ -569,8 +569,7 @@ StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
|
||||
// the same thread (this class has no locks right now).
|
||||
ExtractSessionInfo();
|
||||
ExtractBweInfo();
|
||||
ExtractVoiceInfo();
|
||||
ExtractVideoInfo(level);
|
||||
ExtractMediaInfo();
|
||||
ExtractSenderInfo();
|
||||
ExtractDataInfo();
|
||||
UpdateTrackReports();
|
||||
@ -846,59 +845,100 @@ void StatsCollector::ExtractBweInfo() {
|
||||
ExtractStats(bwe_info, stats_gathering_started_, report);
|
||||
}
|
||||
|
||||
void StatsCollector::ExtractVoiceInfo() {
|
||||
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
||||
namespace {
|
||||
|
||||
if (!pc_->voice_channel()) {
|
||||
return;
|
||||
}
|
||||
cricket::VoiceMediaInfo voice_info;
|
||||
if (!pc_->voice_channel()->GetStats(&voice_info)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to get voice channel stats.";
|
||||
return;
|
||||
struct VoiceChannelStatsInfo {
|
||||
std::string transport_name;
|
||||
cricket::VoiceMediaChannel* voice_media_channel;
|
||||
cricket::VoiceMediaInfo voice_media_info;
|
||||
};
|
||||
|
||||
struct VideoChannelStatsInfo {
|
||||
std::string transport_name;
|
||||
cricket::VideoMediaChannel* video_media_channel;
|
||||
cricket::VideoMediaInfo video_media_info;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void StatsCollector::ExtractMediaInfo() {
|
||||
RTC_DCHECK_RUN_ON(pc_->signaling_thread());
|
||||
|
||||
std::vector<VoiceChannelStatsInfo> voice_channel_infos;
|
||||
std::vector<VideoChannelStatsInfo> video_channel_infos;
|
||||
|
||||
{
|
||||
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
||||
for (auto transceiver : pc_->GetTransceiversInternal()) {
|
||||
if (!transceiver->internal()->channel()) {
|
||||
continue;
|
||||
}
|
||||
cricket::MediaType media_type = transceiver->internal()->media_type();
|
||||
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
|
||||
auto* voice_channel = static_cast<cricket::VoiceChannel*>(
|
||||
transceiver->internal()->channel());
|
||||
voice_channel_infos.emplace_back();
|
||||
VoiceChannelStatsInfo& info = voice_channel_infos.back();
|
||||
info.transport_name = voice_channel->transport_name();
|
||||
info.voice_media_channel = voice_channel->media_channel();
|
||||
} else {
|
||||
RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
|
||||
auto* video_channel = static_cast<cricket::VideoChannel*>(
|
||||
transceiver->internal()->channel());
|
||||
video_channel_infos.emplace_back();
|
||||
VideoChannelStatsInfo& info = video_channel_infos.back();
|
||||
info.transport_name = video_channel->transport_name();
|
||||
info.video_media_channel = video_channel->media_channel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(tommi): The above code should run on the worker thread and post the
|
||||
// results back to the signaling thread, where we can add data to the reports.
|
||||
pc_->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
||||
for (auto it = voice_channel_infos.begin(); it != voice_channel_infos.end();
|
||||
/* incremented manually */) {
|
||||
if (!it->voice_media_channel->GetStats(&it->voice_media_info)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to get voice channel stats";
|
||||
it = voice_channel_infos.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
for (auto it = video_channel_infos.begin(); it != video_channel_infos.end();
|
||||
/* incremented manually */) {
|
||||
if (!it->video_media_channel->GetStats(&it->video_media_info)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to get video channel stats";
|
||||
it = video_channel_infos.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
});
|
||||
|
||||
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
||||
|
||||
StatsReport::Id transport_id =
|
||||
StatsReport::NewComponentId(pc_->voice_channel()->transport_name(),
|
||||
cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
||||
|
||||
ExtractStatsFromList(voice_info.receivers, transport_id, this,
|
||||
StatsReport::kReceive);
|
||||
ExtractStatsFromList(voice_info.senders, transport_id, this,
|
||||
StatsReport::kSend);
|
||||
|
||||
UpdateStatsFromExistingLocalAudioTracks(voice_info.receivers.size() > 0);
|
||||
}
|
||||
|
||||
void StatsCollector::ExtractVideoInfo(
|
||||
PeerConnectionInterface::StatsOutputLevel level) {
|
||||
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
||||
|
||||
if (!pc_->video_channel()) {
|
||||
return;
|
||||
bool has_remote_audio = false;
|
||||
for (const auto& info : voice_channel_infos) {
|
||||
StatsReport::Id transport_id = StatsReport::NewComponentId(
|
||||
info.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
||||
ExtractStatsFromList(info.voice_media_info.receivers, transport_id, this,
|
||||
StatsReport::kReceive);
|
||||
ExtractStatsFromList(info.voice_media_info.senders, transport_id, this,
|
||||
StatsReport::kSend);
|
||||
if (!info.voice_media_info.receivers.empty()) {
|
||||
has_remote_audio = true;
|
||||
}
|
||||
}
|
||||
cricket::VideoMediaInfo video_info;
|
||||
if (!pc_->video_channel()->GetStats(&video_info)) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to get video channel stats.";
|
||||
return;
|
||||
for (const auto& info : video_channel_infos) {
|
||||
StatsReport::Id transport_id = StatsReport::NewComponentId(
|
||||
info.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
||||
ExtractStatsFromList(info.video_media_info.receivers, transport_id, this,
|
||||
StatsReport::kReceive);
|
||||
ExtractStatsFromList(info.video_media_info.senders, transport_id, this,
|
||||
StatsReport::kSend);
|
||||
}
|
||||
|
||||
// TODO(tommi): The above code should run on the worker thread and post the
|
||||
// results back to the signaling thread, where we can add data to the reports.
|
||||
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
||||
|
||||
StatsReport::Id transport_id =
|
||||
StatsReport::NewComponentId(pc_->video_channel()->transport_name(),
|
||||
cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
||||
|
||||
ExtractStatsFromList(video_info.receivers, transport_id, this,
|
||||
StatsReport::kReceive);
|
||||
ExtractStatsFromList(video_info.senders, transport_id, this,
|
||||
StatsReport::kSend);
|
||||
UpdateStatsFromExistingLocalAudioTracks(has_remote_audio);
|
||||
}
|
||||
|
||||
void StatsCollector::ExtractSenderInfo() {
|
||||
|
||||
@ -111,10 +111,8 @@ class StatsCollector {
|
||||
void ExtractDataInfo();
|
||||
void ExtractSessionInfo();
|
||||
void ExtractBweInfo();
|
||||
void ExtractVoiceInfo();
|
||||
void ExtractVideoInfo(PeerConnectionInterface::StatsOutputLevel level);
|
||||
void ExtractMediaInfo();
|
||||
void ExtractSenderInfo();
|
||||
void BuildSsrcToTransportId();
|
||||
webrtc::StatsReport* GetReport(const StatsReport::StatsType& type,
|
||||
const std::string& id,
|
||||
StatsReport::Direction direction);
|
||||
|
||||
@ -249,7 +249,7 @@ class FakePeerConnectionBase : public PeerConnectionInternal {
|
||||
|
||||
std::vector<
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
||||
GetTransceiversForTesting() const override {
|
||||
GetTransceiversInternal() const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@ -116,6 +116,10 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase {
|
||||
std::move(voice_media_channel), mid, kDefaultRtcpMuxRequired,
|
||||
kDefaultSrtpRequired);
|
||||
voice_channel_->set_transport_name_for_testing(transport_name);
|
||||
auto transceiver = RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
|
||||
signaling_thread_, new RtpTransceiver(cricket::MEDIA_TYPE_AUDIO));
|
||||
transceiver->internal()->SetChannel(voice_channel_.get());
|
||||
transceivers_.push_back(transceiver);
|
||||
return voice_media_channel_ptr;
|
||||
}
|
||||
|
||||
@ -130,6 +134,10 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase {
|
||||
std::move(video_media_channel), mid, kDefaultRtcpMuxRequired,
|
||||
kDefaultSrtpRequired);
|
||||
video_channel_->set_transport_name_for_testing(transport_name);
|
||||
auto transceiver = RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
|
||||
signaling_thread_, new RtpTransceiver(cricket::MEDIA_TYPE_VIDEO));
|
||||
transceiver->internal()->SetChannel(video_channel_.get());
|
||||
transceivers_.push_back(transceiver);
|
||||
return video_media_channel_ptr;
|
||||
}
|
||||
|
||||
@ -220,6 +228,12 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase {
|
||||
return video_channel_.get();
|
||||
}
|
||||
|
||||
std::vector<
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
||||
GetTransceiversInternal() const override {
|
||||
return transceivers_;
|
||||
}
|
||||
|
||||
bool GetLocalTrackIdBySsrc(uint32_t ssrc, std::string* track_id) override {
|
||||
auto it = local_track_id_by_ssrc_.find(ssrc);
|
||||
if (it != local_track_id_by_ssrc_.end()) {
|
||||
@ -316,6 +330,9 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase {
|
||||
rtc::scoped_refptr<StreamCollection> local_streams_;
|
||||
rtc::scoped_refptr<StreamCollection> remote_streams_;
|
||||
|
||||
std::vector<
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
||||
transceivers_;
|
||||
std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders_;
|
||||
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user