Add support of fast media sending in peer connection e2e test

Start sending media from the peer when it's ICE connection state is
connected.

Bug: webrtc:10138
Change-Id: I9f5a1cd917317a3ebadd7c156563035b0bbecf2a
Reviewed-on: https://webrtc-review.googlesource.com/c/121956
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Peter Slatala <psla@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26698}
This commit is contained in:
Artem Titov 2019-02-14 10:51:27 +01:00 committed by Commit Bot
parent ceba6ae2a7
commit bf9e01ab4e
5 changed files with 123 additions and 72 deletions

View File

@ -54,7 +54,7 @@ specific_include_rules = {
"+pc/test/mock_peer_connection_observers.h",
"+p2p/client/basic_port_allocator.h",
],
".*peer_connection_quality_test\.h": [
".*peer_connection_quality_test\.(h|cc)": [
"+pc",
]
}

View File

@ -1,3 +1,5 @@
#include <utility>
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
@ -13,9 +15,11 @@
#include <utility>
#include "absl/memory/memory.h"
#include "api/media_stream_interface.h"
#include "api/peer_connection_interface.h"
#include "api/scoped_refptr.h"
#include "api/units/time_delta.h"
#include "pc/test/mock_peer_connection_observers.h"
#include "rtc_base/bind.h"
#include "rtc_base/gunit.h"
#include "system_wrappers/include/cpu_info.h"
@ -49,6 +53,41 @@ std::string VideoConfigSourcePresenceToString(const VideoConfig& video_config) {
return builder.str();
}
class FixturePeerConnectionObserver : public MockPeerConnectionObserver {
public:
// |on_track_callback| will be called when any new track will be added to peer
// connection.
// |on_connected_callback| will be called when peer connection will come to
// either connected or completed state. Client should notice that in the case
// of reconnect this callback can be called again, so it should be tolerant
// to such behavior.
FixturePeerConnectionObserver(
std::function<void(rtc::scoped_refptr<RtpTransceiverInterface>)>
on_track_callback,
std::function<void()> on_connected_callback)
: on_track_callback_(std::move(on_track_callback)),
on_connected_callback_(std::move(on_connected_callback)) {}
void OnTrack(
rtc::scoped_refptr<RtpTransceiverInterface> transceiver) override {
MockPeerConnectionObserver::OnTrack(transceiver);
on_track_callback_(transceiver);
}
void OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) override {
MockPeerConnectionObserver::OnIceConnectionChange(new_state);
if (ice_connected_) {
on_connected_callback_();
}
}
private:
std::function<void(rtc::scoped_refptr<RtpTransceiverInterface>)>
on_track_callback_;
std::function<void()> on_connected_callback_;
};
} // namespace
PeerConnectionE2EQualityTest::PeerConnectionE2EQualityTest(
@ -110,12 +149,28 @@ void PeerConnectionE2EQualityTest::Run(
alice_params->audio_config
? alice_params->audio_config->output_dump_file_name
: absl::nullopt;
// Copy Alice and Bob video configs to correctly pass them into lambdas.
std::vector<VideoConfig> alice_video_configs = alice_params->video_configs;
std::vector<VideoConfig> bob_video_configs = bob_params->video_configs;
alice_ = TestPeer::CreateTestPeer(
std::move(alice_components), std::move(alice_params),
absl::make_unique<FixturePeerConnectionObserver>(
[this, bob_video_configs](
rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
SetupVideoSink(transceiver, bob_video_configs);
},
[this]() { StartVideo(alice_video_sources_); }),
video_quality_analyzer_injection_helper_.get(), signaling_thread.get(),
alice_audio_output_dump_file_name);
bob_ = TestPeer::CreateTestPeer(
std::move(bob_components), std::move(bob_params),
absl::make_unique<FixturePeerConnectionObserver>(
[this, alice_video_configs](
rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
SetupVideoSink(transceiver, alice_video_configs);
},
[this]() { StartVideo(bob_video_sources_); }),
video_quality_analyzer_injection_helper_.get(), signaling_thread.get(),
bob_audio_output_dump_file_name);
@ -144,7 +199,8 @@ void PeerConnectionE2EQualityTest::Run(
RTC_CHECK(!bob_);
// Ensuring that FrameGeneratorCapturerVideoTrackSource and VideoFrameWriter
// are destroyed on the right thread.
RTC_CHECK(video_sources_.empty());
RTC_CHECK(alice_video_sources_.empty());
RTC_CHECK(bob_video_sources_.empty());
RTC_CHECK(video_writers_.empty());
}
@ -211,35 +267,60 @@ void PeerConnectionE2EQualityTest::ValidateParams(std::vector<Params*> params) {
RTC_CHECK_GT(media_streams_count, 0) << "No media in the call.";
}
void PeerConnectionE2EQualityTest::SetupVideoSink(
rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
std::vector<VideoConfig> remote_video_configs) {
const rtc::scoped_refptr<MediaStreamTrackInterface>& track =
transceiver->receiver()->track();
if (track->kind() != MediaStreamTrackInterface::kVideoKind) {
return;
}
VideoConfig* video_config = nullptr;
for (auto& config : remote_video_configs) {
if (config.stream_label == track->id()) {
video_config = &config;
break;
}
}
RTC_CHECK(video_config);
VideoFrameWriter* writer = MaybeCreateVideoWriter(
video_config->output_dump_file_name, *video_config);
// It is safe to cast here, because it is checked above that
// track->kind() is kVideoKind.
auto* video_track = static_cast<VideoTrackInterface*>(track.get());
std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> video_sink =
video_quality_analyzer_injection_helper_->CreateVideoSink(writer);
video_track->AddOrUpdateSink(video_sink.get(), rtc::VideoSinkWants());
output_video_sinks_.push_back(std::move(video_sink));
}
void PeerConnectionE2EQualityTest::RunOnSignalingThread(RunParams run_params) {
AddMedia(alice_.get());
AddMedia(bob_.get());
alice_video_sources_ = AddMedia(alice_.get());
bob_video_sources_ = AddMedia(bob_.get());
SetupCall();
WaitForTransceiversSetup(alice_->params(), bob_.get());
WaitForTransceiversSetup(bob_->params(), alice_.get());
SetupVideoSink(alice_->params(), bob_.get());
SetupVideoSink(bob_->params(), alice_.get());
StartVideo();
rtc::Event done;
done.Wait(static_cast<int>(run_params.run_duration.ms()));
TearDownCall();
}
void PeerConnectionE2EQualityTest::AddMedia(TestPeer* peer) {
AddVideo(peer);
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
PeerConnectionE2EQualityTest::AddMedia(TestPeer* peer) {
if (peer->params()->audio_config) {
AddAudio(peer);
}
return AddVideo(peer);
}
void PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) {
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) {
// Params here valid because of pre-run validation.
Params* params = peer->params();
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>> out;
for (auto video_config : params->video_configs) {
// Create video generator.
std::unique_ptr<FrameGenerator> frame_generator =
@ -261,7 +342,7 @@ void PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) {
rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource> source =
new rtc::RefCountedObject<FrameGeneratorCapturerVideoTrackSource>(
move(capturer));
video_sources_.push_back(source);
out.push_back(source);
RTC_LOG(INFO) << "Adding video with video_config.stream_label="
<< video_config.stream_label.value();
rtc::scoped_refptr<VideoTrackInterface> track =
@ -269,6 +350,7 @@ void PeerConnectionE2EQualityTest::AddVideo(TestPeer* peer) {
source);
peer->AddTransceiver(track);
}
return out;
}
std::unique_ptr<FrameGenerator>
@ -332,58 +414,21 @@ void PeerConnectionE2EQualityTest::SetupCall() {
ASSERT_TRUE_WAIT(alice_->IsIceConnected(), kDefaultTimeoutMs);
}
void PeerConnectionE2EQualityTest::WaitForTransceiversSetup(
Params* params,
TestPeer* remote_peer) {
uint64_t expected_remote_transceivers =
params->video_configs.size() + (params->audio_config ? 1 : 0);
ASSERT_EQ_WAIT(remote_peer->observer()->on_track_transceivers_.size(),
expected_remote_transceivers, kDefaultTimeoutMs);
}
void PeerConnectionE2EQualityTest::SetupVideoSink(Params* params,
TestPeer* remote_peer) {
if (params->video_configs.empty()) {
return;
}
std::map<std::string, VideoConfig*> video_configs_by_label;
for (auto& video_config : params->video_configs) {
video_configs_by_label.insert(std::pair<std::string, VideoConfig*>(
video_config.stream_label.value(), &video_config));
}
for (const auto& transceiver :
remote_peer->observer()->on_track_transceivers_) {
const rtc::scoped_refptr<MediaStreamTrackInterface>& track =
transceiver->receiver()->track();
if (track->kind() != MediaStreamTrackInterface::kVideoKind) {
continue;
void PeerConnectionE2EQualityTest::StartVideo(
const std::vector<
rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>& sources) {
for (auto& source : sources) {
if (source->state() != MediaSourceInterface::SourceState::kLive) {
source->Start();
}
auto it = video_configs_by_label.find(track->id());
RTC_CHECK(it != video_configs_by_label.end());
VideoConfig* video_config = it->second;
VideoFrameWriter* writer = MaybeCreateVideoWriter(
video_config->output_dump_file_name, *video_config);
// It is safe to cast here, because it is checked above that track->kind()
// is kVideoKind.
auto* video_track = static_cast<VideoTrackInterface*>(track.get());
std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> video_sink =
video_quality_analyzer_injection_helper_->CreateVideoSink(writer);
video_track->AddOrUpdateSink(video_sink.get(), rtc::VideoSinkWants());
output_video_sinks_.push_back(std::move(video_sink));
}
}
void PeerConnectionE2EQualityTest::StartVideo() {
for (const auto& video_source : video_sources_) {
video_source->Start();
}
}
void PeerConnectionE2EQualityTest::TearDownCall() {
for (const auto& video_source : video_sources_) {
for (const auto& video_source : alice_video_sources_) {
video_source->Stop();
}
for (const auto& video_source : bob_video_sources_) {
video_source->Stop();
}
@ -394,7 +439,8 @@ void PeerConnectionE2EQualityTest::TearDownCall() {
video_writer->Close();
}
video_sources_.clear();
alice_video_sources_.clear();
bob_video_sources_.clear();
video_writers_.clear();
alice_.reset();
bob_.reset();

View File

@ -55,17 +55,21 @@ class PeerConnectionE2EQualityTest
// Validate peer's parameters, also ensure uniqueness of all video stream
// labels.
void ValidateParams(std::vector<Params*> params);
void SetupVideoSink(rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
std::vector<VideoConfig> remote_video_configs);
// Have to be run on the signaling thread.
void RunOnSignalingThread(RunParams run_params);
void AddMedia(TestPeer* peer);
void AddVideo(TestPeer* peer);
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
AddMedia(TestPeer* peer);
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
AddVideo(TestPeer* peer);
std::unique_ptr<FrameGenerator> CreateFrameGenerator(
const VideoConfig& video_config);
void AddAudio(TestPeer* peer);
void SetupCall();
void WaitForTransceiversSetup(Params* params, TestPeer* remote_peer);
void SetupVideoSink(Params* params, TestPeer* remote_peer);
void StartVideo();
void StartVideo(
const std::vector<
rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>& sources);
void TearDownCall();
VideoFrameWriter* MaybeCreateVideoWriter(
absl::optional<std::string> file_name,
@ -81,7 +85,9 @@ class PeerConnectionE2EQualityTest
std::unique_ptr<TestPeer> bob_;
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
video_sources_;
alice_video_sources_;
std::vector<rtc::scoped_refptr<FrameGeneratorCapturerVideoTrackSource>>
bob_video_sources_;
std::vector<std::unique_ptr<VideoFrameWriter>> video_writers_;
std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>>
output_video_sinks_;

View File

@ -245,6 +245,7 @@ PeerConnectionDependencies CreatePCDependencies(
std::unique_ptr<TestPeer> TestPeer::CreateTestPeer(
std::unique_ptr<InjectableComponents> components,
std::unique_ptr<Params> params,
std::unique_ptr<MockPeerConnectionObserver> observer,
VideoQualityAnalyzerInjectionHelper* video_analyzer_helper,
rtc::Thread* signaling_thread,
absl::optional<std::string> audio_output_file_name) {
@ -253,9 +254,6 @@ std::unique_ptr<TestPeer> TestPeer::CreateTestPeer(
SetMandatoryEntities(components.get());
params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
std::unique_ptr<MockPeerConnectionObserver> observer =
absl::make_unique<MockPeerConnectionObserver>();
// Create peer connection factory.
PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies(
std::move(components->pcf_dependencies), params->audio_config,

View File

@ -53,6 +53,7 @@ class TestPeer final : public PeerConnectionWrapper {
static std::unique_ptr<TestPeer> CreateTestPeer(
std::unique_ptr<InjectableComponents> components,
std::unique_ptr<Params> params,
std::unique_ptr<MockPeerConnectionObserver> observer,
VideoQualityAnalyzerInjectionHelper* video_analyzer_helper,
rtc::Thread* signaling_thread,
absl::optional<std::string> audio_output_file_name);