mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00
Add RTCRemoteOutboundRtpStreamStats
for audio streams
Changes: - adding the `RTCRemoteOutboundRtpStreamStats` dictionary (see [1]) - collection of remote outbound stats (only for audio streams) - adding `remote_id` to the inbound stats and set with the ID of the corresponding remote outbound stats only if the latter are available - unit tests [1] https://www.w3.org/TR/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats Tested: verified from chrome://webrtc-internals during an appr.tc call Bug: webrtc:12529 Change-Id: Ide91dc04a3c387ba439618a9c6b64a95994a1940 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/211042 Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Reviewed-by: Sam Zackrisson <saza@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33545}
This commit is contained in:
parent
26abdaf478
commit
f7b1b95f11
10 changed files with 465 additions and 57 deletions
|
@ -388,6 +388,7 @@ class RTC_EXPORT RTCRTPStreamStats : public RTCStats {
|
||||||
RTCRTPStreamStats(std::string&& id, int64_t timestamp_us);
|
RTCRTPStreamStats(std::string&& id, int64_t timestamp_us);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/webrtc-stats/#receivedrtpstats-dict*
|
||||||
class RTC_EXPORT RTCReceivedRtpStreamStats : public RTCRTPStreamStats {
|
class RTC_EXPORT RTCReceivedRtpStreamStats : public RTCRTPStreamStats {
|
||||||
public:
|
public:
|
||||||
WEBRTC_RTCSTATS_DECL();
|
WEBRTC_RTCSTATS_DECL();
|
||||||
|
@ -410,6 +411,22 @@ class RTC_EXPORT RTCReceivedRtpStreamStats : public RTCRTPStreamStats {
|
||||||
RTCReceivedRtpStreamStats(std::string&& id, int64_t timestamp_us);
|
RTCReceivedRtpStreamStats(std::string&& id, int64_t timestamp_us);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/webrtc-stats/#sentrtpstats-dict*
|
||||||
|
class RTC_EXPORT RTCSentRtpStreamStats : public RTCRTPStreamStats {
|
||||||
|
public:
|
||||||
|
WEBRTC_RTCSTATS_DECL();
|
||||||
|
|
||||||
|
RTCSentRtpStreamStats(const RTCSentRtpStreamStats& other);
|
||||||
|
~RTCSentRtpStreamStats() override;
|
||||||
|
|
||||||
|
RTCStatsMember<uint32_t> packets_sent;
|
||||||
|
RTCStatsMember<uint64_t> bytes_sent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RTCSentRtpStreamStats(const std::string&& id, int64_t timestamp_us);
|
||||||
|
RTCSentRtpStreamStats(std::string&& id, int64_t timestamp_us);
|
||||||
|
};
|
||||||
|
|
||||||
// https://w3c.github.io/webrtc-stats/#inboundrtpstats-dict*
|
// https://w3c.github.io/webrtc-stats/#inboundrtpstats-dict*
|
||||||
// TODO(hbos): Support the remote case |is_remote = true|.
|
// TODO(hbos): Support the remote case |is_remote = true|.
|
||||||
// https://bugs.webrtc.org/7065
|
// https://bugs.webrtc.org/7065
|
||||||
|
@ -423,6 +440,7 @@ class RTC_EXPORT RTCInboundRTPStreamStats final
|
||||||
RTCInboundRTPStreamStats(const RTCInboundRTPStreamStats& other);
|
RTCInboundRTPStreamStats(const RTCInboundRTPStreamStats& other);
|
||||||
~RTCInboundRTPStreamStats() override;
|
~RTCInboundRTPStreamStats() override;
|
||||||
|
|
||||||
|
RTCStatsMember<std::string> remote_id;
|
||||||
RTCStatsMember<uint32_t> packets_received;
|
RTCStatsMember<uint32_t> packets_received;
|
||||||
RTCStatsMember<uint64_t> fec_packets_received;
|
RTCStatsMember<uint64_t> fec_packets_received;
|
||||||
RTCStatsMember<uint64_t> fec_packets_discarded;
|
RTCStatsMember<uint64_t> fec_packets_discarded;
|
||||||
|
@ -573,6 +591,22 @@ class RTC_EXPORT RTCRemoteInboundRtpStreamStats final
|
||||||
RTCStatsMember<int32_t> round_trip_time_measurements;
|
RTCStatsMember<int32_t> round_trip_time_measurements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
|
||||||
|
class RTC_EXPORT RTCRemoteOutboundRtpStreamStats final
|
||||||
|
: public RTCSentRtpStreamStats {
|
||||||
|
public:
|
||||||
|
WEBRTC_RTCSTATS_DECL();
|
||||||
|
|
||||||
|
RTCRemoteOutboundRtpStreamStats(const std::string& id, int64_t timestamp_us);
|
||||||
|
RTCRemoteOutboundRtpStreamStats(std::string&& id, int64_t timestamp_us);
|
||||||
|
RTCRemoteOutboundRtpStreamStats(const RTCRemoteOutboundRtpStreamStats& other);
|
||||||
|
~RTCRemoteOutboundRtpStreamStats() override;
|
||||||
|
|
||||||
|
RTCStatsMember<std::string> local_id;
|
||||||
|
RTCStatsMember<double> remote_timestamp;
|
||||||
|
RTCStatsMember<uint64_t> reports_sent;
|
||||||
|
};
|
||||||
|
|
||||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediasourcestats
|
// https://w3c.github.io/webrtc-stats/#dom-rtcmediasourcestats
|
||||||
class RTC_EXPORT RTCMediaSourceStats : public RTCStats {
|
class RTC_EXPORT RTCMediaSourceStats : public RTCStats {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -264,6 +264,14 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats(
|
||||||
stats.decoding_plc_cng = ds.decoded_plc_cng;
|
stats.decoding_plc_cng = ds.decoded_plc_cng;
|
||||||
stats.decoding_muted_output = ds.decoded_muted_output;
|
stats.decoding_muted_output = ds.decoded_muted_output;
|
||||||
|
|
||||||
|
stats.last_sender_report_timestamp_ms =
|
||||||
|
call_stats.last_sender_report_timestamp_ms;
|
||||||
|
stats.last_sender_report_remote_timestamp_ms =
|
||||||
|
call_stats.last_sender_report_remote_timestamp_ms;
|
||||||
|
stats.sender_reports_packets_sent = call_stats.sender_reports_packets_sent;
|
||||||
|
stats.sender_reports_bytes_sent = call_stats.sender_reports_bytes_sent;
|
||||||
|
stats.sender_reports_reports_count = call_stats.sender_reports_reports_count;
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,13 @@ class AudioReceiveStream {
|
||||||
int32_t total_interruption_duration_ms = 0;
|
int32_t total_interruption_duration_ms = 0;
|
||||||
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-estimatedplayouttimestamp
|
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-estimatedplayouttimestamp
|
||||||
absl::optional<int64_t> estimated_playout_ntp_timestamp_ms;
|
absl::optional<int64_t> estimated_playout_ntp_timestamp_ms;
|
||||||
|
// Remote outbound stats derived by the received RTCP sender reports.
|
||||||
|
// https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
|
||||||
|
absl::optional<int64_t> last_sender_report_timestamp_ms;
|
||||||
|
absl::optional<int64_t> last_sender_report_remote_timestamp_ms;
|
||||||
|
uint32_t sender_reports_packets_sent = 0;
|
||||||
|
uint64_t sender_reports_bytes_sent = 0;
|
||||||
|
uint64_t sender_reports_reports_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
|
|
|
@ -536,6 +536,13 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
|
||||||
// longer than 150 ms).
|
// longer than 150 ms).
|
||||||
int32_t interruption_count = 0;
|
int32_t interruption_count = 0;
|
||||||
int32_t total_interruption_duration_ms = 0;
|
int32_t total_interruption_duration_ms = 0;
|
||||||
|
// Remote outbound stats derived by the received RTCP sender reports.
|
||||||
|
// https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
|
||||||
|
absl::optional<int64_t> last_sender_report_timestamp_ms;
|
||||||
|
absl::optional<int64_t> last_sender_report_remote_timestamp_ms;
|
||||||
|
uint32_t sender_reports_packets_sent = 0;
|
||||||
|
uint64_t sender_reports_bytes_sent = 0;
|
||||||
|
uint64_t sender_reports_reports_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VideoSenderInfo : public MediaSenderInfo {
|
struct VideoSenderInfo : public MediaSenderInfo {
|
||||||
|
|
|
@ -2461,6 +2461,13 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info,
|
||||||
stats.relative_packet_arrival_delay_seconds;
|
stats.relative_packet_arrival_delay_seconds;
|
||||||
rinfo.interruption_count = stats.interruption_count;
|
rinfo.interruption_count = stats.interruption_count;
|
||||||
rinfo.total_interruption_duration_ms = stats.total_interruption_duration_ms;
|
rinfo.total_interruption_duration_ms = stats.total_interruption_duration_ms;
|
||||||
|
rinfo.last_sender_report_timestamp_ms =
|
||||||
|
stats.last_sender_report_timestamp_ms;
|
||||||
|
rinfo.last_sender_report_remote_timestamp_ms =
|
||||||
|
stats.last_sender_report_remote_timestamp_ms;
|
||||||
|
rinfo.sender_reports_packets_sent = stats.sender_reports_packets_sent;
|
||||||
|
rinfo.sender_reports_bytes_sent = stats.sender_reports_bytes_sent;
|
||||||
|
rinfo.sender_reports_reports_count = stats.sender_reports_reports_count;
|
||||||
|
|
||||||
info->receivers.push_back(rinfo);
|
info->receivers.push_back(rinfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,17 +109,23 @@ std::string RTCTransportStatsIDFromTransportChannel(
|
||||||
return sb.str();
|
return sb.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RTCInboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
|
std::string RTCInboundRTPStreamStatsIDFromSSRC(cricket::MediaType media_type,
|
||||||
|
uint32_t ssrc) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
rtc::SimpleStringBuilder sb(buf);
|
rtc::SimpleStringBuilder sb(buf);
|
||||||
sb << "RTCInboundRTP" << (audio ? "Audio" : "Video") << "Stream_" << ssrc;
|
sb << "RTCInboundRTP"
|
||||||
|
<< (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
|
||||||
|
<< "Stream_" << ssrc;
|
||||||
return sb.str();
|
return sb.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RTCOutboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
|
std::string RTCOutboundRTPStreamStatsIDFromSSRC(cricket::MediaType media_type,
|
||||||
|
uint32_t ssrc) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
rtc::SimpleStringBuilder sb(buf);
|
rtc::SimpleStringBuilder sb(buf);
|
||||||
sb << "RTCOutboundRTP" << (audio ? "Audio" : "Video") << "Stream_" << ssrc;
|
sb << "RTCOutboundRTP"
|
||||||
|
<< (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
|
||||||
|
<< "Stream_" << ssrc;
|
||||||
return sb.str();
|
return sb.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +140,17 @@ std::string RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(
|
||||||
return sb.str();
|
return sb.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
|
||||||
|
cricket::MediaType media_type,
|
||||||
|
uint32_t source_ssrc) {
|
||||||
|
char buf[1024];
|
||||||
|
rtc::SimpleStringBuilder sb(buf);
|
||||||
|
sb << "RTCRemoteOutboundRTP"
|
||||||
|
<< (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
|
||||||
|
<< "Stream_" << source_ssrc;
|
||||||
|
return sb.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string RTCMediaSourceStatsIDFromKindAndAttachment(
|
std::string RTCMediaSourceStatsIDFromKindAndAttachment(
|
||||||
cricket::MediaType media_type,
|
cricket::MediaType media_type,
|
||||||
int attachment_id) {
|
int attachment_id) {
|
||||||
|
@ -309,17 +326,21 @@ void SetInboundRTPStreamStatsFromMediaReceiverInfo(
|
||||||
static_cast<int32_t>(media_receiver_info.packets_lost);
|
static_cast<int32_t>(media_receiver_info.packets_lost);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInboundRTPStreamStatsFromVoiceReceiverInfo(
|
std::unique_ptr<RTCInboundRTPStreamStats> CreateInboundAudioStreamStats(
|
||||||
const std::string& mid,
|
|
||||||
const cricket::VoiceReceiverInfo& voice_receiver_info,
|
const cricket::VoiceReceiverInfo& voice_receiver_info,
|
||||||
RTCInboundRTPStreamStats* inbound_audio) {
|
const std::string& mid,
|
||||||
|
int64_t timestamp_us) {
|
||||||
|
auto inbound_audio = std::make_unique<RTCInboundRTPStreamStats>(
|
||||||
|
/*id=*/RTCInboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
voice_receiver_info.ssrc()),
|
||||||
|
timestamp_us);
|
||||||
SetInboundRTPStreamStatsFromMediaReceiverInfo(voice_receiver_info,
|
SetInboundRTPStreamStatsFromMediaReceiverInfo(voice_receiver_info,
|
||||||
inbound_audio);
|
inbound_audio.get());
|
||||||
inbound_audio->media_type = "audio";
|
inbound_audio->media_type = "audio";
|
||||||
inbound_audio->kind = "audio";
|
inbound_audio->kind = "audio";
|
||||||
if (voice_receiver_info.codec_payload_type) {
|
if (voice_receiver_info.codec_payload_type) {
|
||||||
inbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
inbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
||||||
mid, true, *voice_receiver_info.codec_payload_type);
|
mid, /*inbound=*/true, *voice_receiver_info.codec_payload_type);
|
||||||
}
|
}
|
||||||
inbound_audio->jitter = static_cast<double>(voice_receiver_info.jitter_ms) /
|
inbound_audio->jitter = static_cast<double>(voice_receiver_info.jitter_ms) /
|
||||||
rtc::kNumMillisecsPerSec;
|
rtc::kNumMillisecsPerSec;
|
||||||
|
@ -358,6 +379,51 @@ void SetInboundRTPStreamStatsFromVoiceReceiverInfo(
|
||||||
voice_receiver_info.fec_packets_received;
|
voice_receiver_info.fec_packets_received;
|
||||||
inbound_audio->fec_packets_discarded =
|
inbound_audio->fec_packets_discarded =
|
||||||
voice_receiver_info.fec_packets_discarded;
|
voice_receiver_info.fec_packets_discarded;
|
||||||
|
return inbound_audio;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<RTCRemoteOutboundRtpStreamStats>
|
||||||
|
CreateRemoteOutboundAudioStreamStats(
|
||||||
|
const cricket::VoiceReceiverInfo& voice_receiver_info,
|
||||||
|
const std::string& mid,
|
||||||
|
const std::string& inbound_audio_id,
|
||||||
|
const std::string& transport_id) {
|
||||||
|
if (!voice_receiver_info.last_sender_report_timestamp_ms.has_value()) {
|
||||||
|
// Cannot create `RTCRemoteOutboundRtpStreamStats` when the RTCP SR arrival
|
||||||
|
// timestamp is not available - i.e., until the first sender report is
|
||||||
|
// received.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
RTC_DCHECK_GT(voice_receiver_info.sender_reports_reports_count, 0);
|
||||||
|
|
||||||
|
// Create.
|
||||||
|
auto stats = std::make_unique<RTCRemoteOutboundRtpStreamStats>(
|
||||||
|
/*id=*/RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
|
||||||
|
cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
|
||||||
|
/*timestamp_us=*/rtc::kNumMicrosecsPerMillisec *
|
||||||
|
voice_receiver_info.last_sender_report_timestamp_ms.value());
|
||||||
|
|
||||||
|
// Populate.
|
||||||
|
// - RTCRtpStreamStats.
|
||||||
|
stats->ssrc = voice_receiver_info.ssrc();
|
||||||
|
stats->kind = "audio";
|
||||||
|
stats->transport_id = transport_id;
|
||||||
|
stats->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
||||||
|
mid,
|
||||||
|
/*inbound=*/true, // Remote-outbound same as local-inbound.
|
||||||
|
*voice_receiver_info.codec_payload_type);
|
||||||
|
// - RTCSentRtpStreamStats.
|
||||||
|
stats->packets_sent = voice_receiver_info.sender_reports_packets_sent;
|
||||||
|
stats->bytes_sent = voice_receiver_info.sender_reports_bytes_sent;
|
||||||
|
// - RTCRemoteOutboundRtpStreamStats.
|
||||||
|
stats->local_id = inbound_audio_id;
|
||||||
|
RTC_DCHECK(
|
||||||
|
voice_receiver_info.last_sender_report_remote_timestamp_ms.has_value());
|
||||||
|
stats->remote_timestamp = static_cast<double>(
|
||||||
|
voice_receiver_info.last_sender_report_remote_timestamp_ms.value());
|
||||||
|
stats->reports_sent = voice_receiver_info.sender_reports_reports_count;
|
||||||
|
|
||||||
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInboundRTPStreamStatsFromVideoReceiverInfo(
|
void SetInboundRTPStreamStatsFromVideoReceiverInfo(
|
||||||
|
@ -370,7 +436,7 @@ void SetInboundRTPStreamStatsFromVideoReceiverInfo(
|
||||||
inbound_video->kind = "video";
|
inbound_video->kind = "video";
|
||||||
if (video_receiver_info.codec_payload_type) {
|
if (video_receiver_info.codec_payload_type) {
|
||||||
inbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
inbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
||||||
mid, true, *video_receiver_info.codec_payload_type);
|
mid, /*inbound=*/true, *video_receiver_info.codec_payload_type);
|
||||||
}
|
}
|
||||||
inbound_video->jitter = static_cast<double>(video_receiver_info.jitter_ms) /
|
inbound_video->jitter = static_cast<double>(video_receiver_info.jitter_ms) /
|
||||||
rtc::kNumMillisecsPerSec;
|
rtc::kNumMillisecsPerSec;
|
||||||
|
@ -454,7 +520,7 @@ void SetOutboundRTPStreamStatsFromVoiceSenderInfo(
|
||||||
outbound_audio->kind = "audio";
|
outbound_audio->kind = "audio";
|
||||||
if (voice_sender_info.codec_payload_type) {
|
if (voice_sender_info.codec_payload_type) {
|
||||||
outbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
outbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
||||||
mid, false, *voice_sender_info.codec_payload_type);
|
mid, /*inbound=*/false, *voice_sender_info.codec_payload_type);
|
||||||
}
|
}
|
||||||
// |fir_count|, |pli_count| and |sli_count| are only valid for video and are
|
// |fir_count|, |pli_count| and |sli_count| are only valid for video and are
|
||||||
// purposefully left undefined for audio.
|
// purposefully left undefined for audio.
|
||||||
|
@ -470,7 +536,7 @@ void SetOutboundRTPStreamStatsFromVideoSenderInfo(
|
||||||
outbound_video->kind = "video";
|
outbound_video->kind = "video";
|
||||||
if (video_sender_info.codec_payload_type) {
|
if (video_sender_info.codec_payload_type) {
|
||||||
outbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
outbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
|
||||||
mid, false, *video_sender_info.codec_payload_type);
|
mid, /*inbound=*/false, *video_sender_info.codec_payload_type);
|
||||||
}
|
}
|
||||||
outbound_video->fir_count =
|
outbound_video->fir_count =
|
||||||
static_cast<uint32_t>(video_sender_info.firs_rcvd);
|
static_cast<uint32_t>(video_sender_info.firs_rcvd);
|
||||||
|
@ -550,8 +616,8 @@ ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
|
||||||
remote_inbound->round_trip_time_measurements =
|
remote_inbound->round_trip_time_measurements =
|
||||||
report_block_data.num_rtts();
|
report_block_data.num_rtts();
|
||||||
|
|
||||||
std::string local_id = RTCOutboundRTPStreamStatsIDFromSSRC(
|
std::string local_id =
|
||||||
media_type == cricket::MEDIA_TYPE_AUDIO, report_block.source_ssrc);
|
RTCOutboundRTPStreamStatsIDFromSSRC(media_type, report_block.source_ssrc);
|
||||||
// Look up local stat from |outbound_rtps| where the pointers are non-const.
|
// Look up local stat from |outbound_rtps| where the pointers are non-const.
|
||||||
auto local_id_it = outbound_rtps.find(local_id);
|
auto local_id_it = outbound_rtps.find(local_id);
|
||||||
if (local_id_it != outbound_rtps.end()) {
|
if (local_id_it != outbound_rtps.end()) {
|
||||||
|
@ -1678,16 +1744,16 @@ void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
|
||||||
std::string mid = *stats.mid;
|
std::string mid = *stats.mid;
|
||||||
std::string transport_id = RTCTransportStatsIDFromTransportChannel(
|
std::string transport_id = RTCTransportStatsIDFromTransportChannel(
|
||||||
*stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
*stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
||||||
// Inbound
|
// Inbound and remote-outbound.
|
||||||
|
// The remote-outbound stats are based on RTCP sender reports sent from the
|
||||||
|
// remote endpoint providing metrics about the remote outbound streams.
|
||||||
for (const cricket::VoiceReceiverInfo& voice_receiver_info :
|
for (const cricket::VoiceReceiverInfo& voice_receiver_info :
|
||||||
track_media_info_map.voice_media_info()->receivers) {
|
track_media_info_map.voice_media_info()->receivers) {
|
||||||
if (!voice_receiver_info.connected())
|
if (!voice_receiver_info.connected())
|
||||||
continue;
|
continue;
|
||||||
auto inbound_audio = std::make_unique<RTCInboundRTPStreamStats>(
|
// Inbound.
|
||||||
RTCInboundRTPStreamStatsIDFromSSRC(true, voice_receiver_info.ssrc()),
|
auto inbound_audio =
|
||||||
timestamp_us);
|
CreateInboundAudioStreamStats(voice_receiver_info, mid, timestamp_us);
|
||||||
SetInboundRTPStreamStatsFromVoiceReceiverInfo(mid, voice_receiver_info,
|
|
||||||
inbound_audio.get());
|
|
||||||
// TODO(hta): This lookup should look for the sender, not the track.
|
// TODO(hta): This lookup should look for the sender, not the track.
|
||||||
rtc::scoped_refptr<AudioTrackInterface> audio_track =
|
rtc::scoped_refptr<AudioTrackInterface> audio_track =
|
||||||
track_media_info_map.GetAudioTrack(voice_receiver_info);
|
track_media_info_map.GetAudioTrack(voice_receiver_info);
|
||||||
|
@ -1698,16 +1764,27 @@ void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
|
||||||
track_media_info_map.GetAttachmentIdByTrack(audio_track).value());
|
track_media_info_map.GetAttachmentIdByTrack(audio_track).value());
|
||||||
}
|
}
|
||||||
inbound_audio->transport_id = transport_id;
|
inbound_audio->transport_id = transport_id;
|
||||||
|
// Remote-outbound.
|
||||||
|
auto remote_outbound_audio = CreateRemoteOutboundAudioStreamStats(
|
||||||
|
voice_receiver_info, mid, inbound_audio->id(), transport_id);
|
||||||
|
// Add stats.
|
||||||
|
if (remote_outbound_audio) {
|
||||||
|
// When the remote outbound stats are available, the remote ID for the
|
||||||
|
// local inbound stats is set.
|
||||||
|
inbound_audio->remote_id = remote_outbound_audio->id();
|
||||||
|
report->AddStats(std::move(remote_outbound_audio));
|
||||||
|
}
|
||||||
report->AddStats(std::move(inbound_audio));
|
report->AddStats(std::move(inbound_audio));
|
||||||
}
|
}
|
||||||
// Outbound
|
// Outbound.
|
||||||
std::map<std::string, RTCOutboundRTPStreamStats*> audio_outbound_rtps;
|
std::map<std::string, RTCOutboundRTPStreamStats*> audio_outbound_rtps;
|
||||||
for (const cricket::VoiceSenderInfo& voice_sender_info :
|
for (const cricket::VoiceSenderInfo& voice_sender_info :
|
||||||
track_media_info_map.voice_media_info()->senders) {
|
track_media_info_map.voice_media_info()->senders) {
|
||||||
if (!voice_sender_info.connected())
|
if (!voice_sender_info.connected())
|
||||||
continue;
|
continue;
|
||||||
auto outbound_audio = std::make_unique<RTCOutboundRTPStreamStats>(
|
auto outbound_audio = std::make_unique<RTCOutboundRTPStreamStats>(
|
||||||
RTCOutboundRTPStreamStatsIDFromSSRC(true, voice_sender_info.ssrc()),
|
RTCOutboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_AUDIO,
|
||||||
|
voice_sender_info.ssrc()),
|
||||||
timestamp_us);
|
timestamp_us);
|
||||||
SetOutboundRTPStreamStatsFromVoiceSenderInfo(mid, voice_sender_info,
|
SetOutboundRTPStreamStatsFromVoiceSenderInfo(mid, voice_sender_info,
|
||||||
outbound_audio.get());
|
outbound_audio.get());
|
||||||
|
@ -1728,7 +1805,7 @@ void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
|
||||||
std::make_pair(outbound_audio->id(), outbound_audio.get()));
|
std::make_pair(outbound_audio->id(), outbound_audio.get()));
|
||||||
report->AddStats(std::move(outbound_audio));
|
report->AddStats(std::move(outbound_audio));
|
||||||
}
|
}
|
||||||
// Remote-inbound
|
// Remote-inbound.
|
||||||
// These are Report Block-based, information sent from the remote endpoint,
|
// These are Report Block-based, information sent from the remote endpoint,
|
||||||
// providing metrics about our Outbound streams. We take advantage of the fact
|
// providing metrics about our Outbound streams. We take advantage of the fact
|
||||||
// that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
|
// that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
|
||||||
|
@ -1765,7 +1842,8 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
|
||||||
if (!video_receiver_info.connected())
|
if (!video_receiver_info.connected())
|
||||||
continue;
|
continue;
|
||||||
auto inbound_video = std::make_unique<RTCInboundRTPStreamStats>(
|
auto inbound_video = std::make_unique<RTCInboundRTPStreamStats>(
|
||||||
RTCInboundRTPStreamStatsIDFromSSRC(false, video_receiver_info.ssrc()),
|
RTCInboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
video_receiver_info.ssrc()),
|
||||||
timestamp_us);
|
timestamp_us);
|
||||||
SetInboundRTPStreamStatsFromVideoReceiverInfo(mid, video_receiver_info,
|
SetInboundRTPStreamStatsFromVideoReceiverInfo(mid, video_receiver_info,
|
||||||
inbound_video.get());
|
inbound_video.get());
|
||||||
|
@ -1779,6 +1857,7 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
|
||||||
}
|
}
|
||||||
inbound_video->transport_id = transport_id;
|
inbound_video->transport_id = transport_id;
|
||||||
report->AddStats(std::move(inbound_video));
|
report->AddStats(std::move(inbound_video));
|
||||||
|
// TODO(crbug.com/webrtc/12529): Add remote-outbound stats.
|
||||||
}
|
}
|
||||||
// Outbound
|
// Outbound
|
||||||
std::map<std::string, RTCOutboundRTPStreamStats*> video_outbound_rtps;
|
std::map<std::string, RTCOutboundRTPStreamStats*> video_outbound_rtps;
|
||||||
|
@ -1787,7 +1866,8 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
|
||||||
if (!video_sender_info.connected())
|
if (!video_sender_info.connected())
|
||||||
continue;
|
continue;
|
||||||
auto outbound_video = std::make_unique<RTCOutboundRTPStreamStats>(
|
auto outbound_video = std::make_unique<RTCOutboundRTPStreamStats>(
|
||||||
RTCOutboundRTPStreamStatsIDFromSSRC(false, video_sender_info.ssrc()),
|
RTCOutboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_VIDEO,
|
||||||
|
video_sender_info.ssrc()),
|
||||||
timestamp_us);
|
timestamp_us);
|
||||||
SetOutboundRTPStreamStatsFromVideoSenderInfo(mid, video_sender_info,
|
SetOutboundRTPStreamStatsFromVideoSenderInfo(mid, video_sender_info,
|
||||||
outbound_video.get());
|
outbound_video.get());
|
||||||
|
|
|
@ -119,6 +119,14 @@ namespace {
|
||||||
|
|
||||||
const int64_t kGetStatsReportTimeoutMs = 1000;
|
const int64_t kGetStatsReportTimeoutMs = 1000;
|
||||||
|
|
||||||
|
// Fake data used by `SetupExampleStatsVoiceGraph()` to fill in remote outbound
|
||||||
|
// stats.
|
||||||
|
constexpr int64_t kRemoteOutboundStatsTimestampMs = 123;
|
||||||
|
constexpr int64_t kRemoteOutboundStatsRemoteTimestampMs = 456;
|
||||||
|
constexpr uint32_t kRemoteOutboundStatsPacketsSent = 7u;
|
||||||
|
constexpr uint64_t kRemoteOutboundStatsBytesSent = 8u;
|
||||||
|
constexpr uint64_t kRemoteOutboundStatsReportsCount = 9u;
|
||||||
|
|
||||||
struct CertificateInfo {
|
struct CertificateInfo {
|
||||||
rtc::scoped_refptr<rtc::RTCCertificate> certificate;
|
rtc::scoped_refptr<rtc::RTCCertificate> certificate;
|
||||||
std::vector<std::string> ders;
|
std::vector<std::string> ders;
|
||||||
|
@ -575,6 +583,11 @@ class RTCStatsCollectorWrapper {
|
||||||
EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs);
|
EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs);
|
||||||
int64_t after = rtc::TimeUTCMicros();
|
int64_t after = rtc::TimeUTCMicros();
|
||||||
for (const RTCStats& stats : *callback->report()) {
|
for (const RTCStats& stats : *callback->report()) {
|
||||||
|
if (stats.type() == RTCRemoteInboundRtpStreamStats::kType ||
|
||||||
|
stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
|
||||||
|
// Ignore remote timestamps.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
EXPECT_LE(stats.timestamp_us(), after);
|
EXPECT_LE(stats.timestamp_us(), after);
|
||||||
}
|
}
|
||||||
return callback->report();
|
return callback->report();
|
||||||
|
@ -619,6 +632,7 @@ class RTCStatsCollectorTest : public ::testing::Test {
|
||||||
std::string recv_codec_id;
|
std::string recv_codec_id;
|
||||||
std::string outbound_rtp_id;
|
std::string outbound_rtp_id;
|
||||||
std::string inbound_rtp_id;
|
std::string inbound_rtp_id;
|
||||||
|
std::string remote_outbound_rtp_id;
|
||||||
std::string transport_id;
|
std::string transport_id;
|
||||||
std::string sender_track_id;
|
std::string sender_track_id;
|
||||||
std::string receiver_track_id;
|
std::string receiver_track_id;
|
||||||
|
@ -627,9 +641,9 @@ class RTCStatsCollectorTest : public ::testing::Test {
|
||||||
std::string media_source_id;
|
std::string media_source_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sets up the example stats graph (see ASCII art below) used for testing the
|
// Sets up the example stats graph (see ASCII art below) for a video only
|
||||||
// stats selection algorithm,
|
// call. The graph is used for testing the stats selection algorithm (see
|
||||||
// https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm.
|
// https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm).
|
||||||
// These tests test the integration of the stats traversal algorithm inside of
|
// These tests test the integration of the stats traversal algorithm inside of
|
||||||
// RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
|
// RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
|
||||||
// traversal tests.
|
// traversal tests.
|
||||||
|
@ -731,6 +745,125 @@ class RTCStatsCollectorTest : public ::testing::Test {
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets up an example stats graph (see ASCII art below) for an audio only call
|
||||||
|
// and checks that the expected stats are generated.
|
||||||
|
ExampleStatsGraph SetupExampleStatsVoiceGraph(
|
||||||
|
bool add_remote_outbound_stats) {
|
||||||
|
constexpr uint32_t kLocalSsrc = 3;
|
||||||
|
constexpr uint32_t kRemoteSsrc = 4;
|
||||||
|
ExampleStatsGraph graph;
|
||||||
|
|
||||||
|
// codec (send)
|
||||||
|
graph.send_codec_id = "RTCCodec_VoiceMid_Outbound_1";
|
||||||
|
cricket::VoiceMediaInfo media_info;
|
||||||
|
RtpCodecParameters send_codec;
|
||||||
|
send_codec.payload_type = 1;
|
||||||
|
send_codec.clock_rate = 0;
|
||||||
|
media_info.send_codecs.insert(
|
||||||
|
std::make_pair(send_codec.payload_type, send_codec));
|
||||||
|
// codec (recv)
|
||||||
|
graph.recv_codec_id = "RTCCodec_VoiceMid_Inbound_2";
|
||||||
|
RtpCodecParameters recv_codec;
|
||||||
|
recv_codec.payload_type = 2;
|
||||||
|
recv_codec.clock_rate = 0;
|
||||||
|
media_info.receive_codecs.insert(
|
||||||
|
std::make_pair(recv_codec.payload_type, recv_codec));
|
||||||
|
// outbound-rtp
|
||||||
|
graph.outbound_rtp_id = "RTCOutboundRTPAudioStream_3";
|
||||||
|
media_info.senders.push_back(cricket::VoiceSenderInfo());
|
||||||
|
media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
|
||||||
|
media_info.senders[0].local_stats[0].ssrc = kLocalSsrc;
|
||||||
|
media_info.senders[0].codec_payload_type = send_codec.payload_type;
|
||||||
|
// inbound-rtp
|
||||||
|
graph.inbound_rtp_id = "RTCInboundRTPAudioStream_4";
|
||||||
|
media_info.receivers.push_back(cricket::VoiceReceiverInfo());
|
||||||
|
media_info.receivers[0].local_stats.push_back(cricket::SsrcReceiverInfo());
|
||||||
|
media_info.receivers[0].local_stats[0].ssrc = kRemoteSsrc;
|
||||||
|
media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
|
||||||
|
// remote-outbound-rtp
|
||||||
|
if (add_remote_outbound_stats) {
|
||||||
|
graph.remote_outbound_rtp_id = "RTCRemoteOutboundRTPAudioStream_4";
|
||||||
|
media_info.receivers[0].last_sender_report_timestamp_ms =
|
||||||
|
kRemoteOutboundStatsTimestampMs;
|
||||||
|
media_info.receivers[0].last_sender_report_remote_timestamp_ms =
|
||||||
|
kRemoteOutboundStatsRemoteTimestampMs;
|
||||||
|
media_info.receivers[0].sender_reports_packets_sent =
|
||||||
|
kRemoteOutboundStatsPacketsSent;
|
||||||
|
media_info.receivers[0].sender_reports_bytes_sent =
|
||||||
|
kRemoteOutboundStatsBytesSent;
|
||||||
|
media_info.receivers[0].sender_reports_reports_count =
|
||||||
|
kRemoteOutboundStatsReportsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// transport
|
||||||
|
graph.transport_id = "RTCTransport_TransportName_1";
|
||||||
|
auto* video_media_channel =
|
||||||
|
pc_->AddVoiceChannel("VoiceMid", "TransportName");
|
||||||
|
video_media_channel->SetStats(media_info);
|
||||||
|
// track (sender)
|
||||||
|
graph.sender = stats_->SetupLocalTrackAndSender(
|
||||||
|
cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", kLocalSsrc, false, 50);
|
||||||
|
graph.sender_track_id = "RTCMediaStreamTrack_sender_" +
|
||||||
|
rtc::ToString(graph.sender->AttachmentId());
|
||||||
|
// track (receiver) and stream (remote stream)
|
||||||
|
graph.receiver = stats_->SetupRemoteTrackAndReceiver(
|
||||||
|
cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId",
|
||||||
|
kRemoteSsrc);
|
||||||
|
graph.receiver_track_id = "RTCMediaStreamTrack_receiver_" +
|
||||||
|
rtc::ToString(graph.receiver->AttachmentId());
|
||||||
|
graph.remote_stream_id = "RTCMediaStream_RemoteStreamId";
|
||||||
|
// peer-connection
|
||||||
|
graph.peer_connection_id = "RTCPeerConnection";
|
||||||
|
// media-source (kind: video)
|
||||||
|
graph.media_source_id =
|
||||||
|
"RTCAudioSource_" + rtc::ToString(graph.sender->AttachmentId());
|
||||||
|
|
||||||
|
// Expected stats graph:
|
||||||
|
//
|
||||||
|
// +--- track (sender) stream (remote stream) ---> track (receiver)
|
||||||
|
// | ^ ^
|
||||||
|
// | | |
|
||||||
|
// | +--------- outbound-rtp inbound-rtp ---------------+
|
||||||
|
// | | | | | |
|
||||||
|
// | | v v v v
|
||||||
|
// | | codec (send) transport codec (recv) peer-connection
|
||||||
|
// v v
|
||||||
|
// media-source
|
||||||
|
|
||||||
|
// Verify the stats graph is set up correctly.
|
||||||
|
graph.full_report = stats_->GetStatsReport();
|
||||||
|
EXPECT_EQ(graph.full_report->size(), add_remote_outbound_stats ? 11u : 10u);
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
|
||||||
|
EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
|
||||||
|
// `graph.remote_outbound_rtp_id` is omitted on purpose so that expectations
|
||||||
|
// can be added by the caller depending on what value it sets for the
|
||||||
|
// `add_remote_outbound_stats` argument.
|
||||||
|
const auto& sender_track = graph.full_report->Get(graph.sender_track_id)
|
||||||
|
->cast_to<RTCMediaStreamTrackStats>();
|
||||||
|
EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
|
||||||
|
const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
|
||||||
|
->cast_to<RTCOutboundRTPStreamStats>();
|
||||||
|
EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
|
||||||
|
EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
|
||||||
|
EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
|
||||||
|
EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
|
||||||
|
const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
|
||||||
|
->cast_to<RTCInboundRTPStreamStats>();
|
||||||
|
EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
|
||||||
|
EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
|
||||||
|
EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
rtc::ScopedFakeClock fake_clock_;
|
rtc::ScopedFakeClock fake_clock_;
|
||||||
rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
|
rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
|
||||||
|
@ -2872,6 +3005,43 @@ INSTANTIATE_TEST_SUITE_P(All,
|
||||||
::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
|
::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
|
||||||
cricket::MEDIA_TYPE_VIDEO)); // "/1"
|
cricket::MEDIA_TYPE_VIDEO)); // "/1"
|
||||||
|
|
||||||
|
// Checks that no remote outbound stats are collected if not available in
|
||||||
|
// `VoiceMediaInfo`.
|
||||||
|
TEST_F(RTCStatsCollectorTest,
|
||||||
|
RTCRemoteOutboundRtpAudioStreamStatsNotCollected) {
|
||||||
|
ExampleStatsGraph graph =
|
||||||
|
SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/false);
|
||||||
|
EXPECT_FALSE(graph.full_report->Get(graph.remote_outbound_rtp_id));
|
||||||
|
// Also check that no other remote outbound report is created (in case the
|
||||||
|
// expected ID is incorrect).
|
||||||
|
rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
|
||||||
|
ASSERT_NE(report->begin(), report->end())
|
||||||
|
<< "No reports have been generated.";
|
||||||
|
for (const auto& stats : *report) {
|
||||||
|
SCOPED_TRACE(stats.id());
|
||||||
|
EXPECT_NE(stats.type(), RTCRemoteOutboundRtpStreamStats::kType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks that the remote outbound stats are collected when available in
|
||||||
|
// `VoiceMediaInfo`.
|
||||||
|
TEST_F(RTCStatsCollectorTest, RTCRemoteOutboundRtpAudioStreamStatsCollected) {
|
||||||
|
ExampleStatsGraph graph =
|
||||||
|
SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/true);
|
||||||
|
ASSERT_TRUE(graph.full_report->Get(graph.remote_outbound_rtp_id));
|
||||||
|
const auto& remote_outbound_rtp =
|
||||||
|
graph.full_report->Get(graph.remote_outbound_rtp_id)
|
||||||
|
->cast_to<RTCRemoteOutboundRtpStreamStats>();
|
||||||
|
EXPECT_EQ(remote_outbound_rtp.timestamp_us(),
|
||||||
|
kRemoteOutboundStatsTimestampMs * rtc::kNumMicrosecsPerMillisec);
|
||||||
|
EXPECT_FLOAT_EQ(*remote_outbound_rtp.remote_timestamp,
|
||||||
|
static_cast<double>(kRemoteOutboundStatsRemoteTimestampMs));
|
||||||
|
EXPECT_EQ(*remote_outbound_rtp.packets_sent, kRemoteOutboundStatsPacketsSent);
|
||||||
|
EXPECT_EQ(*remote_outbound_rtp.bytes_sent, kRemoteOutboundStatsBytesSent);
|
||||||
|
EXPECT_EQ(*remote_outbound_rtp.reports_sent,
|
||||||
|
kRemoteOutboundStatsReportsCount);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RTCStatsCollectorTest,
|
TEST_F(RTCStatsCollectorTest,
|
||||||
RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
|
RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
|
||||||
const uint32_t kSsrc = 4;
|
const uint32_t kSsrc = 4;
|
||||||
|
|
|
@ -399,6 +399,9 @@ class RTCStatsReportVerifier {
|
||||||
} else if (stats.type() == RTCRemoteInboundRtpStreamStats::kType) {
|
} else if (stats.type() == RTCRemoteInboundRtpStreamStats::kType) {
|
||||||
verify_successful &= VerifyRTCRemoteInboundRtpStreamStats(
|
verify_successful &= VerifyRTCRemoteInboundRtpStreamStats(
|
||||||
stats.cast_to<RTCRemoteInboundRtpStreamStats>());
|
stats.cast_to<RTCRemoteInboundRtpStreamStats>());
|
||||||
|
} else if (stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
|
||||||
|
verify_successful &= VerifyRTCRemoteOutboundRTPStreamStats(
|
||||||
|
stats.cast_to<RTCRemoteOutboundRtpStreamStats>());
|
||||||
} else if (stats.type() == RTCAudioSourceStats::kType) {
|
} else if (stats.type() == RTCAudioSourceStats::kType) {
|
||||||
// RTCAudioSourceStats::kType and RTCVideoSourceStats::kType both have
|
// RTCAudioSourceStats::kType and RTCVideoSourceStats::kType both have
|
||||||
// the value "media-source", but they are distinguishable with pointer
|
// the value "media-source", but they are distinguishable with pointer
|
||||||
|
@ -769,29 +772,38 @@ class RTCStatsReportVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyRTCRTPStreamStats(const RTCRTPStreamStats& stream,
|
void VerifyRTCRTPStreamStats(const RTCRTPStreamStats& stream,
|
||||||
RTCStatsVerifier* verifier) {
|
RTCStatsVerifier& verifier) {
|
||||||
verifier->TestMemberIsDefined(stream.ssrc);
|
verifier.TestMemberIsDefined(stream.ssrc);
|
||||||
verifier->TestMemberIsDefined(stream.kind);
|
verifier.TestMemberIsDefined(stream.kind);
|
||||||
// Some legacy metrics are only defined for some of the RTP types in the
|
// Some legacy metrics are only defined for some of the RTP types in the
|
||||||
// hierarcy.
|
// hierarcy.
|
||||||
if (stream.type() == RTCInboundRTPStreamStats::kType ||
|
if (stream.type() == RTCInboundRTPStreamStats::kType ||
|
||||||
stream.type() == RTCOutboundRTPStreamStats::kType) {
|
stream.type() == RTCOutboundRTPStreamStats::kType) {
|
||||||
verifier->TestMemberIsDefined(stream.media_type);
|
verifier.TestMemberIsDefined(stream.media_type);
|
||||||
verifier->TestMemberIsIDReference(stream.track_id,
|
verifier.TestMemberIsIDReference(stream.track_id,
|
||||||
RTCMediaStreamTrackStats::kType);
|
RTCMediaStreamTrackStats::kType);
|
||||||
} else {
|
} else {
|
||||||
verifier->TestMemberIsUndefined(stream.media_type);
|
verifier.TestMemberIsUndefined(stream.media_type);
|
||||||
verifier->TestMemberIsUndefined(stream.track_id);
|
verifier.TestMemberIsUndefined(stream.track_id);
|
||||||
}
|
}
|
||||||
verifier->TestMemberIsIDReference(stream.transport_id,
|
verifier.TestMemberIsIDReference(stream.transport_id,
|
||||||
RTCTransportStats::kType);
|
RTCTransportStats::kType);
|
||||||
verifier->TestMemberIsIDReference(stream.codec_id, RTCCodecStats::kType);
|
verifier.TestMemberIsIDReference(stream.codec_id, RTCCodecStats::kType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifyRTCSentRTPStreamStats(const RTCSentRtpStreamStats& sent_stream,
|
||||||
|
RTCStatsVerifier& verifier) {
|
||||||
|
VerifyRTCRTPStreamStats(sent_stream, verifier);
|
||||||
|
verifier.TestMemberIsDefined(sent_stream.packets_sent);
|
||||||
|
verifier.TestMemberIsDefined(sent_stream.bytes_sent);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VerifyRTCInboundRTPStreamStats(
|
bool VerifyRTCInboundRTPStreamStats(
|
||||||
const RTCInboundRTPStreamStats& inbound_stream) {
|
const RTCInboundRTPStreamStats& inbound_stream) {
|
||||||
RTCStatsVerifier verifier(report_, &inbound_stream);
|
RTCStatsVerifier verifier(report_, &inbound_stream);
|
||||||
VerifyRTCRTPStreamStats(inbound_stream, &verifier);
|
VerifyRTCRTPStreamStats(inbound_stream, verifier);
|
||||||
|
verifier.TestMemberIsOptionalIDReference(
|
||||||
|
inbound_stream.remote_id, RTCRemoteOutboundRtpStreamStats::kType);
|
||||||
if (inbound_stream.media_type.is_defined() &&
|
if (inbound_stream.media_type.is_defined() &&
|
||||||
*inbound_stream.media_type == "video") {
|
*inbound_stream.media_type == "video") {
|
||||||
verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.qp_sum);
|
verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.qp_sum);
|
||||||
|
@ -928,7 +940,7 @@ class RTCStatsReportVerifier {
|
||||||
// TODO(https://crbug.com/webrtc/12532): Invoke
|
// TODO(https://crbug.com/webrtc/12532): Invoke
|
||||||
// VerifyRTCReceivedRtpStreamStats() instead of VerifyRTCRTPStreamStats()
|
// VerifyRTCReceivedRtpStreamStats() instead of VerifyRTCRTPStreamStats()
|
||||||
// because they have a shared hierarchy now!
|
// because they have a shared hierarchy now!
|
||||||
VerifyRTCRTPStreamStats(outbound_stream, &verifier);
|
VerifyRTCRTPStreamStats(outbound_stream, verifier);
|
||||||
if (outbound_stream.media_type.is_defined() &&
|
if (outbound_stream.media_type.is_defined() &&
|
||||||
*outbound_stream.media_type == "video") {
|
*outbound_stream.media_type == "video") {
|
||||||
verifier.TestMemberIsIDReference(outbound_stream.media_source_id,
|
verifier.TestMemberIsIDReference(outbound_stream.media_source_id,
|
||||||
|
@ -1021,16 +1033,16 @@ class RTCStatsReportVerifier {
|
||||||
|
|
||||||
void VerifyRTCReceivedRtpStreamStats(
|
void VerifyRTCReceivedRtpStreamStats(
|
||||||
const RTCReceivedRtpStreamStats& received_rtp,
|
const RTCReceivedRtpStreamStats& received_rtp,
|
||||||
RTCStatsVerifier* verifier) {
|
RTCStatsVerifier& verifier) {
|
||||||
VerifyRTCRTPStreamStats(received_rtp, verifier);
|
VerifyRTCRTPStreamStats(received_rtp, verifier);
|
||||||
verifier->TestMemberIsNonNegative<double>(received_rtp.jitter);
|
verifier.TestMemberIsNonNegative<double>(received_rtp.jitter);
|
||||||
verifier->TestMemberIsDefined(received_rtp.packets_lost);
|
verifier.TestMemberIsDefined(received_rtp.packets_lost);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VerifyRTCRemoteInboundRtpStreamStats(
|
bool VerifyRTCRemoteInboundRtpStreamStats(
|
||||||
const RTCRemoteInboundRtpStreamStats& remote_inbound_stream) {
|
const RTCRemoteInboundRtpStreamStats& remote_inbound_stream) {
|
||||||
RTCStatsVerifier verifier(report_, &remote_inbound_stream);
|
RTCStatsVerifier verifier(report_, &remote_inbound_stream);
|
||||||
VerifyRTCReceivedRtpStreamStats(remote_inbound_stream, &verifier);
|
VerifyRTCReceivedRtpStreamStats(remote_inbound_stream, verifier);
|
||||||
verifier.TestMemberIsDefined(remote_inbound_stream.fraction_lost);
|
verifier.TestMemberIsDefined(remote_inbound_stream.fraction_lost);
|
||||||
verifier.TestMemberIsIDReference(remote_inbound_stream.local_id,
|
verifier.TestMemberIsIDReference(remote_inbound_stream.local_id,
|
||||||
RTCOutboundRTPStreamStats::kType);
|
RTCOutboundRTPStreamStats::kType);
|
||||||
|
@ -1043,6 +1055,19 @@ class RTCStatsReportVerifier {
|
||||||
return verifier.ExpectAllMembersSuccessfullyTested();
|
return verifier.ExpectAllMembersSuccessfullyTested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VerifyRTCRemoteOutboundRTPStreamStats(
|
||||||
|
const RTCRemoteOutboundRtpStreamStats& remote_outbound_stream) {
|
||||||
|
RTCStatsVerifier verifier(report_, &remote_outbound_stream);
|
||||||
|
VerifyRTCRTPStreamStats(remote_outbound_stream, verifier);
|
||||||
|
VerifyRTCSentRTPStreamStats(remote_outbound_stream, verifier);
|
||||||
|
verifier.TestMemberIsIDReference(remote_outbound_stream.local_id,
|
||||||
|
RTCOutboundRTPStreamStats::kType);
|
||||||
|
verifier.TestMemberIsNonNegative<double>(
|
||||||
|
remote_outbound_stream.remote_timestamp);
|
||||||
|
verifier.TestMemberIsDefined(remote_outbound_stream.reports_sent);
|
||||||
|
return verifier.ExpectAllMembersSuccessfullyTested();
|
||||||
|
}
|
||||||
|
|
||||||
void VerifyRTCMediaSourceStats(const RTCMediaSourceStats& media_source,
|
void VerifyRTCMediaSourceStats(const RTCMediaSourceStats& media_source,
|
||||||
RTCStatsVerifier* verifier) {
|
RTCStatsVerifier* verifier) {
|
||||||
verifier->TestMemberIsDefined(media_source.track_identifier);
|
verifier->TestMemberIsDefined(media_source.track_identifier);
|
||||||
|
|
|
@ -99,24 +99,36 @@ std::vector<const std::string*> GetStatsReferencedIds(const RTCStats& stats) {
|
||||||
AddIdIfDefined(track.media_source_id, &neighbor_ids);
|
AddIdIfDefined(track.media_source_id, &neighbor_ids);
|
||||||
} else if (type == RTCPeerConnectionStats::kType) {
|
} else if (type == RTCPeerConnectionStats::kType) {
|
||||||
// RTCPeerConnectionStats does not have any neighbor references.
|
// RTCPeerConnectionStats does not have any neighbor references.
|
||||||
} else if (type == RTCInboundRTPStreamStats::kType ||
|
} else if (type == RTCInboundRTPStreamStats::kType) {
|
||||||
type == RTCOutboundRTPStreamStats::kType) {
|
const auto& inbound_rtp =
|
||||||
const auto& rtp = static_cast<const RTCRTPStreamStats&>(stats);
|
static_cast<const RTCInboundRTPStreamStats&>(stats);
|
||||||
AddIdIfDefined(rtp.track_id, &neighbor_ids);
|
AddIdIfDefined(inbound_rtp.remote_id, &neighbor_ids);
|
||||||
AddIdIfDefined(rtp.transport_id, &neighbor_ids);
|
AddIdIfDefined(inbound_rtp.track_id, &neighbor_ids);
|
||||||
AddIdIfDefined(rtp.codec_id, &neighbor_ids);
|
AddIdIfDefined(inbound_rtp.transport_id, &neighbor_ids);
|
||||||
if (type == RTCOutboundRTPStreamStats::kType) {
|
AddIdIfDefined(inbound_rtp.codec_id, &neighbor_ids);
|
||||||
const auto& outbound_rtp =
|
} else if (type == RTCOutboundRTPStreamStats::kType) {
|
||||||
static_cast<const RTCOutboundRTPStreamStats&>(stats);
|
const auto& outbound_rtp =
|
||||||
AddIdIfDefined(outbound_rtp.media_source_id, &neighbor_ids);
|
static_cast<const RTCOutboundRTPStreamStats&>(stats);
|
||||||
AddIdIfDefined(outbound_rtp.remote_id, &neighbor_ids);
|
AddIdIfDefined(outbound_rtp.remote_id, &neighbor_ids);
|
||||||
}
|
AddIdIfDefined(outbound_rtp.track_id, &neighbor_ids);
|
||||||
|
AddIdIfDefined(outbound_rtp.transport_id, &neighbor_ids);
|
||||||
|
AddIdIfDefined(outbound_rtp.codec_id, &neighbor_ids);
|
||||||
|
AddIdIfDefined(outbound_rtp.media_source_id, &neighbor_ids);
|
||||||
} else if (type == RTCRemoteInboundRtpStreamStats::kType) {
|
} else if (type == RTCRemoteInboundRtpStreamStats::kType) {
|
||||||
const auto& remote_inbound_rtp =
|
const auto& remote_inbound_rtp =
|
||||||
static_cast<const RTCRemoteInboundRtpStreamStats&>(stats);
|
static_cast<const RTCRemoteInboundRtpStreamStats&>(stats);
|
||||||
AddIdIfDefined(remote_inbound_rtp.transport_id, &neighbor_ids);
|
AddIdIfDefined(remote_inbound_rtp.transport_id, &neighbor_ids);
|
||||||
AddIdIfDefined(remote_inbound_rtp.codec_id, &neighbor_ids);
|
AddIdIfDefined(remote_inbound_rtp.codec_id, &neighbor_ids);
|
||||||
AddIdIfDefined(remote_inbound_rtp.local_id, &neighbor_ids);
|
AddIdIfDefined(remote_inbound_rtp.local_id, &neighbor_ids);
|
||||||
|
} else if (type == RTCRemoteOutboundRtpStreamStats::kType) {
|
||||||
|
const auto& remote_outbound_rtp =
|
||||||
|
static_cast<const RTCRemoteOutboundRtpStreamStats&>(stats);
|
||||||
|
// Inherited from `RTCRTPStreamStats`.
|
||||||
|
AddIdIfDefined(remote_outbound_rtp.track_id, &neighbor_ids);
|
||||||
|
AddIdIfDefined(remote_outbound_rtp.transport_id, &neighbor_ids);
|
||||||
|
AddIdIfDefined(remote_outbound_rtp.codec_id, &neighbor_ids);
|
||||||
|
// Direct members of `RTCRemoteOutboundRtpStreamStats`.
|
||||||
|
AddIdIfDefined(remote_outbound_rtp.local_id, &neighbor_ids);
|
||||||
} else if (type == RTCAudioSourceStats::kType ||
|
} else if (type == RTCAudioSourceStats::kType ||
|
||||||
type == RTCVideoSourceStats::kType) {
|
type == RTCVideoSourceStats::kType) {
|
||||||
// RTC[Audio/Video]SourceStats does not have any neighbor references.
|
// RTC[Audio/Video]SourceStats does not have any neighbor references.
|
||||||
|
|
|
@ -606,9 +606,34 @@ RTCReceivedRtpStreamStats::RTCReceivedRtpStreamStats(
|
||||||
|
|
||||||
RTCReceivedRtpStreamStats::~RTCReceivedRtpStreamStats() {}
|
RTCReceivedRtpStreamStats::~RTCReceivedRtpStreamStats() {}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
WEBRTC_RTCSTATS_IMPL(
|
||||||
|
RTCSentRtpStreamStats, RTCRTPStreamStats, "sent-rtp",
|
||||||
|
&packets_sent,
|
||||||
|
&bytes_sent)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RTCSentRtpStreamStats::RTCSentRtpStreamStats(const std::string&& id,
|
||||||
|
int64_t timestamp_us)
|
||||||
|
: RTCSentRtpStreamStats(std::string(id), timestamp_us) {}
|
||||||
|
|
||||||
|
RTCSentRtpStreamStats::RTCSentRtpStreamStats(std::string&& id,
|
||||||
|
int64_t timestamp_us)
|
||||||
|
: RTCRTPStreamStats(std::move(id), timestamp_us),
|
||||||
|
packets_sent("packetsSent"),
|
||||||
|
bytes_sent("bytesSent") {}
|
||||||
|
|
||||||
|
RTCSentRtpStreamStats::RTCSentRtpStreamStats(const RTCSentRtpStreamStats& other)
|
||||||
|
: RTCRTPStreamStats(other),
|
||||||
|
packets_sent(other.packets_sent),
|
||||||
|
bytes_sent(other.bytes_sent) {}
|
||||||
|
|
||||||
|
RTCSentRtpStreamStats::~RTCSentRtpStreamStats() {}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
WEBRTC_RTCSTATS_IMPL(
|
WEBRTC_RTCSTATS_IMPL(
|
||||||
RTCInboundRTPStreamStats, RTCReceivedRtpStreamStats, "inbound-rtp",
|
RTCInboundRTPStreamStats, RTCReceivedRtpStreamStats, "inbound-rtp",
|
||||||
|
&remote_id,
|
||||||
&packets_received,
|
&packets_received,
|
||||||
&fec_packets_received,
|
&fec_packets_received,
|
||||||
&fec_packets_discarded,
|
&fec_packets_discarded,
|
||||||
|
@ -665,6 +690,7 @@ RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(const std::string& id,
|
||||||
RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(std::string&& id,
|
RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(std::string&& id,
|
||||||
int64_t timestamp_us)
|
int64_t timestamp_us)
|
||||||
: RTCReceivedRtpStreamStats(std::move(id), timestamp_us),
|
: RTCReceivedRtpStreamStats(std::move(id), timestamp_us),
|
||||||
|
remote_id("remoteId"),
|
||||||
packets_received("packetsReceived"),
|
packets_received("packetsReceived"),
|
||||||
fec_packets_received("fecPacketsReceived"),
|
fec_packets_received("fecPacketsReceived"),
|
||||||
fec_packets_discarded("fecPacketsDiscarded"),
|
fec_packets_discarded("fecPacketsDiscarded"),
|
||||||
|
@ -716,6 +742,7 @@ RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(std::string&& id,
|
||||||
RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(
|
RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(
|
||||||
const RTCInboundRTPStreamStats& other)
|
const RTCInboundRTPStreamStats& other)
|
||||||
: RTCReceivedRtpStreamStats(other),
|
: RTCReceivedRtpStreamStats(other),
|
||||||
|
remote_id(other.remote_id),
|
||||||
packets_received(other.packets_received),
|
packets_received(other.packets_received),
|
||||||
fec_packets_received(other.fec_packets_received),
|
fec_packets_received(other.fec_packets_received),
|
||||||
fec_packets_discarded(other.fec_packets_discarded),
|
fec_packets_discarded(other.fec_packets_discarded),
|
||||||
|
@ -913,6 +940,37 @@ RTCRemoteInboundRtpStreamStats::RTCRemoteInboundRtpStreamStats(
|
||||||
|
|
||||||
RTCRemoteInboundRtpStreamStats::~RTCRemoteInboundRtpStreamStats() {}
|
RTCRemoteInboundRtpStreamStats::~RTCRemoteInboundRtpStreamStats() {}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
WEBRTC_RTCSTATS_IMPL(
|
||||||
|
RTCRemoteOutboundRtpStreamStats, RTCSentRtpStreamStats,
|
||||||
|
"remote-outbound-rtp",
|
||||||
|
&local_id,
|
||||||
|
&remote_timestamp,
|
||||||
|
&reports_sent)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RTCRemoteOutboundRtpStreamStats::RTCRemoteOutboundRtpStreamStats(
|
||||||
|
const std::string& id,
|
||||||
|
int64_t timestamp_us)
|
||||||
|
: RTCRemoteOutboundRtpStreamStats(std::string(id), timestamp_us) {}
|
||||||
|
|
||||||
|
RTCRemoteOutboundRtpStreamStats::RTCRemoteOutboundRtpStreamStats(
|
||||||
|
std::string&& id,
|
||||||
|
int64_t timestamp_us)
|
||||||
|
: RTCSentRtpStreamStats(std::move(id), timestamp_us),
|
||||||
|
local_id("localId"),
|
||||||
|
remote_timestamp("remoteTimestamp"),
|
||||||
|
reports_sent("reportsSent") {}
|
||||||
|
|
||||||
|
RTCRemoteOutboundRtpStreamStats::RTCRemoteOutboundRtpStreamStats(
|
||||||
|
const RTCRemoteOutboundRtpStreamStats& other)
|
||||||
|
: RTCSentRtpStreamStats(other),
|
||||||
|
local_id(other.local_id),
|
||||||
|
remote_timestamp(other.remote_timestamp),
|
||||||
|
reports_sent(other.reports_sent) {}
|
||||||
|
|
||||||
|
RTCRemoteOutboundRtpStreamStats::~RTCRemoteOutboundRtpStreamStats() {}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
WEBRTC_RTCSTATS_IMPL(RTCMediaSourceStats, RTCStats, "parent-media-source",
|
WEBRTC_RTCSTATS_IMPL(RTCMediaSourceStats, RTCStats, "parent-media-source",
|
||||||
&track_identifier,
|
&track_identifier,
|
||||||
|
|
Loading…
Reference in a new issue