Populate RTCInboundRtpStreamStats::playoutId when appropriate
Bug: webrtc:14653 Change-Id: I0c59604b218d0839a126c02914626b8ed2bee76c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/291040 Commit-Queue: Fredrik Hernqvist <fhernqvist@google.com> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39149}
This commit is contained in:
parent
4abca6699d
commit
828de8036d
@ -447,6 +447,7 @@ class RTC_EXPORT RTCInboundRTPStreamStats final
|
||||
|
||||
// TODO(https://crbug.com/webrtc/14174): Implement trackIdentifier and kind.
|
||||
|
||||
RTCStatsMember<std::string> playout_id;
|
||||
RTCStatsMember<std::string> track_identifier;
|
||||
RTCStatsMember<std::string> mid;
|
||||
RTCStatsMember<std::string> remote_id;
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "api/candidate.h"
|
||||
#include "api/dtls_transport_interface.h"
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "api/media_types.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/stats/rtc_stats.h"
|
||||
@ -70,6 +71,8 @@ namespace {
|
||||
const char kDirectionInbound = 'I';
|
||||
const char kDirectionOutbound = 'O';
|
||||
|
||||
const char* kAudioPlayoutSingletonId = "AP";
|
||||
|
||||
// TODO(https://crbug.com/webrtc/10656): Consider making IDs less predictable.
|
||||
std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) {
|
||||
return "CF" + fingerprint;
|
||||
@ -518,7 +521,7 @@ std::unique_ptr<RTCAudioPlayoutStats> CreateAudioPlayoutStats(
|
||||
const AudioDeviceModule::Stats& audio_device_stats,
|
||||
webrtc::Timestamp timestamp) {
|
||||
auto stats = std::make_unique<RTCAudioPlayoutStats>(
|
||||
/*id=*/"AP", timestamp);
|
||||
/*id=*/kAudioPlayoutSingletonId, timestamp);
|
||||
stats->synthesized_samples_duration =
|
||||
audio_device_stats.synthesized_samples_duration_s;
|
||||
stats->synthesized_samples_events =
|
||||
@ -2017,6 +2020,12 @@ void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
|
||||
.value());
|
||||
inbound_audio->track_identifier = audio_track->id();
|
||||
}
|
||||
if (audio_device_stats_ && stats.media_type == cricket::MEDIA_TYPE_AUDIO &&
|
||||
stats.current_direction &&
|
||||
(*stats.current_direction == RtpTransceiverDirection::kSendRecv ||
|
||||
*stats.current_direction == RtpTransceiverDirection::kRecvOnly)) {
|
||||
inbound_audio->playout_id = kAudioPlayoutSingletonId;
|
||||
}
|
||||
auto* inbound_audio_ptr = report->TryAddStats(std::move(inbound_audio));
|
||||
if (!inbound_audio_ptr) {
|
||||
RTC_LOG(LS_ERROR)
|
||||
@ -2477,6 +2486,10 @@ void RTCStatsCollector::PrepareTransceiverStatsInfosAndCallStats_s_w_n() {
|
||||
call_stats_ = pc_->GetCallStats();
|
||||
audio_device_stats_ = pc_->GetAudioDeviceStats();
|
||||
});
|
||||
|
||||
for (auto& stats : transceiver_stats_infos_) {
|
||||
stats.current_direction = stats.transceiver->current_direction();
|
||||
}
|
||||
}
|
||||
|
||||
void RTCStatsCollector::OnSctpDataChannelCreated(SctpDataChannel* channel) {
|
||||
|
||||
@ -171,6 +171,7 @@ class RTCStatsCollector : public rtc::RefCountInterface,
|
||||
absl::optional<std::string> mid;
|
||||
absl::optional<std::string> transport_name;
|
||||
TrackMediaInfoMap track_media_info_map;
|
||||
absl::optional<RtpTransceiverDirection> current_direction;
|
||||
};
|
||||
|
||||
void DeliverCachedReport(
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "api/media_stream_track.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/rtp_transceiver_direction.h"
|
||||
#include "api/stats/rtc_stats.h"
|
||||
#include "api/stats/rtc_stats_report.h"
|
||||
#include "api/stats/rtcstats_objects.h"
|
||||
@ -2494,6 +2495,11 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
|
||||
stats_->SetupRemoteTrackAndReceiver(
|
||||
cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
|
||||
|
||||
// Needed for playoutId to be populated.
|
||||
pc_->SetAudioDeviceStats(AudioDeviceModule::Stats());
|
||||
pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
|
||||
RtpTransceiverDirection::kSendRecv);
|
||||
|
||||
rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
|
||||
|
||||
auto stats_of_track_type =
|
||||
@ -2538,6 +2544,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
|
||||
expected_audio.relative_packet_arrival_delay = 16;
|
||||
expected_audio.interruption_count = 7788;
|
||||
expected_audio.total_interruption_duration = 778.899;
|
||||
expected_audio.playout_id = "AP";
|
||||
|
||||
ASSERT_TRUE(report->Get(expected_audio.id()));
|
||||
EXPECT_EQ(
|
||||
@ -2562,6 +2569,44 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
|
||||
EXPECT_TRUE(report->Get(*expected_audio.codec_id));
|
||||
}
|
||||
|
||||
TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio_PlayoutId) {
|
||||
cricket::VoiceMediaInfo voice_media_info;
|
||||
|
||||
voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
|
||||
voice_media_info.receivers[0].local_stats.push_back(
|
||||
cricket::SsrcReceiverInfo());
|
||||
voice_media_info.receivers[0].local_stats[0].ssrc = 1;
|
||||
|
||||
pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
|
||||
stats_->SetupRemoteTrackAndReceiver(
|
||||
cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
|
||||
// Needed for playoutId to be populated.
|
||||
pc_->SetAudioDeviceStats(AudioDeviceModule::Stats());
|
||||
|
||||
{
|
||||
// We do not expect a playout id when only sending.
|
||||
pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
|
||||
RtpTransceiverDirection::kSendOnly);
|
||||
rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
|
||||
ASSERT_TRUE(report->Get("ITTransportName1A1"));
|
||||
auto stats =
|
||||
report->Get("ITTransportName1A1")->cast_to<RTCInboundRTPStreamStats>();
|
||||
ASSERT_FALSE(stats.playout_id.is_defined());
|
||||
}
|
||||
{
|
||||
// We do expect a playout id when receiving.
|
||||
pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
|
||||
RtpTransceiverDirection::kRecvOnly);
|
||||
rtc::scoped_refptr<const RTCStatsReport> report =
|
||||
stats_->GetFreshStatsReport();
|
||||
ASSERT_TRUE(report->Get("ITTransportName1A1"));
|
||||
auto stats =
|
||||
report->Get("ITTransportName1A1")->cast_to<RTCInboundRTPStreamStats>();
|
||||
ASSERT_TRUE(stats.playout_id.is_defined());
|
||||
EXPECT_EQ(*stats.playout_id, "AP");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
|
||||
cricket::VideoMediaInfo video_media_info;
|
||||
|
||||
|
||||
@ -416,6 +416,9 @@ class RTCStatsReportVerifier {
|
||||
} else if (stats.type() == RTCTransportStats::kType) {
|
||||
verify_successful &=
|
||||
VerifyRTCTransportStats(stats.cast_to<RTCTransportStats>());
|
||||
} else if (stats.type() == RTCAudioPlayoutStats::kType) {
|
||||
verify_successful &=
|
||||
VerifyRTCAudioPlayoutSTats(stats.cast_to<RTCAudioPlayoutStats>());
|
||||
} else {
|
||||
EXPECT_TRUE(false) << "Unrecognized stats type: " << stats.type();
|
||||
verify_successful = false;
|
||||
@ -908,6 +911,12 @@ class RTCStatsReportVerifier {
|
||||
verifier.TestMemberIsUndefined(inbound_stream.min_playout_delay);
|
||||
verifier.TestMemberIsUndefined(inbound_stream.goog_timing_frame_info);
|
||||
}
|
||||
if (inbound_stream.kind.is_defined() && *inbound_stream.kind == "audio") {
|
||||
verifier.TestMemberIsDefined(inbound_stream.playout_id);
|
||||
} else {
|
||||
verifier.TestMemberIsUndefined(inbound_stream.playout_id);
|
||||
}
|
||||
|
||||
return verifier.ExpectAllMembersSuccessfullyTested();
|
||||
}
|
||||
|
||||
@ -1119,6 +1128,20 @@ class RTCStatsReportVerifier {
|
||||
return verifier.ExpectAllMembersSuccessfullyTested();
|
||||
}
|
||||
|
||||
bool VerifyRTCAudioPlayoutSTats(const RTCAudioPlayoutStats& audio_playout) {
|
||||
RTCStatsVerifier verifier(report_.get(), &audio_playout);
|
||||
verifier.TestMemberIsNonNegative<uint64_t>(
|
||||
audio_playout.synthesized_samples_events);
|
||||
verifier.TestMemberIsNonNegative<double>(
|
||||
audio_playout.synthesized_samples_duration);
|
||||
verifier.TestMemberIsNonNegative<uint64_t>(
|
||||
audio_playout.total_samples_count);
|
||||
verifier.TestMemberIsNonNegative<double>(
|
||||
audio_playout.total_samples_duration);
|
||||
verifier.TestMemberIsNonNegative<double>(audio_playout.total_playout_delay);
|
||||
return verifier.ExpectAllMembersSuccessfullyTested();
|
||||
}
|
||||
|
||||
private:
|
||||
rtc::scoped_refptr<const RTCStatsReport> report_;
|
||||
};
|
||||
|
||||
@ -108,6 +108,7 @@ std::vector<const std::string*> GetStatsReferencedIds(const RTCStats& stats) {
|
||||
AddIdIfDefined(inbound_rtp.track_id, &neighbor_ids);
|
||||
AddIdIfDefined(inbound_rtp.transport_id, &neighbor_ids);
|
||||
AddIdIfDefined(inbound_rtp.codec_id, &neighbor_ids);
|
||||
AddIdIfDefined(inbound_rtp.playout_id, &neighbor_ids);
|
||||
} else if (type == RTCOutboundRTPStreamStats::kType) {
|
||||
const auto& outbound_rtp =
|
||||
static_cast<const RTCOutboundRTPStreamStats&>(stats);
|
||||
@ -135,12 +136,13 @@ std::vector<const std::string*> GetStatsReferencedIds(const RTCStats& stats) {
|
||||
type == RTCVideoSourceStats::kType) {
|
||||
// RTC[Audio/Video]SourceStats does not have any neighbor references.
|
||||
} else if (type == RTCTransportStats::kType) {
|
||||
// RTCTransportStats does not have any neighbor references.
|
||||
const auto& transport = static_cast<const RTCTransportStats&>(stats);
|
||||
AddIdIfDefined(transport.rtcp_transport_stats_id, &neighbor_ids);
|
||||
AddIdIfDefined(transport.selected_candidate_pair_id, &neighbor_ids);
|
||||
AddIdIfDefined(transport.local_certificate_id, &neighbor_ids);
|
||||
AddIdIfDefined(transport.remote_certificate_id, &neighbor_ids);
|
||||
} else if (type == RTCAudioPlayoutStats::kType) {
|
||||
// RTCAudioPlayoutStats does not have any neighbor references.
|
||||
} else {
|
||||
RTC_DCHECK_NOTREACHED() << "Unrecognized type: " << type;
|
||||
}
|
||||
|
||||
@ -136,6 +136,10 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule {
|
||||
int32_t EnableBuiltInNS(bool enable) override { return -1; }
|
||||
|
||||
int32_t GetPlayoutUnderrunCount() const override { return -1; }
|
||||
|
||||
absl::optional<webrtc::AudioDeviceModule::Stats> GetStats() const override {
|
||||
return webrtc::AudioDeviceModule::Stats();
|
||||
}
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(
|
||||
webrtc::AudioParameters* params) const override {
|
||||
|
||||
@ -528,6 +528,7 @@ WEBRTC_RTCSTATS_IMPL(
|
||||
&audio_level,
|
||||
&total_audio_energy,
|
||||
&total_samples_duration,
|
||||
&playout_id,
|
||||
&frames_received,
|
||||
&frame_width,
|
||||
&frame_height,
|
||||
@ -565,6 +566,7 @@ WEBRTC_RTCSTATS_IMPL(
|
||||
RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(std::string id,
|
||||
Timestamp timestamp)
|
||||
: RTCReceivedRtpStreamStats(std::move(id), timestamp),
|
||||
playout_id("playoutId"),
|
||||
track_identifier("trackIdentifier"),
|
||||
mid("mid"),
|
||||
remote_id("remoteId"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user