mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00

- Modify munger to take (mutable) std::unique_ptr<SessionDescriptionInterface> rather than cricket::SessionDescription (that latter is embedded in the former) - For all pranswer test cases, do a final SetRemoteDescription(kAnswer) and check that signaling_state == stable Add new test cases: 1) A test case that only applies it as prAnswer on caller (callee is stable) 2) A test case that "scramble" sdb between prAnswer and Anser. Bug: None Change-Id: Ifedd92ade01ae781a2e59d0569133c486c7093fe Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360781 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Jonas Oreland <jonaso@webrtc.org> Commit-Queue: Jonas Oreland <jonaso@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42891}
270 lines
10 KiB
C++
270 lines
10 KiB
C++
/*
|
|
* Copyright 2012 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "pc/test/integration_test_helpers.h"
|
|
|
|
namespace webrtc {
|
|
|
|
PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions() {
|
|
PeerConnectionInterface::RTCOfferAnswerOptions options;
|
|
options.ice_restart = true;
|
|
return options;
|
|
}
|
|
|
|
void RemoveSsrcsAndMsids(std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
|
for (ContentInfo& content : sdp->description()->contents()) {
|
|
content.media_description()->mutable_streams().clear();
|
|
}
|
|
sdp->description()->set_msid_signaling(0);
|
|
}
|
|
|
|
void RemoveSsrcsAndKeepMsids(
|
|
std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
|
for (ContentInfo& content : sdp->description()->contents()) {
|
|
std::string track_id;
|
|
std::vector<std::string> stream_ids;
|
|
if (!content.media_description()->streams().empty()) {
|
|
const StreamParams& first_stream =
|
|
content.media_description()->streams()[0];
|
|
track_id = first_stream.id;
|
|
stream_ids = first_stream.stream_ids();
|
|
}
|
|
content.media_description()->mutable_streams().clear();
|
|
StreamParams new_stream;
|
|
new_stream.id = track_id;
|
|
new_stream.set_stream_ids(stream_ids);
|
|
content.media_description()->AddStream(new_stream);
|
|
}
|
|
}
|
|
|
|
void SetSdpType(std::unique_ptr<SessionDescriptionInterface>& sdp,
|
|
SdpType sdpType) {
|
|
std::string str;
|
|
sdp->ToString(&str);
|
|
sdp = CreateSessionDescription(sdpType, str);
|
|
}
|
|
|
|
int FindFirstMediaStatsIndexByKind(
|
|
const std::string& kind,
|
|
const std::vector<const RTCInboundRtpStreamStats*>& inbound_rtps) {
|
|
for (size_t i = 0; i < inbound_rtps.size(); i++) {
|
|
if (*inbound_rtps[i]->kind == kind) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void ReplaceFirstSsrc(StreamParams& stream, uint32_t ssrc) {
|
|
stream.ssrcs[0] = ssrc;
|
|
for (auto& group : stream.ssrc_groups) {
|
|
group.ssrcs[0] = ssrc;
|
|
}
|
|
}
|
|
|
|
TaskQueueMetronome::TaskQueueMetronome(TimeDelta tick_period)
|
|
: tick_period_(tick_period) {}
|
|
|
|
TaskQueueMetronome::~TaskQueueMetronome() {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
}
|
|
void TaskQueueMetronome::RequestCallOnNextTick(
|
|
absl::AnyInvocable<void() &&> callback) {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
callbacks_.push_back(std::move(callback));
|
|
// Only schedule a tick callback for the first `callback` addition.
|
|
// Schedule on the current task queue to comply with RequestCallOnNextTick
|
|
// requirements.
|
|
if (callbacks_.size() == 1) {
|
|
TaskQueueBase::Current()->PostDelayedTask(
|
|
SafeTask(safety_.flag(),
|
|
[this] {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
std::vector<absl::AnyInvocable<void() &&>> callbacks;
|
|
callbacks_.swap(callbacks);
|
|
for (auto& callback : callbacks)
|
|
std::move(callback)();
|
|
}),
|
|
tick_period_);
|
|
}
|
|
}
|
|
|
|
TimeDelta TaskQueueMetronome::TickPeriod() const {
|
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
|
return tick_period_;
|
|
}
|
|
|
|
// Implementation of PeerConnectionIntegrationWrapper functions
|
|
void PeerConnectionIntegrationWrapper::StartWatchingDelayStats() {
|
|
// Get the baseline numbers for audio_packets and audio_delay.
|
|
auto received_stats = NewGetStats();
|
|
auto rtp_stats =
|
|
received_stats->GetStatsOfType<RTCInboundRtpStreamStats>()[0];
|
|
ASSERT_TRUE(rtp_stats->relative_packet_arrival_delay.has_value());
|
|
ASSERT_TRUE(rtp_stats->packets_received.has_value());
|
|
rtp_stats_id_ = rtp_stats->id();
|
|
audio_packets_stat_ = *rtp_stats->packets_received;
|
|
audio_delay_stat_ = *rtp_stats->relative_packet_arrival_delay;
|
|
audio_samples_stat_ = *rtp_stats->total_samples_received;
|
|
audio_concealed_stat_ = *rtp_stats->concealed_samples;
|
|
}
|
|
|
|
void PeerConnectionIntegrationWrapper::UpdateDelayStats(std::string tag,
|
|
int desc_size) {
|
|
auto report = NewGetStats();
|
|
auto rtp_stats = report->GetAs<RTCInboundRtpStreamStats>(rtp_stats_id_);
|
|
ASSERT_TRUE(rtp_stats);
|
|
auto delta_packets = *rtp_stats->packets_received - audio_packets_stat_;
|
|
auto delta_rpad =
|
|
*rtp_stats->relative_packet_arrival_delay - audio_delay_stat_;
|
|
auto recent_delay = delta_packets > 0 ? delta_rpad / delta_packets : -1;
|
|
// The purpose of these checks is to sound the alarm early if we introduce
|
|
// serious regressions. The numbers are not acceptable for production, but
|
|
// occur on slow bots.
|
|
//
|
|
// An average relative packet arrival delay over the renegotiation of
|
|
// > 100 ms indicates that something is dramatically wrong, and will impact
|
|
// quality for sure.
|
|
// Worst bots:
|
|
// linux_x86_dbg at 0.206
|
|
#if !defined(NDEBUG)
|
|
EXPECT_GT(0.25, recent_delay) << tag << " size " << desc_size;
|
|
#else
|
|
EXPECT_GT(0.1, recent_delay) << tag << " size " << desc_size;
|
|
#endif
|
|
auto delta_samples = *rtp_stats->total_samples_received - audio_samples_stat_;
|
|
auto delta_concealed = *rtp_stats->concealed_samples - audio_concealed_stat_;
|
|
// These limits should be adjusted down as we improve:
|
|
//
|
|
// Concealing more than 4000 samples during a renegotiation is unacceptable.
|
|
// But some bots are slow.
|
|
|
|
// Worst bots:
|
|
// linux_more_configs bot at conceal count 5184
|
|
// android_arm_rel at conceal count 9241
|
|
// linux_x86_dbg at 15174
|
|
#if !defined(NDEBUG)
|
|
EXPECT_GT(18000U, delta_concealed) << "Concealed " << delta_concealed
|
|
<< " of " << delta_samples << " samples";
|
|
#else
|
|
EXPECT_GT(15000U, delta_concealed) << "Concealed " << delta_concealed
|
|
<< " of " << delta_samples << " samples";
|
|
#endif
|
|
// Concealing more than 20% of samples during a renegotiation is
|
|
// unacceptable.
|
|
// Worst bots:
|
|
// Nondebug: Linux32 Release at conceal rate 0.606597 (CI run)
|
|
// Debug: linux_x86_dbg bot at conceal rate 0.854
|
|
// internal bot at conceal rate 0.967 (b/294020344)
|
|
// TODO(https://crbug.com/webrtc/15393): Improve audio quality during
|
|
// renegotiation so that we can reduce these thresholds, 99% is not even
|
|
// close to the 20% deemed unacceptable above or the 0% that would be ideal.
|
|
if (delta_samples > 0) {
|
|
#if !defined(NDEBUG)
|
|
EXPECT_LT(1.0 * delta_concealed / delta_samples, 0.99)
|
|
<< "Concealed " << delta_concealed << " of " << delta_samples
|
|
<< " samples";
|
|
#else
|
|
EXPECT_LT(1.0 * delta_concealed / delta_samples, 0.7)
|
|
<< "Concealed " << delta_concealed << " of " << delta_samples
|
|
<< " samples";
|
|
#endif
|
|
}
|
|
// Increment trailing counters
|
|
audio_packets_stat_ = *rtp_stats->packets_received;
|
|
audio_delay_stat_ = *rtp_stats->relative_packet_arrival_delay;
|
|
audio_samples_stat_ = *rtp_stats->total_samples_received;
|
|
audio_concealed_stat_ = *rtp_stats->concealed_samples;
|
|
}
|
|
|
|
bool PeerConnectionIntegrationWrapper::Init(
|
|
const PeerConnectionFactory::Options* options,
|
|
const PeerConnectionInterface::RTCConfiguration* config,
|
|
PeerConnectionDependencies dependencies,
|
|
rtc::SocketServer* socket_server,
|
|
rtc::Thread* network_thread,
|
|
rtc::Thread* worker_thread,
|
|
std::unique_ptr<FakeRtcEventLogFactory> event_log_factory,
|
|
bool reset_encoder_factory,
|
|
bool reset_decoder_factory,
|
|
bool create_media_engine) {
|
|
// There's an error in this test code if Init ends up being called twice.
|
|
RTC_DCHECK(!peer_connection_);
|
|
RTC_DCHECK(!peer_connection_factory_);
|
|
|
|
fake_network_manager_.reset(new rtc::FakeNetworkManager());
|
|
fake_network_manager_->AddInterface(kDefaultLocalAddress);
|
|
|
|
socket_factory_.reset(new rtc::BasicPacketSocketFactory(socket_server));
|
|
|
|
std::unique_ptr<cricket::PortAllocator> port_allocator(
|
|
new cricket::BasicPortAllocator(fake_network_manager_.get(),
|
|
socket_factory_.get()));
|
|
port_allocator_ = port_allocator.get();
|
|
fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
|
|
if (!fake_audio_capture_module_) {
|
|
return false;
|
|
}
|
|
rtc::Thread* const signaling_thread = rtc::Thread::Current();
|
|
|
|
PeerConnectionFactoryDependencies pc_factory_dependencies;
|
|
pc_factory_dependencies.network_thread = network_thread;
|
|
pc_factory_dependencies.worker_thread = worker_thread;
|
|
pc_factory_dependencies.signaling_thread = signaling_thread;
|
|
pc_factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
|
|
pc_factory_dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
|
|
pc_factory_dependencies.decode_metronome =
|
|
std::make_unique<TaskQueueMetronome>(TimeDelta::Millis(8));
|
|
|
|
pc_factory_dependencies.adm = fake_audio_capture_module_;
|
|
if (create_media_engine) {
|
|
EnableMediaWithDefaults(pc_factory_dependencies);
|
|
}
|
|
|
|
if (reset_encoder_factory) {
|
|
pc_factory_dependencies.video_encoder_factory.reset();
|
|
}
|
|
if (reset_decoder_factory) {
|
|
pc_factory_dependencies.video_decoder_factory.reset();
|
|
}
|
|
|
|
if (!pc_factory_dependencies.audio_processing) {
|
|
// If the standard Creation method for APM returns a null pointer, instead
|
|
// use the builder for testing to create an APM object.
|
|
pc_factory_dependencies.audio_processing =
|
|
AudioProcessingBuilderForTesting().Create();
|
|
}
|
|
|
|
if (event_log_factory) {
|
|
event_log_factory_ = event_log_factory.get();
|
|
pc_factory_dependencies.event_log_factory = std::move(event_log_factory);
|
|
} else {
|
|
pc_factory_dependencies.event_log_factory =
|
|
std::make_unique<RtcEventLogFactory>();
|
|
}
|
|
peer_connection_factory_ =
|
|
CreateModularPeerConnectionFactory(std::move(pc_factory_dependencies));
|
|
|
|
if (!peer_connection_factory_) {
|
|
return false;
|
|
}
|
|
if (options) {
|
|
peer_connection_factory_->SetOptions(*options);
|
|
}
|
|
if (config) {
|
|
sdp_semantics_ = config->sdp_semantics;
|
|
}
|
|
|
|
dependencies.allocator = std::move(port_allocator);
|
|
peer_connection_ = CreatePeerConnection(config, std::move(dependencies));
|
|
return peer_connection_.get() != nullptr;
|
|
}
|
|
|
|
} // namespace webrtc
|