2013-08-05 12:01:36 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2013 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.
|
|
|
|
|
*/
|
2013-11-18 11:45:11 +00:00
|
|
|
#include <algorithm>
|
2016-02-03 14:14:49 -08:00
|
|
|
#include <list>
|
2013-08-05 12:01:36 +00:00
|
|
|
#include <map>
|
2016-03-01 11:52:33 -08:00
|
|
|
#include <memory>
|
2013-11-18 11:45:11 +00:00
|
|
|
#include <sstream>
|
|
|
|
|
#include <string>
|
2016-03-31 10:24:26 -07:00
|
|
|
#include <vector>
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "api/optional.h"
|
|
|
|
|
#include "api/video_codecs/video_encoder.h"
|
|
|
|
|
#include "call/call.h"
|
|
|
|
|
#include "common_video/include/frame_callback.h"
|
|
|
|
|
#include "logging/rtc_event_log/rtc_event_log.h"
|
|
|
|
|
#include "media/base/fakevideorenderer.h"
|
|
|
|
|
#include "media/base/mediaconstants.h"
|
|
|
|
|
#include "media/engine/internalencoderfactory.h"
|
|
|
|
|
#include "media/engine/simulcast_encoder_adapter.h"
|
|
|
|
|
#include "media/engine/webrtcvideoencoderfactory.h"
|
|
|
|
|
#include "modules/include/module_common_types.h"
|
|
|
|
|
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
|
|
|
|
|
#include "modules/rtp_rtcp/source/byte_io.h"
|
|
|
|
|
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
|
|
|
|
|
#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
|
|
|
|
|
#include "modules/rtp_rtcp/source/rtp_format.h"
|
|
|
|
|
#include "modules/rtp_rtcp/source/rtp_utility.h"
|
|
|
|
|
#include "modules/video_coding/codecs/h264/include/h264.h"
|
|
|
|
|
#include "modules/video_coding/codecs/vp8/include/vp8.h"
|
|
|
|
|
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
|
|
|
|
#include "modules/video_coding/include/video_coding_defines.h"
|
|
|
|
|
#include "rtc_base/checks.h"
|
|
|
|
|
#include "rtc_base/event.h"
|
|
|
|
|
#include "rtc_base/file.h"
|
|
|
|
|
#include "rtc_base/ptr_util.h"
|
|
|
|
|
#include "rtc_base/random.h"
|
|
|
|
|
#include "rtc_base/rate_limiter.h"
|
|
|
|
|
#include "system_wrappers/include/metrics.h"
|
|
|
|
|
#include "system_wrappers/include/metrics_default.h"
|
|
|
|
|
#include "system_wrappers/include/sleep.h"
|
|
|
|
|
#include "test/call_test.h"
|
|
|
|
|
#include "test/direct_transport.h"
|
|
|
|
|
#include "test/encoder_settings.h"
|
|
|
|
|
#include "test/fake_decoder.h"
|
|
|
|
|
#include "test/fake_encoder.h"
|
|
|
|
|
#include "test/field_trial.h"
|
|
|
|
|
#include "test/frame_generator.h"
|
|
|
|
|
#include "test/frame_generator_capturer.h"
|
|
|
|
|
#include "test/gmock.h"
|
|
|
|
|
#include "test/gtest.h"
|
|
|
|
|
#include "test/null_transport.h"
|
|
|
|
|
#include "test/rtcp_packet_parser.h"
|
|
|
|
|
#include "test/rtp_rtcp_observer.h"
|
|
|
|
|
#include "test/testsupport/fileutils.h"
|
|
|
|
|
#include "test/testsupport/perf_test.h"
|
|
|
|
|
#include "video/transport_adapter.h"
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2017-06-22 01:47:20 -07:00
|
|
|
// Flaky under MemorySanitizer: bugs.webrtc.org/7419
|
2017-03-29 02:07:33 -07:00
|
|
|
#if defined(MEMORY_SANITIZER)
|
2017-06-22 01:47:20 -07:00
|
|
|
#define MAYBE_InitialProbing DISABLED_InitialProbing
|
|
|
|
|
// Fails on iOS bots: bugs.webrtc.org/7851
|
|
|
|
|
#elif defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
|
2017-03-29 02:07:33 -07:00
|
|
|
#define MAYBE_InitialProbing DISABLED_InitialProbing
|
|
|
|
|
#else
|
|
|
|
|
#define MAYBE_InitialProbing InitialProbing
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-08-05 12:01:36 +00:00
|
|
|
namespace webrtc {
|
|
|
|
|
|
2017-04-10 16:57:57 -07:00
|
|
|
namespace {
|
|
|
|
|
constexpr int kSilenceTimeoutMs = 2000;
|
|
|
|
|
}
|
2013-10-17 14:14:42 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
class EndToEndTest : public test::CallTest,
|
|
|
|
|
public testing::WithParamInterface<std::string> {
|
2013-08-05 12:01:36 +00:00
|
|
|
public:
|
2017-10-23 12:42:17 +02:00
|
|
|
EndToEndTest() : field_trial_(GetParam()) {}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
virtual ~EndToEndTest() {
|
2015-12-21 03:14:00 -08:00
|
|
|
EXPECT_EQ(nullptr, video_send_stream_);
|
|
|
|
|
EXPECT_TRUE(video_receive_streams_.empty());
|
2013-08-19 16:09:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
2015-09-28 09:59:31 -07:00
|
|
|
class UnusedTransport : public Transport {
|
2014-09-03 16:17:12 +00:00
|
|
|
private:
|
2015-10-02 03:39:33 -07:00
|
|
|
bool SendRtp(const uint8_t* packet,
|
|
|
|
|
size_t length,
|
|
|
|
|
const PacketOptions& options) override {
|
2014-09-03 16:17:12 +00:00
|
|
|
ADD_FAILURE() << "Unexpected RTP sent.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
bool SendRtcp(const uint8_t* packet, size_t length) override {
|
2014-09-03 16:17:12 +00:00
|
|
|
ADD_FAILURE() << "Unexpected RTCP sent.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-03-22 15:32:27 -07:00
|
|
|
class RequiredTransport : public Transport {
|
|
|
|
|
public:
|
|
|
|
|
RequiredTransport(bool rtp_required, bool rtcp_required)
|
|
|
|
|
: need_rtp_(rtp_required), need_rtcp_(rtcp_required) {}
|
|
|
|
|
~RequiredTransport() {
|
|
|
|
|
if (need_rtp_) {
|
|
|
|
|
ADD_FAILURE() << "Expected RTP packet not sent.";
|
|
|
|
|
}
|
|
|
|
|
if (need_rtcp_) {
|
|
|
|
|
ADD_FAILURE() << "Expected RTCP packet not sent.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
bool SendRtp(const uint8_t* packet,
|
|
|
|
|
size_t length,
|
|
|
|
|
const PacketOptions& options) override {
|
2016-08-22 18:14:14 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2016-03-22 15:32:27 -07:00
|
|
|
need_rtp_ = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SendRtcp(const uint8_t* packet, size_t length) override {
|
2016-08-22 18:14:14 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2016-03-22 15:32:27 -07:00
|
|
|
need_rtcp_ = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool need_rtp_;
|
|
|
|
|
bool need_rtcp_;
|
2016-08-22 18:14:14 -07:00
|
|
|
rtc::CriticalSection crit_;
|
2016-03-22 15:32:27 -07:00
|
|
|
};
|
|
|
|
|
|
2016-02-15 11:27:15 +01:00
|
|
|
void DecodesRetransmittedFrame(bool enable_rtx, bool enable_red);
|
2013-08-19 16:09:34 +00:00
|
|
|
void ReceivesPliAndRecovers(int rtp_history_ms);
|
2015-10-02 02:36:56 -07:00
|
|
|
void RespectsRtcpMode(RtcpMode rtcp_mode);
|
2014-06-30 13:19:09 +00:00
|
|
|
void TestSendsSetSsrcs(size_t num_ssrcs, bool send_single_ssrc_first);
|
2016-07-20 15:26:59 +02:00
|
|
|
void TestRtpStatePreservation(bool use_rtx, bool provoke_rtcpsr_before_rtp);
|
2017-09-26 02:49:21 -07:00
|
|
|
void VerifyHistogramStats(bool use_rtx, bool use_fec, bool screenshare);
|
2016-03-22 15:32:27 -07:00
|
|
|
void VerifyNewVideoSendStreamsRespectNetworkState(
|
2016-11-22 16:08:30 -08:00
|
|
|
MediaType network_to_bring_up,
|
2016-03-22 15:32:27 -07:00
|
|
|
VideoEncoder* encoder,
|
|
|
|
|
Transport* transport);
|
|
|
|
|
void VerifyNewVideoReceiveStreamsRespectNetworkState(
|
2016-11-22 16:08:30 -08:00
|
|
|
MediaType network_to_bring_up,
|
2016-03-22 15:32:27 -07:00
|
|
|
Transport* transport);
|
2017-10-23 12:42:17 +02:00
|
|
|
|
|
|
|
|
test::ScopedFieldTrials field_trial_;
|
2013-08-05 12:01:36 +00:00
|
|
|
};
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceiverCanBeStartedTwice) {
|
2017-04-10 03:54:05 -07:00
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
2014-01-10 18:47:32 +00:00
|
|
|
|
2015-08-28 04:07:10 -07:00
|
|
|
test::NullTransport transport;
|
2016-11-15 07:10:52 -08:00
|
|
|
CreateSendConfig(1, 0, 0, &transport);
|
2015-08-28 04:07:10 -07:00
|
|
|
CreateMatchingReceiveConfigs(&transport);
|
2014-06-27 08:47:52 +00:00
|
|
|
|
2016-01-07 17:43:18 +01:00
|
|
|
CreateVideoStreams();
|
2014-01-10 18:47:32 +00:00
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
video_receive_streams_[0]->Start();
|
|
|
|
|
video_receive_streams_[0]->Start();
|
2014-01-10 18:47:32 +00:00
|
|
|
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceiverCanBeStoppedTwice) {
|
2017-04-10 03:54:05 -07:00
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
2014-01-10 18:47:32 +00:00
|
|
|
|
2015-08-28 04:07:10 -07:00
|
|
|
test::NullTransport transport;
|
2016-11-15 07:10:52 -08:00
|
|
|
CreateSendConfig(1, 0, 0, &transport);
|
2015-08-28 04:07:10 -07:00
|
|
|
CreateMatchingReceiveConfigs(&transport);
|
2014-06-27 08:47:52 +00:00
|
|
|
|
2016-01-07 17:43:18 +01:00
|
|
|
CreateVideoStreams();
|
2014-01-10 18:47:32 +00:00
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
video_receive_streams_[0]->Stop();
|
2016-10-11 03:10:10 -07:00
|
|
|
video_receive_streams_[0]->Stop();
|
|
|
|
|
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceiverCanBeStoppedAndRestarted) {
|
2017-04-10 03:54:05 -07:00
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
2016-10-11 03:10:10 -07:00
|
|
|
|
|
|
|
|
test::NullTransport transport;
|
2016-11-15 07:10:52 -08:00
|
|
|
CreateSendConfig(1, 0, 0, &transport);
|
2016-10-11 03:10:10 -07:00
|
|
|
CreateMatchingReceiveConfigs(&transport);
|
|
|
|
|
|
|
|
|
|
CreateVideoStreams();
|
|
|
|
|
|
|
|
|
|
video_receive_streams_[0]->Stop();
|
|
|
|
|
video_receive_streams_[0]->Start();
|
2015-12-21 03:14:00 -08:00
|
|
|
video_receive_streams_[0]->Stop();
|
2014-01-10 18:47:32 +00:00
|
|
|
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RendersSingleDelayedFrame) {
|
2013-12-16 18:24:37 +00:00
|
|
|
static const int kWidth = 320;
|
|
|
|
|
static const int kHeight = 240;
|
|
|
|
|
// This constant is chosen to be higher than the timeout in the video_render
|
|
|
|
|
// module. This makes sure that frames aren't dropped if there are no other
|
|
|
|
|
// frames in the queue.
|
2017-02-07 09:37:41 -08:00
|
|
|
static const int kRenderDelayMs = 1000;
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2016-03-23 04:48:10 -07:00
|
|
|
class Renderer : public rtc::VideoSinkInterface<VideoFrame> {
|
2013-12-16 18:24:37 +00:00
|
|
|
public:
|
2015-12-10 13:02:50 +01:00
|
|
|
Renderer() : event_(false, false) {}
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-02-07 09:37:41 -08:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
|
|
|
|
SleepMs(kRenderDelayMs);
|
|
|
|
|
event_.Set();
|
|
|
|
|
}
|
2015-02-09 15:14:36 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
bool Wait() { return event_.Wait(kDefaultTimeoutMs); }
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event event_;
|
2013-12-16 18:24:37 +00:00
|
|
|
} renderer;
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::FrameForwarder frame_forwarder;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> sender_transport;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> receiver_transport;
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &renderer, &frame_forwarder, &sender_transport,
|
|
|
|
|
&receiver_transport]() {
|
|
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
sender_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, sender_call_.get(), payload_type_map_);
|
|
|
|
|
receiver_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, receiver_call_.get(), payload_type_map_);
|
|
|
|
|
sender_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
receiver_transport->SetReceiver(sender_call_->Receiver());
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateSendConfig(1, 0, 0, sender_transport.get());
|
|
|
|
|
CreateMatchingReceiveConfigs(receiver_transport.get());
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
video_receive_configs_[0].renderer = &renderer;
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateVideoStreams();
|
|
|
|
|
Start();
|
2016-09-16 07:53:41 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// Create frames that are smaller than the send width/height, this is done
|
|
|
|
|
// to check that the callbacks are done after processing video.
|
|
|
|
|
std::unique_ptr<test::FrameGenerator> frame_generator(
|
|
|
|
|
test::FrameGenerator::CreateSquareGenerator(kWidth, kHeight));
|
|
|
|
|
video_send_stream_->SetSource(
|
|
|
|
|
&frame_forwarder,
|
|
|
|
|
VideoSendStream::DegradationPreference::kMaintainFramerate);
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
frame_forwarder.IncomingCapturedFrame(*frame_generator->NextFrame());
|
|
|
|
|
});
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
EXPECT_TRUE(renderer.Wait())
|
|
|
|
|
<< "Timed out while waiting for the frame to render.";
|
2013-12-16 18:24:37 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &sender_transport, &receiver_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
sender_transport.reset();
|
|
|
|
|
receiver_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2013-12-16 18:24:37 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TransmitsFirstFrame) {
|
2016-03-23 04:48:10 -07:00
|
|
|
class Renderer : public rtc::VideoSinkInterface<VideoFrame> {
|
2013-10-21 09:02:30 +00:00
|
|
|
public:
|
2015-12-10 13:02:50 +01:00
|
|
|
Renderer() : event_(false, false) {}
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2016-03-21 01:27:56 -07:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override { event_.Set(); }
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
bool Wait() { return event_.Wait(kDefaultTimeoutMs); }
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event event_;
|
2013-10-21 09:02:30 +00:00
|
|
|
} renderer;
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::FrameGenerator> frame_generator;
|
|
|
|
|
test::FrameForwarder frame_forwarder;
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::DirectTransport> sender_transport;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> receiver_transport;
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &renderer, &frame_generator, &frame_forwarder,
|
|
|
|
|
&sender_transport, &receiver_transport]() {
|
|
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
sender_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, sender_call_.get(), payload_type_map_);
|
|
|
|
|
receiver_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, receiver_call_.get(), payload_type_map_);
|
|
|
|
|
sender_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
receiver_transport->SetReceiver(sender_call_->Receiver());
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateSendConfig(1, 0, 0, sender_transport.get());
|
|
|
|
|
CreateMatchingReceiveConfigs(receiver_transport.get());
|
|
|
|
|
video_receive_configs_[0].renderer = &renderer;
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateVideoStreams();
|
|
|
|
|
Start();
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
frame_generator = test::FrameGenerator::CreateSquareGenerator(
|
|
|
|
|
kDefaultWidth, kDefaultHeight);
|
|
|
|
|
video_send_stream_->SetSource(
|
|
|
|
|
&frame_forwarder,
|
|
|
|
|
VideoSendStream::DegradationPreference::kMaintainFramerate);
|
|
|
|
|
frame_forwarder.IncomingCapturedFrame(*frame_generator->NextFrame());
|
|
|
|
|
});
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
EXPECT_TRUE(renderer.Wait())
|
|
|
|
|
<< "Timed out while waiting for the frame to render.";
|
2013-10-21 09:02:30 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &sender_transport, &receiver_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
sender_transport.reset();
|
|
|
|
|
receiver_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2013-10-21 09:02:30 +00:00
|
|
|
}
|
|
|
|
|
|
2016-04-19 15:01:23 +02:00
|
|
|
class CodecObserver : public test::EndToEndTest,
|
2016-03-23 04:48:10 -07:00
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
2016-04-19 15:01:23 +02:00
|
|
|
public:
|
|
|
|
|
CodecObserver(int no_frames_to_wait_for,
|
|
|
|
|
VideoRotation rotation_to_test,
|
|
|
|
|
const std::string& payload_name,
|
2017-11-13 14:10:02 +01:00
|
|
|
std::unique_ptr<webrtc::VideoEncoder> encoder,
|
|
|
|
|
std::unique_ptr<webrtc::VideoDecoder> decoder)
|
2016-12-06 05:36:03 -08:00
|
|
|
: EndToEndTest(4 * webrtc::EndToEndTest::kDefaultTimeoutMs),
|
|
|
|
|
// TODO(hta): This timeout (120 seconds) is excessive.
|
|
|
|
|
// https://bugs.webrtc.org/6830
|
2016-04-19 15:01:23 +02:00
|
|
|
no_frames_to_wait_for_(no_frames_to_wait_for),
|
|
|
|
|
expected_rotation_(rotation_to_test),
|
|
|
|
|
payload_name_(payload_name),
|
2017-11-13 14:10:02 +01:00
|
|
|
encoder_(std::move(encoder)),
|
|
|
|
|
decoder_(std::move(decoder)),
|
2016-04-19 15:01:23 +02:00
|
|
|
frame_counter_(0) {}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
EXPECT_TRUE(Wait())
|
|
|
|
|
<< "Timed out while waiting for enough frames to be decoded.";
|
|
|
|
|
}
|
2014-11-01 06:10:48 +00:00
|
|
|
|
2016-04-19 15:01:23 +02:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
send_config->encoder_settings.encoder = encoder_.get();
|
|
|
|
|
send_config->encoder_settings.payload_name = payload_name_;
|
2017-04-10 16:57:57 -07:00
|
|
|
send_config->encoder_settings.payload_type =
|
|
|
|
|
test::CallTest::kVideoSendPayloadType;
|
2016-04-19 15:01:23 +02:00
|
|
|
|
|
|
|
|
(*receive_configs)[0].renderer = this;
|
|
|
|
|
(*receive_configs)[0].decoders.resize(1);
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_type =
|
|
|
|
|
send_config->encoder_settings.payload_type;
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_name =
|
|
|
|
|
send_config->encoder_settings.payload_name;
|
|
|
|
|
(*receive_configs)[0].decoders[0].decoder = decoder_.get();
|
|
|
|
|
}
|
2014-11-01 06:10:48 +00:00
|
|
|
|
2016-04-19 15:01:23 +02:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
|
|
|
|
EXPECT_EQ(expected_rotation_, video_frame.rotation());
|
|
|
|
|
if (++frame_counter_ == no_frames_to_wait_for_)
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
2014-11-01 06:10:48 +00:00
|
|
|
|
2016-04-19 15:01:23 +02:00
|
|
|
void OnFrameGeneratorCapturerCreated(
|
|
|
|
|
test::FrameGeneratorCapturer* frame_generator_capturer) override {
|
|
|
|
|
frame_generator_capturer->SetFakeRotation(expected_rotation_);
|
|
|
|
|
}
|
2014-11-01 06:10:48 +00:00
|
|
|
|
2016-04-19 15:01:23 +02:00
|
|
|
private:
|
|
|
|
|
int no_frames_to_wait_for_;
|
|
|
|
|
VideoRotation expected_rotation_;
|
|
|
|
|
std::string payload_name_;
|
|
|
|
|
std::unique_ptr<webrtc::VideoEncoder> encoder_;
|
|
|
|
|
std::unique_ptr<webrtc::VideoDecoder> decoder_;
|
|
|
|
|
int frame_counter_;
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, SendsAndReceivesVP8) {
|
2016-11-28 08:49:07 -08:00
|
|
|
CodecObserver test(5, kVideoRotation_0, "VP8", VP8Encoder::Create(),
|
|
|
|
|
VP8Decoder::Create());
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, SendsAndReceivesVP8Rotation90) {
|
Reland of Stop using hardcoded payload types for video codecs (patchset #1 id:1 of https://codereview.webrtc.org/2513633002/ )
Reason for revert:
The WebRtcBrowserTest.NegotiateUnsupportedVideoCodec test has been fixed in Chromium with the following change:
function removeVideoCodec(offerSdp) {
- offerSdp = offerSdp.replace('a=rtpmap:100 VP8/90000\r\n',
- 'a=rtpmap:100 XVP8/90000\r\n');
+ offerSdp = offerSdp.replace(/a=rtpmap:(\d+)\ VP8\/90000\r\n/,
+ 'a=rtpmap:$1 XVP8/90000\r\n');
return offerSdp;
}
Original issue's description:
> Revert of Stop using hardcoded payload types for video codecs (patchset #6 id:210001 of https://codereview.webrtc.org/2493133002/ )
>
> Reason for revert:
> Breaks chromium.fyi test:
> WebRtcBrowserTest.NegotiateUnsupportedVideoCodec
>
> Original issue's description:
> > Stop using hardcoded payload types for video codecs
> >
> > This CL stops using hardcoded payload types for different video codecs
> > and will dynamically assign them payload types incrementally from 96 to
> > 127 instead.
> >
> > This CL:
> > * Replaces 'std::vector<VideoCodec> DefaultVideoCodecList()' in
> > webrtcvideoengine2.cc with an explicit WebRtcVideoEncoderFactory for
> > internally supported software codecs instead. The purpose is to
> > streamline the payload type assignment in webrtcvideoengine2.cc which
> > will now have two encoder factories of the same
> > WebRtcVideoEncoderFactory type; one internal and one external.
> > * Removes webrtc::VideoEncoder::EncoderType and use cricket::VideoCodec
> > instead.
> > * Removes 'static VideoEncoder* Create(EncoderType codec_type)' and
> > moves the create function to the internal encoder factory instead.
> > * Removes video_encoder.cc. webrtc::VideoEncoder is now just an
> > interface without any static functions.
> > * The function GetSupportedCodecs in webrtcvideoengine2.cc unifies
> > the internal and external codecs and assigns them payload types
> > incrementally from 96 to 127.
> > * Updates webrtcvideoengine2_unittest.cc and removes assumptions about
> > what payload types will be used.
> >
> > BUG=webrtc:6677,webrtc:6705
> > R=hta@webrtc.org, ossu@webrtc.org, stefan@webrtc.org
> >
> > Committed: https://crrev.com/42043b95872b51321f508bf255d804ce3dff366b
> > Cr-Commit-Position: refs/heads/master@{#15135}
>
> TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:6677,webrtc:6705
>
> Committed: https://crrev.com/eacbaea920797ff751ca83050d140821f5055591
> Cr-Commit-Position: refs/heads/master@{#15140}
TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:6677,webrtc:6705
Review-Url: https://codereview.webrtc.org/2511933002
Cr-Commit-Position: refs/heads/master@{#15148}
2016-11-18 01:34:11 -08:00
|
|
|
CodecObserver test(5, kVideoRotation_90, "VP8", VP8Encoder::Create(),
|
2016-04-19 15:01:23 +02:00
|
|
|
VP8Decoder::Create());
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-11-01 06:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-14 02:03:18 +02:00
|
|
|
#if !defined(RTC_DISABLE_VP9)
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, SendsAndReceivesVP9) {
|
Reland of Stop using hardcoded payload types for video codecs (patchset #1 id:1 of https://codereview.webrtc.org/2513633002/ )
Reason for revert:
The WebRtcBrowserTest.NegotiateUnsupportedVideoCodec test has been fixed in Chromium with the following change:
function removeVideoCodec(offerSdp) {
- offerSdp = offerSdp.replace('a=rtpmap:100 VP8/90000\r\n',
- 'a=rtpmap:100 XVP8/90000\r\n');
+ offerSdp = offerSdp.replace(/a=rtpmap:(\d+)\ VP8\/90000\r\n/,
+ 'a=rtpmap:$1 XVP8/90000\r\n');
return offerSdp;
}
Original issue's description:
> Revert of Stop using hardcoded payload types for video codecs (patchset #6 id:210001 of https://codereview.webrtc.org/2493133002/ )
>
> Reason for revert:
> Breaks chromium.fyi test:
> WebRtcBrowserTest.NegotiateUnsupportedVideoCodec
>
> Original issue's description:
> > Stop using hardcoded payload types for video codecs
> >
> > This CL stops using hardcoded payload types for different video codecs
> > and will dynamically assign them payload types incrementally from 96 to
> > 127 instead.
> >
> > This CL:
> > * Replaces 'std::vector<VideoCodec> DefaultVideoCodecList()' in
> > webrtcvideoengine2.cc with an explicit WebRtcVideoEncoderFactory for
> > internally supported software codecs instead. The purpose is to
> > streamline the payload type assignment in webrtcvideoengine2.cc which
> > will now have two encoder factories of the same
> > WebRtcVideoEncoderFactory type; one internal and one external.
> > * Removes webrtc::VideoEncoder::EncoderType and use cricket::VideoCodec
> > instead.
> > * Removes 'static VideoEncoder* Create(EncoderType codec_type)' and
> > moves the create function to the internal encoder factory instead.
> > * Removes video_encoder.cc. webrtc::VideoEncoder is now just an
> > interface without any static functions.
> > * The function GetSupportedCodecs in webrtcvideoengine2.cc unifies
> > the internal and external codecs and assigns them payload types
> > incrementally from 96 to 127.
> > * Updates webrtcvideoengine2_unittest.cc and removes assumptions about
> > what payload types will be used.
> >
> > BUG=webrtc:6677,webrtc:6705
> > R=hta@webrtc.org, ossu@webrtc.org, stefan@webrtc.org
> >
> > Committed: https://crrev.com/42043b95872b51321f508bf255d804ce3dff366b
> > Cr-Commit-Position: refs/heads/master@{#15135}
>
> TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:6677,webrtc:6705
>
> Committed: https://crrev.com/eacbaea920797ff751ca83050d140821f5055591
> Cr-Commit-Position: refs/heads/master@{#15140}
TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:6677,webrtc:6705
Review-Url: https://codereview.webrtc.org/2511933002
Cr-Commit-Position: refs/heads/master@{#15148}
2016-11-18 01:34:11 -08:00
|
|
|
CodecObserver test(500, kVideoRotation_0, "VP9", VP9Encoder::Create(),
|
2016-04-19 15:01:23 +02:00
|
|
|
VP9Decoder::Create());
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
2014-08-06 09:24:53 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, SendsAndReceivesVP9VideoRotation90) {
|
Reland of Stop using hardcoded payload types for video codecs (patchset #1 id:1 of https://codereview.webrtc.org/2513633002/ )
Reason for revert:
The WebRtcBrowserTest.NegotiateUnsupportedVideoCodec test has been fixed in Chromium with the following change:
function removeVideoCodec(offerSdp) {
- offerSdp = offerSdp.replace('a=rtpmap:100 VP8/90000\r\n',
- 'a=rtpmap:100 XVP8/90000\r\n');
+ offerSdp = offerSdp.replace(/a=rtpmap:(\d+)\ VP8\/90000\r\n/,
+ 'a=rtpmap:$1 XVP8/90000\r\n');
return offerSdp;
}
Original issue's description:
> Revert of Stop using hardcoded payload types for video codecs (patchset #6 id:210001 of https://codereview.webrtc.org/2493133002/ )
>
> Reason for revert:
> Breaks chromium.fyi test:
> WebRtcBrowserTest.NegotiateUnsupportedVideoCodec
>
> Original issue's description:
> > Stop using hardcoded payload types for video codecs
> >
> > This CL stops using hardcoded payload types for different video codecs
> > and will dynamically assign them payload types incrementally from 96 to
> > 127 instead.
> >
> > This CL:
> > * Replaces 'std::vector<VideoCodec> DefaultVideoCodecList()' in
> > webrtcvideoengine2.cc with an explicit WebRtcVideoEncoderFactory for
> > internally supported software codecs instead. The purpose is to
> > streamline the payload type assignment in webrtcvideoengine2.cc which
> > will now have two encoder factories of the same
> > WebRtcVideoEncoderFactory type; one internal and one external.
> > * Removes webrtc::VideoEncoder::EncoderType and use cricket::VideoCodec
> > instead.
> > * Removes 'static VideoEncoder* Create(EncoderType codec_type)' and
> > moves the create function to the internal encoder factory instead.
> > * Removes video_encoder.cc. webrtc::VideoEncoder is now just an
> > interface without any static functions.
> > * The function GetSupportedCodecs in webrtcvideoengine2.cc unifies
> > the internal and external codecs and assigns them payload types
> > incrementally from 96 to 127.
> > * Updates webrtcvideoengine2_unittest.cc and removes assumptions about
> > what payload types will be used.
> >
> > BUG=webrtc:6677,webrtc:6705
> > R=hta@webrtc.org, ossu@webrtc.org, stefan@webrtc.org
> >
> > Committed: https://crrev.com/42043b95872b51321f508bf255d804ce3dff366b
> > Cr-Commit-Position: refs/heads/master@{#15135}
>
> TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:6677,webrtc:6705
>
> Committed: https://crrev.com/eacbaea920797ff751ca83050d140821f5055591
> Cr-Commit-Position: refs/heads/master@{#15140}
TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:6677,webrtc:6705
Review-Url: https://codereview.webrtc.org/2511933002
Cr-Commit-Position: refs/heads/master@{#15148}
2016-11-18 01:34:11 -08:00
|
|
|
CodecObserver test(5, kVideoRotation_90, "VP9", VP9Encoder::Create(),
|
2016-04-19 15:01:23 +02:00
|
|
|
VP9Decoder::Create());
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
2016-05-14 02:03:18 +02:00
|
|
|
#endif // !defined(RTC_DISABLE_VP9)
|
2014-08-06 09:24:53 +00:00
|
|
|
|
2016-11-14 04:11:23 -08:00
|
|
|
#if defined(WEBRTC_USE_H264)
|
2017-10-24 10:07:48 +02:00
|
|
|
class EndToEndTestH264 : public EndToEndTest {};
|
|
|
|
|
|
|
|
|
|
const auto h264_field_trial_combinations = ::testing::Values(
|
|
|
|
|
"WebRTC-SpsPpsIdrIsH264Keyframe/Disabled/WebRTC-RoundRobinPacing/Disabled/",
|
|
|
|
|
"WebRTC-SpsPpsIdrIsH264Keyframe/Enabled/WebRTC-RoundRobinPacing/Disabled/",
|
|
|
|
|
"WebRTC-SpsPpsIdrIsH264Keyframe/Disabled/WebRTC-RoundRobinPacing/Enabled/",
|
|
|
|
|
"WebRTC-SpsPpsIdrIsH264Keyframe/Enabled/WebRTC-RoundRobinPacing/Enabled/");
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(SpsPpsIdrIsKeyframe,
|
|
|
|
|
EndToEndTestH264,
|
|
|
|
|
h264_field_trial_combinations);
|
|
|
|
|
|
|
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264) {
|
2016-11-28 07:20:21 -08:00
|
|
|
CodecObserver test(500, kVideoRotation_0, "H264",
|
|
|
|
|
H264Encoder::Create(cricket::VideoCodec("H264")),
|
2016-04-19 15:01:23 +02:00
|
|
|
H264Decoder::Create());
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
2014-08-06 09:24:53 +00:00
|
|
|
|
2017-10-24 10:07:48 +02:00
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264VideoRotation90) {
|
2016-11-28 07:20:21 -08:00
|
|
|
CodecObserver test(5, kVideoRotation_90, "H264",
|
|
|
|
|
H264Encoder::Create(cricket::VideoCodec("H264")),
|
2016-04-19 15:01:23 +02:00
|
|
|
H264Decoder::Create());
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-08-06 09:24:53 +00:00
|
|
|
}
|
2016-12-06 05:36:03 -08:00
|
|
|
|
2017-10-24 10:07:48 +02:00
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264PacketizationMode0) {
|
2016-12-06 05:36:03 -08:00
|
|
|
cricket::VideoCodec codec = cricket::VideoCodec("H264");
|
|
|
|
|
codec.SetParam(cricket::kH264FmtpPacketizationMode, "0");
|
|
|
|
|
CodecObserver test(500, kVideoRotation_0, "H264", H264Encoder::Create(codec),
|
|
|
|
|
H264Decoder::Create());
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 10:07:48 +02:00
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264PacketizationMode1) {
|
2016-12-06 05:36:03 -08:00
|
|
|
cricket::VideoCodec codec = cricket::VideoCodec("H264");
|
|
|
|
|
codec.SetParam(cricket::kH264FmtpPacketizationMode, "1");
|
|
|
|
|
CodecObserver test(500, kVideoRotation_0, "H264", H264Encoder::Create(codec),
|
|
|
|
|
H264Decoder::Create());
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
2016-11-14 04:11:23 -08:00
|
|
|
#endif // defined(WEBRTC_USE_H264)
|
2016-01-27 01:36:03 -08:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceiverUsesLocalSsrc) {
|
2014-06-27 08:47:52 +00:00
|
|
|
class SyncRtcpObserver : public test::EndToEndTest {
|
2013-12-03 10:13:04 +00:00
|
|
|
public:
|
2014-06-27 08:47:52 +00:00
|
|
|
SyncRtcpObserver() : EndToEndTest(kDefaultTimeoutMs) {}
|
2013-12-03 10:13:04 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2016-11-02 08:21:59 -07:00
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
|
EXPECT_EQ(kReceiverLocalVideoSsrc, parser.sender_ssrc());
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2013-12-03 10:13:04 +00:00
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2014-06-27 08:47:52 +00:00
|
|
|
<< "Timed out while waiting for a receiver RTCP packet to be sent.";
|
|
|
|
|
}
|
|
|
|
|
} test;
|
2013-12-03 10:13:04 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2013-12-03 10:13:04 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceivesAndRetransmitsNack) {
|
2014-06-27 08:47:52 +00:00
|
|
|
static const int kNumberOfNacksToObserve = 2;
|
|
|
|
|
static const int kLossBurstSize = 2;
|
|
|
|
|
static const int kPacketsBetweenLossBursts = 9;
|
|
|
|
|
class NackObserver : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
NackObserver()
|
|
|
|
|
: EndToEndTest(kLongTimeoutMs),
|
|
|
|
|
sent_rtp_packets_(0),
|
|
|
|
|
packets_left_to_drop_(0),
|
|
|
|
|
nacks_left_(kNumberOfNacksToObserve) {}
|
2013-12-03 10:13:04 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2014-06-27 08:47:52 +00:00
|
|
|
RTPHeader header;
|
2015-12-07 15:22:24 +01:00
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
2014-06-27 08:47:52 +00:00
|
|
|
|
|
|
|
|
// Never drop retransmitted packets.
|
|
|
|
|
if (dropped_packets_.find(header.sequenceNumber) !=
|
|
|
|
|
dropped_packets_.end()) {
|
|
|
|
|
retransmitted_packets_.insert(header.sequenceNumber);
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2013-12-03 10:13:04 +00:00
|
|
|
|
2017-01-10 05:19:19 -08:00
|
|
|
if (nacks_left_ <= 0 &&
|
|
|
|
|
retransmitted_packets_.size() == dropped_packets_.size()) {
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
++sent_rtp_packets_;
|
2013-12-03 10:13:04 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
// Enough NACKs received, stop dropping packets.
|
2015-09-18 11:14:31 +02:00
|
|
|
if (nacks_left_ <= 0)
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
2013-12-03 10:13:04 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
// Check if it's time for a new loss burst.
|
|
|
|
|
if (sent_rtp_packets_ % kPacketsBetweenLossBursts == 0)
|
|
|
|
|
packets_left_to_drop_ = kLossBurstSize;
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2015-05-05 10:21:24 +02:00
|
|
|
// Never drop padding packets as those won't be retransmitted.
|
|
|
|
|
if (packets_left_to_drop_ > 0 && header.paddingLength == 0) {
|
2014-06-27 08:47:52 +00:00
|
|
|
--packets_left_to_drop_;
|
|
|
|
|
dropped_packets_.insert(header.sequenceNumber);
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2013-08-19 16:09:34 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2016-11-02 08:21:59 -07:00
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
|
nacks_left_ -= parser.nack()->num_packets();
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2014-06-27 08:47:52 +00:00
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2014-06-30 13:19:09 +00:00
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2013-08-19 16:09:34 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2014-06-27 08:47:52 +00:00
|
|
|
<< "Timed out waiting for packets to be NACKed, retransmitted and "
|
|
|
|
|
"rendered.";
|
|
|
|
|
}
|
2013-08-19 16:09:34 +00:00
|
|
|
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CriticalSection crit_;
|
2014-06-27 08:47:52 +00:00
|
|
|
std::set<uint16_t> dropped_packets_;
|
|
|
|
|
std::set<uint16_t> retransmitted_packets_;
|
|
|
|
|
uint64_t sent_rtp_packets_;
|
|
|
|
|
int packets_left_to_drop_;
|
2017-09-09 04:17:22 -07:00
|
|
|
int nacks_left_ RTC_GUARDED_BY(&crit_);
|
2014-06-27 08:47:52 +00:00
|
|
|
} test;
|
2014-04-08 11:21:45 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-04-08 11:21:45 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceivesNackAndRetransmitsAudio) {
|
2016-07-29 12:59:36 +02:00
|
|
|
class NackObserver : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
NackObserver()
|
|
|
|
|
: EndToEndTest(kLongTimeoutMs),
|
|
|
|
|
local_ssrc_(0),
|
|
|
|
|
remote_ssrc_(0),
|
|
|
|
|
receive_transport_(nullptr) {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
size_t GetNumVideoStreams() const override { return 0; }
|
|
|
|
|
size_t GetNumAudioStreams() const override { return 1; }
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::PacketTransport* CreateReceiveTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue) override {
|
2016-07-29 12:59:36 +02:00
|
|
|
test::PacketTransport* receive_transport = new test::PacketTransport(
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue, nullptr, this, test::PacketTransport::kReceiver,
|
|
|
|
|
payload_type_map_, FakeNetworkPipe::Config());
|
2016-07-29 12:59:36 +02:00
|
|
|
receive_transport_ = receive_transport;
|
|
|
|
|
return receive_transport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
|
|
|
|
|
|
|
|
if (!sequence_number_to_retransmit_) {
|
|
|
|
|
sequence_number_to_retransmit_ =
|
|
|
|
|
rtc::Optional<uint16_t>(header.sequenceNumber);
|
|
|
|
|
|
|
|
|
|
// Don't ask for retransmission straight away, may be deduped in pacer.
|
|
|
|
|
} else if (header.sequenceNumber == *sequence_number_to_retransmit_) {
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
} else {
|
|
|
|
|
// Send a NACK as often as necessary until retransmission is received.
|
|
|
|
|
rtcp::Nack nack;
|
2016-09-27 09:27:47 -07:00
|
|
|
nack.SetSenderSsrc(local_ssrc_);
|
|
|
|
|
nack.SetMediaSsrc(remote_ssrc_);
|
2016-07-29 12:59:36 +02:00
|
|
|
uint16_t nack_list[] = {*sequence_number_to_retransmit_};
|
2016-09-27 09:27:47 -07:00
|
|
|
nack.SetPacketIds(nack_list, 1);
|
2016-07-29 12:59:36 +02:00
|
|
|
rtc::Buffer buffer = nack.Build();
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(receive_transport_->SendRtcp(buffer.data(), buffer.size()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ModifyAudioConfigs(
|
|
|
|
|
AudioSendStream::Config* send_config,
|
|
|
|
|
std::vector<AudioReceiveStream::Config>* receive_configs) override {
|
|
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
local_ssrc_ = (*receive_configs)[0].rtp.local_ssrc;
|
|
|
|
|
remote_ssrc_ = (*receive_configs)[0].rtp.remote_ssrc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
EXPECT_TRUE(Wait())
|
|
|
|
|
<< "Timed out waiting for packets to be NACKed, retransmitted and "
|
|
|
|
|
"rendered.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t local_ssrc_;
|
|
|
|
|
uint32_t remote_ssrc_;
|
|
|
|
|
Transport* receive_transport_;
|
|
|
|
|
rtc::Optional<uint16_t> sequence_number_to_retransmit_;
|
|
|
|
|
} test;
|
|
|
|
|
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceivesUlpfec) {
|
2016-10-31 03:45:58 -07:00
|
|
|
class UlpfecRenderObserver : public test::EndToEndTest,
|
|
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
2014-04-08 11:21:45 +00:00
|
|
|
public:
|
2016-10-31 03:45:58 -07:00
|
|
|
UlpfecRenderObserver()
|
2017-02-06 06:35:47 -08:00
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
2017-03-20 06:32:59 -07:00
|
|
|
encoder_(VP8Encoder::Create()),
|
2017-02-06 06:35:47 -08:00
|
|
|
random_(0xcafef00d1),
|
|
|
|
|
num_packets_sent_(0) {}
|
2014-04-08 11:21:45 +00:00
|
|
|
|
|
|
|
|
private:
|
2015-10-27 08:29:42 -07:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
2014-04-08 11:21:45 +00:00
|
|
|
RTPHeader header;
|
2014-07-08 12:10:51 +00:00
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
2014-04-08 11:21:45 +00:00
|
|
|
|
2017-03-20 06:32:59 -07:00
|
|
|
EXPECT_TRUE(header.payloadType == kVideoSendPayloadType ||
|
2017-02-06 06:35:47 -08:00
|
|
|
header.payloadType == kRedPayloadType)
|
|
|
|
|
<< "Unknown payload type received.";
|
|
|
|
|
EXPECT_EQ(kVideoSendSsrcs[0], header.ssrc) << "Unknown SSRC received.";
|
|
|
|
|
|
|
|
|
|
// Parse RED header.
|
2015-05-05 10:21:24 +02:00
|
|
|
int encapsulated_payload_type = -1;
|
|
|
|
|
if (header.payloadType == kRedPayloadType) {
|
|
|
|
|
encapsulated_payload_type =
|
|
|
|
|
static_cast<int>(packet[header.headerLength]);
|
2017-02-06 06:35:47 -08:00
|
|
|
|
2017-03-20 06:32:59 -07:00
|
|
|
EXPECT_TRUE(encapsulated_payload_type == kVideoSendPayloadType ||
|
2017-02-06 06:35:47 -08:00
|
|
|
encapsulated_payload_type == kUlpfecPayloadType)
|
|
|
|
|
<< "Unknown encapsulated payload type received.";
|
2015-05-05 10:21:24 +02:00
|
|
|
}
|
2014-04-08 11:21:45 +00:00
|
|
|
|
2017-03-20 06:32:59 -07:00
|
|
|
// To minimize test flakiness, always let ULPFEC packets through.
|
2017-02-06 06:35:47 -08:00
|
|
|
if (encapsulated_payload_type == kUlpfecPayloadType) {
|
2014-11-13 14:40:15 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-06 06:35:47 -08:00
|
|
|
// Simulate 5% video packet loss after rampup period. Record the
|
|
|
|
|
// corresponding timestamps that were dropped.
|
|
|
|
|
if (num_packets_sent_++ > 100 && random_.Rand(1, 100) <= 5) {
|
2017-03-20 06:32:59 -07:00
|
|
|
if (encapsulated_payload_type == kVideoSendPayloadType) {
|
2017-02-06 06:35:47 -08:00
|
|
|
dropped_sequence_numbers_.insert(header.sequenceNumber);
|
|
|
|
|
dropped_timestamps_.insert(header.timestamp);
|
|
|
|
|
}
|
|
|
|
|
return DROP_PACKET;
|
2014-04-08 11:21:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 01:27:56 -07:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&crit_);
|
2014-11-13 14:40:15 +00:00
|
|
|
// Rendering frame with timestamp of packet that was dropped -> FEC
|
2014-04-08 11:21:45 +00:00
|
|
|
// protection worked.
|
2017-02-06 06:35:47 -08:00
|
|
|
auto it = dropped_timestamps_.find(video_frame.timestamp());
|
|
|
|
|
if (it != dropped_timestamps_.end()) {
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2017-02-06 06:35:47 -08:00
|
|
|
}
|
2014-04-08 11:21:45 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2017-03-20 06:32:59 -07:00
|
|
|
// Use VP8 instead of FAKE, since the latter does not have PictureID
|
|
|
|
|
// in the packetization headers.
|
|
|
|
|
send_config->encoder_settings.encoder = encoder_.get();
|
|
|
|
|
send_config->encoder_settings.payload_name = "VP8";
|
|
|
|
|
send_config->encoder_settings.payload_type = kVideoSendPayloadType;
|
|
|
|
|
VideoReceiveStream::Decoder decoder =
|
|
|
|
|
test::CreateMatchingDecoder(send_config->encoder_settings);
|
|
|
|
|
decoder_.reset(decoder.decoder);
|
|
|
|
|
(*receive_configs)[0].decoders.clear();
|
|
|
|
|
(*receive_configs)[0].decoders.push_back(decoder);
|
|
|
|
|
|
|
|
|
|
// Enable ULPFEC over RED.
|
2016-10-04 23:28:39 -07:00
|
|
|
send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
|
|
|
|
|
send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
|
2017-09-26 02:49:21 -07:00
|
|
|
(*receive_configs)[0].rtp.red_payload_type = kRedPayloadType;
|
|
|
|
|
(*receive_configs)[0].rtp.ulpfec_payload_type = kUlpfecPayloadType;
|
2017-03-20 06:32:59 -07:00
|
|
|
|
2014-06-30 13:19:09 +00:00
|
|
|
(*receive_configs)[0].renderer = this;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2014-04-08 11:21:45 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2016-11-16 22:45:19 -08:00
|
|
|
<< "Timed out waiting for dropped frames to be rendered.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtc::CriticalSection crit_;
|
2017-03-20 06:32:59 -07:00
|
|
|
std::unique_ptr<VideoEncoder> encoder_;
|
|
|
|
|
std::unique_ptr<VideoDecoder> decoder_;
|
2017-09-09 04:17:22 -07:00
|
|
|
std::set<uint32_t> dropped_sequence_numbers_ RTC_GUARDED_BY(crit_);
|
2017-02-06 06:35:47 -08:00
|
|
|
// Several packets can have the same timestamp.
|
2017-09-09 04:17:22 -07:00
|
|
|
std::multiset<uint32_t> dropped_timestamps_ RTC_GUARDED_BY(crit_);
|
2017-02-06 06:35:47 -08:00
|
|
|
Random random_;
|
2017-09-09 04:17:22 -07:00
|
|
|
int num_packets_sent_ RTC_GUARDED_BY(crit_);
|
2016-11-16 22:45:19 -08:00
|
|
|
} test;
|
|
|
|
|
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
class FlexfecRenderObserver : public test::EndToEndTest,
|
|
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
|
|
|
|
public:
|
|
|
|
|
static constexpr uint32_t kVideoLocalSsrc = 123;
|
|
|
|
|
static constexpr uint32_t kFlexfecLocalSsrc = 456;
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-02-06 06:35:47 -08:00
|
|
|
explicit FlexfecRenderObserver(bool enable_nack, bool expect_flexfec_rtcp)
|
2017-01-17 01:33:54 -08:00
|
|
|
: test::EndToEndTest(test::CallTest::kDefaultTimeoutMs),
|
2017-02-06 06:35:47 -08:00
|
|
|
enable_nack_(enable_nack),
|
2017-01-17 01:33:54 -08:00
|
|
|
expect_flexfec_rtcp_(expect_flexfec_rtcp),
|
|
|
|
|
received_flexfec_rtcp_(false),
|
2017-02-06 06:35:47 -08:00
|
|
|
random_(0xcafef00d1),
|
|
|
|
|
num_packets_sent_(0) {}
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
size_t GetNumFlexfecStreams() const override { return 1; }
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
private:
|
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
|
|
|
|
2017-02-06 06:35:47 -08:00
|
|
|
EXPECT_TRUE(header.payloadType ==
|
|
|
|
|
test::CallTest::kFakeVideoSendPayloadType ||
|
|
|
|
|
header.payloadType == test::CallTest::kFlexfecPayloadType ||
|
|
|
|
|
(enable_nack_ &&
|
|
|
|
|
header.payloadType == test::CallTest::kSendRtxPayloadType))
|
|
|
|
|
<< "Unknown payload type received.";
|
|
|
|
|
EXPECT_TRUE(
|
|
|
|
|
header.ssrc == test::CallTest::kVideoSendSsrcs[0] ||
|
|
|
|
|
header.ssrc == test::CallTest::kFlexfecSendSsrc ||
|
|
|
|
|
(enable_nack_ && header.ssrc == test::CallTest::kSendRtxSsrcs[0]))
|
|
|
|
|
<< "Unknown SSRC received.";
|
|
|
|
|
|
|
|
|
|
// To reduce test flakiness, always let FlexFEC packets through.
|
|
|
|
|
if (header.payloadType == test::CallTest::kFlexfecPayloadType) {
|
|
|
|
|
EXPECT_EQ(test::CallTest::kFlexfecSendSsrc, header.ssrc);
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
2017-01-17 01:33:54 -08:00
|
|
|
}
|
|
|
|
|
|
2017-02-06 06:35:47 -08:00
|
|
|
// To reduce test flakiness, always let RTX packets through.
|
|
|
|
|
if (header.payloadType == test::CallTest::kSendRtxPayloadType) {
|
|
|
|
|
EXPECT_EQ(test::CallTest::kSendRtxSsrcs[0], header.ssrc);
|
|
|
|
|
|
|
|
|
|
// Parse RTX header.
|
|
|
|
|
uint16_t original_sequence_number =
|
|
|
|
|
ByteReader<uint16_t>::ReadBigEndian(&packet[header.headerLength]);
|
|
|
|
|
|
|
|
|
|
// From the perspective of FEC, a retransmitted packet is no longer
|
|
|
|
|
// dropped, so remove it from list of dropped packets.
|
|
|
|
|
auto seq_num_it =
|
|
|
|
|
dropped_sequence_numbers_.find(original_sequence_number);
|
2017-01-17 01:33:54 -08:00
|
|
|
if (seq_num_it != dropped_sequence_numbers_.end()) {
|
|
|
|
|
dropped_sequence_numbers_.erase(seq_num_it);
|
|
|
|
|
auto ts_it = dropped_timestamps_.find(header.timestamp);
|
|
|
|
|
EXPECT_NE(ts_it, dropped_timestamps_.end());
|
|
|
|
|
dropped_timestamps_.erase(ts_it);
|
2017-02-06 06:19:51 -08:00
|
|
|
}
|
2017-02-06 06:35:47 -08:00
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
2017-01-17 01:33:54 -08:00
|
|
|
}
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-02-06 06:35:47 -08:00
|
|
|
// Simulate 5% video packet loss after rampup period. Record the
|
|
|
|
|
// corresponding timestamps that were dropped.
|
|
|
|
|
if (num_packets_sent_++ > 100 && random_.Rand(1, 100) <= 5) {
|
|
|
|
|
EXPECT_EQ(test::CallTest::kFakeVideoSendPayloadType, header.payloadType);
|
|
|
|
|
EXPECT_EQ(test::CallTest::kVideoSendSsrcs[0], header.ssrc);
|
|
|
|
|
|
|
|
|
|
dropped_sequence_numbers_.insert(header.sequenceNumber);
|
|
|
|
|
dropped_timestamps_.insert(header.timestamp);
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
2016-12-09 06:51:29 -08:00
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
Action OnReceiveRtcp(const uint8_t* data, size_t length) override {
|
|
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
|
|
|
|
|
parser.Parse(data, length);
|
|
|
|
|
if (parser.sender_ssrc() == kFlexfecLocalSsrc) {
|
|
|
|
|
EXPECT_EQ(1, parser.receiver_report()->num_packets());
|
|
|
|
|
const std::vector<rtcp::ReportBlock>& report_blocks =
|
|
|
|
|
parser.receiver_report()->report_blocks();
|
|
|
|
|
if (!report_blocks.empty()) {
|
|
|
|
|
EXPECT_EQ(1U, report_blocks.size());
|
|
|
|
|
EXPECT_EQ(test::CallTest::kFlexfecSendSsrc,
|
|
|
|
|
report_blocks[0].source_ssrc());
|
2017-01-18 00:40:07 -08:00
|
|
|
rtc::CritScope lock(&crit_);
|
2017-01-17 01:33:54 -08:00
|
|
|
received_flexfec_rtcp_ = true;
|
|
|
|
|
}
|
2016-11-16 22:45:19 -08:00
|
|
|
}
|
|
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::PacketTransport* CreateSendTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
|
|
|
|
Call* sender_call) override {
|
2017-02-06 06:35:47 -08:00
|
|
|
// At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
|
|
|
|
|
const int kNetworkDelayMs = 100;
|
|
|
|
|
FakeNetworkPipe::Config config;
|
|
|
|
|
config.queue_delay_ms = kNetworkDelayMs;
|
2017-08-22 04:02:52 -07:00
|
|
|
return new test::PacketTransport(task_queue, sender_call, this,
|
Reland of Don't hardcode MediaType::ANY in FakeNetworkPipe. (patchset #1 id:1 of https://codereview.webrtc.org/2784543002/ )
Reason for revert:
Intend to fix perf failures and reland.
Original issue's description:
> Revert of Don't hardcode MediaType::ANY in FakeNetworkPipe. (patchset #4 id:60001 of https://codereview.webrtc.org/2774463003/ )
>
> Reason for revert:
> Reverting since this seems to break multiple WebRTC Perf buildbots
>
> Original issue's description:
> > Don't hardcode MediaType::ANY in FakeNetworkPipe.
> >
> > Instead let each test set the appropriate media type. This simplifies
> > demuxing in Call and later in RtpTransportController.
> >
> > BUG=webrtc:7135
> >
> > Review-Url: https://codereview.webrtc.org/2774463003
> > Cr-Commit-Position: refs/heads/master@{#17418}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/9c47b00e24da2941eb095df5a4459c6d98a8a88d
>
> TBR=stefan@webrtc.org,deadbeef@webrtc.org,solenberg@webrtc.org,pbos@webrtc.org,sprang@webrtc.org,nisse@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:7135
>
> Review-Url: https://codereview.webrtc.org/2784543002
> Cr-Commit-Position: refs/heads/master@{#17427}
> Committed: https://chromium.googlesource.com/external/webrtc/+/3a3bd5061089da5327fc549337a8430054d66057
TBR=stefan@webrtc.org,deadbeef@webrtc.org,solenberg@webrtc.org,pbos@webrtc.org,sprang@webrtc.org,lliuu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:7135
Review-Url: https://codereview.webrtc.org/2783853002
Cr-Commit-Position: refs/heads/master@{#17459}
2017-03-29 23:57:43 -07:00
|
|
|
test::PacketTransport::kSender,
|
2017-04-10 16:57:57 -07:00
|
|
|
test::CallTest::payload_type_map_, config);
|
2017-02-06 06:35:47 -08:00
|
|
|
}
|
|
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
2017-08-23 00:55:17 -07:00
|
|
|
EXPECT_EQ(kVideoRotation_90, video_frame.rotation());
|
|
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
// Rendering frame with timestamp of packet that was dropped -> FEC
|
|
|
|
|
// protection worked.
|
|
|
|
|
auto it = dropped_timestamps_.find(video_frame.timestamp());
|
|
|
|
|
if (it != dropped_timestamps_.end()) {
|
|
|
|
|
if (!expect_flexfec_rtcp_ || received_flexfec_rtcp_) {
|
2016-11-16 22:45:19 -08:00
|
|
|
observation_complete_.Set();
|
2017-01-17 01:33:54 -08:00
|
|
|
}
|
2016-11-16 22:45:19 -08:00
|
|
|
}
|
2017-01-17 01:33:54 -08:00
|
|
|
}
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
(*receive_configs)[0].rtp.local_ssrc = kVideoLocalSsrc;
|
|
|
|
|
(*receive_configs)[0].renderer = this;
|
2017-02-06 06:35:47 -08:00
|
|
|
|
|
|
|
|
if (enable_nack_) {
|
|
|
|
|
send_config->rtp.nack.rtp_history_ms = test::CallTest::kNackRtpHistoryMs;
|
|
|
|
|
send_config->rtp.rtx.ssrcs.push_back(test::CallTest::kSendRtxSsrcs[0]);
|
|
|
|
|
send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType;
|
|
|
|
|
|
|
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms =
|
|
|
|
|
test::CallTest::kNackRtpHistoryMs;
|
|
|
|
|
(*receive_configs)[0].rtp.rtx_ssrc = test::CallTest::kSendRtxSsrcs[0];
|
|
|
|
|
(*receive_configs)[0]
|
2017-08-25 04:44:25 -07:00
|
|
|
.rtp
|
|
|
|
|
.rtx_associated_payload_types[test::CallTest::kSendRtxPayloadType] =
|
|
|
|
|
test::CallTest::kVideoSendPayloadType;
|
2017-02-06 06:35:47 -08:00
|
|
|
}
|
2017-01-17 01:33:54 -08:00
|
|
|
}
|
2016-11-16 22:45:19 -08:00
|
|
|
|
2017-08-23 00:55:17 -07:00
|
|
|
void OnFrameGeneratorCapturerCreated(
|
|
|
|
|
test::FrameGeneratorCapturer* frame_generator_capturer) override {
|
|
|
|
|
frame_generator_capturer->SetFakeRotation(kVideoRotation_90);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
void ModifyFlexfecConfigs(
|
|
|
|
|
std::vector<FlexfecReceiveStream::Config>* receive_configs) override {
|
|
|
|
|
(*receive_configs)[0].local_ssrc = kFlexfecLocalSsrc;
|
|
|
|
|
}
|
2014-04-08 11:21:45 +00:00
|
|
|
|
2017-01-17 01:33:54 -08:00
|
|
|
void PerformTest() override {
|
|
|
|
|
EXPECT_TRUE(Wait())
|
|
|
|
|
<< "Timed out waiting for dropped frames to be rendered.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtc::CriticalSection crit_;
|
2017-09-09 04:17:22 -07:00
|
|
|
std::set<uint32_t> dropped_sequence_numbers_ RTC_GUARDED_BY(crit_);
|
2017-02-06 06:35:47 -08:00
|
|
|
// Several packets can have the same timestamp.
|
2017-09-09 04:17:22 -07:00
|
|
|
std::multiset<uint32_t> dropped_timestamps_ RTC_GUARDED_BY(crit_);
|
2017-02-06 06:35:47 -08:00
|
|
|
const bool enable_nack_;
|
2017-01-18 00:40:07 -08:00
|
|
|
const bool expect_flexfec_rtcp_;
|
2017-09-09 04:17:22 -07:00
|
|
|
bool received_flexfec_rtcp_ RTC_GUARDED_BY(crit_);
|
2017-01-17 01:33:54 -08:00
|
|
|
Random random_;
|
2017-02-06 06:35:47 -08:00
|
|
|
int num_packets_sent_;
|
2017-01-17 01:33:54 -08:00
|
|
|
};
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RecoversWithFlexfec) {
|
2017-02-06 06:35:47 -08:00
|
|
|
FlexfecRenderObserver test(false, false);
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RecoversWithFlexfecAndNack) {
|
2017-02-06 06:35:47 -08:00
|
|
|
FlexfecRenderObserver test(true, false);
|
2017-01-17 01:33:54 -08:00
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
2013-09-09 08:26:30 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RecoversWithFlexfecAndSendsCorrespondingRtcp) {
|
2017-02-06 06:35:47 -08:00
|
|
|
FlexfecRenderObserver test(false, true);
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2013-08-19 16:09:34 +00:00
|
|
|
}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceivedUlpfecPacketsNotNacked) {
|
2016-10-31 03:45:58 -07:00
|
|
|
class UlpfecNackObserver : public test::EndToEndTest {
|
2015-01-28 13:58:27 +00:00
|
|
|
public:
|
2016-10-31 03:45:58 -07:00
|
|
|
UlpfecNackObserver()
|
2015-10-27 08:29:42 -07:00
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
2015-02-25 11:47:11 +00:00
|
|
|
state_(kFirstPacket),
|
2016-10-31 03:45:58 -07:00
|
|
|
ulpfec_sequence_number_(0),
|
2015-01-28 13:58:27 +00:00
|
|
|
has_last_sequence_number_(false),
|
2016-05-27 14:12:09 +02:00
|
|
|
last_sequence_number_(0),
|
Reland of Stop using hardcoded payload types for video codecs (patchset #1 id:1 of https://codereview.webrtc.org/2513633002/ )
Reason for revert:
The WebRtcBrowserTest.NegotiateUnsupportedVideoCodec test has been fixed in Chromium with the following change:
function removeVideoCodec(offerSdp) {
- offerSdp = offerSdp.replace('a=rtpmap:100 VP8/90000\r\n',
- 'a=rtpmap:100 XVP8/90000\r\n');
+ offerSdp = offerSdp.replace(/a=rtpmap:(\d+)\ VP8\/90000\r\n/,
+ 'a=rtpmap:$1 XVP8/90000\r\n');
return offerSdp;
}
Original issue's description:
> Revert of Stop using hardcoded payload types for video codecs (patchset #6 id:210001 of https://codereview.webrtc.org/2493133002/ )
>
> Reason for revert:
> Breaks chromium.fyi test:
> WebRtcBrowserTest.NegotiateUnsupportedVideoCodec
>
> Original issue's description:
> > Stop using hardcoded payload types for video codecs
> >
> > This CL stops using hardcoded payload types for different video codecs
> > and will dynamically assign them payload types incrementally from 96 to
> > 127 instead.
> >
> > This CL:
> > * Replaces 'std::vector<VideoCodec> DefaultVideoCodecList()' in
> > webrtcvideoengine2.cc with an explicit WebRtcVideoEncoderFactory for
> > internally supported software codecs instead. The purpose is to
> > streamline the payload type assignment in webrtcvideoengine2.cc which
> > will now have two encoder factories of the same
> > WebRtcVideoEncoderFactory type; one internal and one external.
> > * Removes webrtc::VideoEncoder::EncoderType and use cricket::VideoCodec
> > instead.
> > * Removes 'static VideoEncoder* Create(EncoderType codec_type)' and
> > moves the create function to the internal encoder factory instead.
> > * Removes video_encoder.cc. webrtc::VideoEncoder is now just an
> > interface without any static functions.
> > * The function GetSupportedCodecs in webrtcvideoengine2.cc unifies
> > the internal and external codecs and assigns them payload types
> > incrementally from 96 to 127.
> > * Updates webrtcvideoengine2_unittest.cc and removes assumptions about
> > what payload types will be used.
> >
> > BUG=webrtc:6677,webrtc:6705
> > R=hta@webrtc.org, ossu@webrtc.org, stefan@webrtc.org
> >
> > Committed: https://crrev.com/42043b95872b51321f508bf255d804ce3dff366b
> > Cr-Commit-Position: refs/heads/master@{#15135}
>
> TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:6677,webrtc:6705
>
> Committed: https://crrev.com/eacbaea920797ff751ca83050d140821f5055591
> Cr-Commit-Position: refs/heads/master@{#15140}
TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:6677,webrtc:6705
Review-Url: https://codereview.webrtc.org/2511933002
Cr-Commit-Position: refs/heads/master@{#15148}
2016-11-18 01:34:11 -08:00
|
|
|
encoder_(VP8Encoder::Create()),
|
2016-05-27 14:12:09 +02:00
|
|
|
decoder_(VP8Decoder::Create()) {}
|
2015-01-28 13:58:27 +00:00
|
|
|
|
|
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2015-11-01 14:56:10 -08:00
|
|
|
rtc::CritScope lock_(&crit_);
|
2015-01-28 13:58:27 +00:00
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
|
|
|
|
2015-05-05 10:21:24 +02:00
|
|
|
int encapsulated_payload_type = -1;
|
|
|
|
|
if (header.payloadType == kRedPayloadType) {
|
|
|
|
|
encapsulated_payload_type =
|
|
|
|
|
static_cast<int>(packet[header.headerLength]);
|
2016-01-07 17:43:18 +01:00
|
|
|
if (encapsulated_payload_type != kFakeVideoSendPayloadType)
|
2015-05-05 10:21:24 +02:00
|
|
|
EXPECT_EQ(kUlpfecPayloadType, encapsulated_payload_type);
|
|
|
|
|
} else {
|
2016-01-07 17:43:18 +01:00
|
|
|
EXPECT_EQ(kFakeVideoSendPayloadType, header.payloadType);
|
2015-05-05 10:21:24 +02:00
|
|
|
}
|
2015-01-28 13:58:27 +00:00
|
|
|
|
|
|
|
|
if (has_last_sequence_number_ &&
|
|
|
|
|
!IsNewerSequenceNumber(header.sequenceNumber,
|
|
|
|
|
last_sequence_number_)) {
|
|
|
|
|
// Drop retransmitted packets.
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
|
|
|
|
last_sequence_number_ = header.sequenceNumber;
|
|
|
|
|
has_last_sequence_number_ = true;
|
|
|
|
|
|
2016-10-31 03:45:58 -07:00
|
|
|
bool ulpfec_packet = encapsulated_payload_type == kUlpfecPayloadType;
|
2015-01-28 13:58:27 +00:00
|
|
|
switch (state_) {
|
2015-02-25 11:47:11 +00:00
|
|
|
case kFirstPacket:
|
2016-10-31 03:45:58 -07:00
|
|
|
state_ = kDropEveryOtherPacketUntilUlpfec;
|
2015-02-25 11:47:11 +00:00
|
|
|
break;
|
2016-10-31 03:45:58 -07:00
|
|
|
case kDropEveryOtherPacketUntilUlpfec:
|
|
|
|
|
if (ulpfec_packet) {
|
|
|
|
|
state_ = kDropAllMediaPacketsUntilUlpfec;
|
2015-01-28 13:58:27 +00:00
|
|
|
} else if (header.sequenceNumber % 2 == 0) {
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-10-31 03:45:58 -07:00
|
|
|
case kDropAllMediaPacketsUntilUlpfec:
|
|
|
|
|
if (!ulpfec_packet)
|
2015-01-28 13:58:27 +00:00
|
|
|
return DROP_PACKET;
|
2016-10-31 03:45:58 -07:00
|
|
|
ulpfec_sequence_number_ = header.sequenceNumber;
|
2016-05-27 14:12:09 +02:00
|
|
|
state_ = kDropOneMediaPacket;
|
|
|
|
|
break;
|
|
|
|
|
case kDropOneMediaPacket:
|
2016-10-31 03:45:58 -07:00
|
|
|
if (ulpfec_packet)
|
2016-05-27 14:12:09 +02:00
|
|
|
return DROP_PACKET;
|
|
|
|
|
state_ = kPassOneMediaPacket;
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
break;
|
|
|
|
|
case kPassOneMediaPacket:
|
2016-10-31 03:45:58 -07:00
|
|
|
if (ulpfec_packet)
|
2016-05-27 14:12:09 +02:00
|
|
|
return DROP_PACKET;
|
|
|
|
|
// Pass one media packet after dropped packet after last FEC,
|
|
|
|
|
// otherwise receiver might never see a seq_no after
|
2016-10-31 03:45:58 -07:00
|
|
|
// |ulpfec_sequence_number_|
|
|
|
|
|
state_ = kVerifyUlpfecPacketNotInNackList;
|
2015-01-28 13:58:27 +00:00
|
|
|
break;
|
2016-10-31 03:45:58 -07:00
|
|
|
case kVerifyUlpfecPacketNotInNackList:
|
2015-01-28 13:58:27 +00:00
|
|
|
// Continue to drop packets. Make sure no frame can be decoded.
|
2016-10-31 03:45:58 -07:00
|
|
|
if (ulpfec_packet || header.sequenceNumber % 2 == 0)
|
2015-01-28 13:58:27 +00:00
|
|
|
return DROP_PACKET;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2015-11-01 14:56:10 -08:00
|
|
|
rtc::CritScope lock_(&crit_);
|
2016-10-31 03:45:58 -07:00
|
|
|
if (state_ == kVerifyUlpfecPacketNotInNackList) {
|
2015-01-28 13:58:27 +00:00
|
|
|
test::RtcpPacketParser rtcp_parser;
|
|
|
|
|
rtcp_parser.Parse(packet, length);
|
2016-09-02 18:29:10 +02:00
|
|
|
const std::vector<uint16_t>& nacks = rtcp_parser.nack()->packet_ids();
|
2016-05-27 14:12:09 +02:00
|
|
|
EXPECT_TRUE(std::find(nacks.begin(), nacks.end(),
|
2016-10-31 03:45:58 -07:00
|
|
|
ulpfec_sequence_number_) == nacks.end())
|
|
|
|
|
<< "Got nack for ULPFEC packet";
|
2015-01-28 13:58:27 +00:00
|
|
|
if (!nacks.empty() &&
|
2016-10-31 03:45:58 -07:00
|
|
|
IsNewerSequenceNumber(nacks.back(), ulpfec_sequence_number_)) {
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2015-01-28 13:58:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::PacketTransport* CreateSendTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
|
|
|
|
Call* sender_call) override {
|
2016-01-08 06:47:13 -08:00
|
|
|
// At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
|
|
|
|
|
// Configure some network delay.
|
|
|
|
|
const int kNetworkDelayMs = 50;
|
|
|
|
|
FakeNetworkPipe::Config config;
|
|
|
|
|
config.queue_delay_ms = kNetworkDelayMs;
|
2017-08-22 04:02:52 -07:00
|
|
|
return new test::PacketTransport(task_queue, sender_call, this,
|
Reland of Don't hardcode MediaType::ANY in FakeNetworkPipe. (patchset #1 id:1 of https://codereview.webrtc.org/2784543002/ )
Reason for revert:
Intend to fix perf failures and reland.
Original issue's description:
> Revert of Don't hardcode MediaType::ANY in FakeNetworkPipe. (patchset #4 id:60001 of https://codereview.webrtc.org/2774463003/ )
>
> Reason for revert:
> Reverting since this seems to break multiple WebRTC Perf buildbots
>
> Original issue's description:
> > Don't hardcode MediaType::ANY in FakeNetworkPipe.
> >
> > Instead let each test set the appropriate media type. This simplifies
> > demuxing in Call and later in RtpTransportController.
> >
> > BUG=webrtc:7135
> >
> > Review-Url: https://codereview.webrtc.org/2774463003
> > Cr-Commit-Position: refs/heads/master@{#17418}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/9c47b00e24da2941eb095df5a4459c6d98a8a88d
>
> TBR=stefan@webrtc.org,deadbeef@webrtc.org,solenberg@webrtc.org,pbos@webrtc.org,sprang@webrtc.org,nisse@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:7135
>
> Review-Url: https://codereview.webrtc.org/2784543002
> Cr-Commit-Position: refs/heads/master@{#17427}
> Committed: https://chromium.googlesource.com/external/webrtc/+/3a3bd5061089da5327fc549337a8430054d66057
TBR=stefan@webrtc.org,deadbeef@webrtc.org,solenberg@webrtc.org,pbos@webrtc.org,sprang@webrtc.org,lliuu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:7135
Review-Url: https://codereview.webrtc.org/2783853002
Cr-Commit-Position: refs/heads/master@{#17459}
2017-03-29 23:57:43 -07:00
|
|
|
test::PacketTransport::kSender,
|
2017-04-10 16:57:57 -07:00
|
|
|
payload_type_map_, config);
|
2016-01-08 06:47:13 -08:00
|
|
|
}
|
|
|
|
|
|
2015-03-26 11:11:06 +01:00
|
|
|
// TODO(holmer): Investigate why we don't send FEC packets when the bitrate
|
|
|
|
|
// is 10 kbps.
|
|
|
|
|
Call::Config GetSenderCallConfig() override {
|
2017-04-10 03:54:05 -07:00
|
|
|
Call::Config config(event_log_.get());
|
2015-03-26 11:11:06 +01:00
|
|
|
const int kMinBitrateBps = 30000;
|
|
|
|
|
config.bitrate_config.min_bitrate_bps = kMinBitrateBps;
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2015-01-28 13:58:27 +00:00
|
|
|
// Configure hybrid NACK/FEC.
|
|
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2016-10-04 23:28:39 -07:00
|
|
|
send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
|
|
|
|
|
send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
|
2016-05-27 14:12:09 +02:00
|
|
|
// Set codec to VP8, otherwise NACK/FEC hybrid will be disabled.
|
|
|
|
|
send_config->encoder_settings.encoder = encoder_.get();
|
|
|
|
|
send_config->encoder_settings.payload_name = "VP8";
|
|
|
|
|
send_config->encoder_settings.payload_type = kFakeVideoSendPayloadType;
|
|
|
|
|
|
2015-01-28 13:58:27 +00:00
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2017-09-26 02:49:21 -07:00
|
|
|
(*receive_configs)[0].rtp.red_payload_type = kRedPayloadType;
|
|
|
|
|
(*receive_configs)[0].rtp.ulpfec_payload_type = kUlpfecPayloadType;
|
2016-05-27 14:12:09 +02:00
|
|
|
|
|
|
|
|
(*receive_configs)[0].decoders.resize(1);
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_type =
|
|
|
|
|
send_config->encoder_settings.payload_type;
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_name =
|
|
|
|
|
send_config->encoder_settings.payload_name;
|
|
|
|
|
(*receive_configs)[0].decoders[0].decoder = decoder_.get();
|
2015-01-28 13:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2015-01-28 13:58:27 +00:00
|
|
|
<< "Timed out while waiting for FEC packets to be received.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum {
|
2015-02-25 11:47:11 +00:00
|
|
|
kFirstPacket,
|
2016-10-31 03:45:58 -07:00
|
|
|
kDropEveryOtherPacketUntilUlpfec,
|
|
|
|
|
kDropAllMediaPacketsUntilUlpfec,
|
2016-05-27 14:12:09 +02:00
|
|
|
kDropOneMediaPacket,
|
|
|
|
|
kPassOneMediaPacket,
|
2016-10-31 03:45:58 -07:00
|
|
|
kVerifyUlpfecPacketNotInNackList,
|
2015-01-28 13:58:27 +00:00
|
|
|
} state_;
|
|
|
|
|
|
2015-11-01 14:56:10 -08:00
|
|
|
rtc::CriticalSection crit_;
|
2017-09-09 04:17:22 -07:00
|
|
|
uint16_t ulpfec_sequence_number_ RTC_GUARDED_BY(&crit_);
|
2015-01-28 13:58:27 +00:00
|
|
|
bool has_last_sequence_number_;
|
|
|
|
|
uint16_t last_sequence_number_;
|
2016-05-27 14:12:09 +02:00
|
|
|
std::unique_ptr<webrtc::VideoEncoder> encoder_;
|
|
|
|
|
std::unique_ptr<webrtc::VideoDecoder> decoder_;
|
2015-10-27 08:29:42 -07:00
|
|
|
} test;
|
2015-01-28 13:58:27 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2015-01-28 13:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-24 09:30:53 +00:00
|
|
|
// This test drops second RTP packet with a marker bit set, makes sure it's
|
|
|
|
|
// retransmitted and renders. Retransmission SSRCs are also checked.
|
2016-02-15 11:27:15 +01:00
|
|
|
void EndToEndTest::DecodesRetransmittedFrame(bool enable_rtx, bool enable_red) {
|
2016-02-17 11:10:04 +01:00
|
|
|
static const int kDroppedFrameNumber = 10;
|
2014-06-27 08:47:52 +00:00
|
|
|
class RetransmissionObserver : public test::EndToEndTest,
|
2017-02-07 09:37:41 -08:00
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
2014-01-24 09:30:53 +00:00
|
|
|
public:
|
2016-02-15 11:27:15 +01:00
|
|
|
RetransmissionObserver(bool enable_rtx, bool enable_red)
|
2014-06-27 08:47:52 +00:00
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
2016-02-15 11:27:15 +01:00
|
|
|
payload_type_(GetPayloadType(false, enable_red)),
|
|
|
|
|
retransmission_ssrc_(enable_rtx ? kSendRtxSsrcs[0]
|
|
|
|
|
: kVideoSendSsrcs[0]),
|
|
|
|
|
retransmission_payload_type_(GetPayloadType(enable_rtx, enable_red)),
|
Reland of Stop using hardcoded payload types for video codecs (patchset #1 id:1 of https://codereview.webrtc.org/2513633002/ )
Reason for revert:
The WebRtcBrowserTest.NegotiateUnsupportedVideoCodec test has been fixed in Chromium with the following change:
function removeVideoCodec(offerSdp) {
- offerSdp = offerSdp.replace('a=rtpmap:100 VP8/90000\r\n',
- 'a=rtpmap:100 XVP8/90000\r\n');
+ offerSdp = offerSdp.replace(/a=rtpmap:(\d+)\ VP8\/90000\r\n/,
+ 'a=rtpmap:$1 XVP8/90000\r\n');
return offerSdp;
}
Original issue's description:
> Revert of Stop using hardcoded payload types for video codecs (patchset #6 id:210001 of https://codereview.webrtc.org/2493133002/ )
>
> Reason for revert:
> Breaks chromium.fyi test:
> WebRtcBrowserTest.NegotiateUnsupportedVideoCodec
>
> Original issue's description:
> > Stop using hardcoded payload types for video codecs
> >
> > This CL stops using hardcoded payload types for different video codecs
> > and will dynamically assign them payload types incrementally from 96 to
> > 127 instead.
> >
> > This CL:
> > * Replaces 'std::vector<VideoCodec> DefaultVideoCodecList()' in
> > webrtcvideoengine2.cc with an explicit WebRtcVideoEncoderFactory for
> > internally supported software codecs instead. The purpose is to
> > streamline the payload type assignment in webrtcvideoengine2.cc which
> > will now have two encoder factories of the same
> > WebRtcVideoEncoderFactory type; one internal and one external.
> > * Removes webrtc::VideoEncoder::EncoderType and use cricket::VideoCodec
> > instead.
> > * Removes 'static VideoEncoder* Create(EncoderType codec_type)' and
> > moves the create function to the internal encoder factory instead.
> > * Removes video_encoder.cc. webrtc::VideoEncoder is now just an
> > interface without any static functions.
> > * The function GetSupportedCodecs in webrtcvideoengine2.cc unifies
> > the internal and external codecs and assigns them payload types
> > incrementally from 96 to 127.
> > * Updates webrtcvideoengine2_unittest.cc and removes assumptions about
> > what payload types will be used.
> >
> > BUG=webrtc:6677,webrtc:6705
> > R=hta@webrtc.org, ossu@webrtc.org, stefan@webrtc.org
> >
> > Committed: https://crrev.com/42043b95872b51321f508bf255d804ce3dff366b
> > Cr-Commit-Position: refs/heads/master@{#15135}
>
> TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:6677,webrtc:6705
>
> Committed: https://crrev.com/eacbaea920797ff751ca83050d140821f5055591
> Cr-Commit-Position: refs/heads/master@{#15140}
TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:6677,webrtc:6705
Review-Url: https://codereview.webrtc.org/2511933002
Cr-Commit-Position: refs/heads/master@{#15148}
2016-11-18 01:34:11 -08:00
|
|
|
encoder_(VP8Encoder::Create()),
|
2014-01-24 09:30:53 +00:00
|
|
|
marker_bits_observed_(0),
|
2016-07-25 08:20:51 -07:00
|
|
|
retransmitted_timestamp_(0) {}
|
2014-01-24 09:30:53 +00:00
|
|
|
|
|
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2014-01-24 09:30:53 +00:00
|
|
|
RTPHeader header;
|
2014-07-08 12:10:51 +00:00
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
2014-01-24 09:30:53 +00:00
|
|
|
|
2016-02-17 11:10:04 +01:00
|
|
|
// Ignore padding-only packets over RTX.
|
|
|
|
|
if (header.payloadType != payload_type_) {
|
|
|
|
|
EXPECT_EQ(retransmission_ssrc_, header.ssrc);
|
|
|
|
|
if (length == header.headerLength + header.paddingLength)
|
|
|
|
|
return SEND_PACKET;
|
2015-09-18 11:14:31 +02:00
|
|
|
}
|
2016-02-17 11:10:04 +01:00
|
|
|
|
2014-01-24 09:30:53 +00:00
|
|
|
if (header.timestamp == retransmitted_timestamp_) {
|
|
|
|
|
EXPECT_EQ(retransmission_ssrc_, header.ssrc);
|
|
|
|
|
EXPECT_EQ(retransmission_payload_type_, header.payloadType);
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 11:14:31 +02:00
|
|
|
// Found the final packet of the frame to inflict loss to, drop this and
|
|
|
|
|
// expect a retransmission.
|
2016-07-25 04:03:20 -07:00
|
|
|
if (header.payloadType == payload_type_ && header.markerBit &&
|
|
|
|
|
++marker_bits_observed_ == kDroppedFrameNumber) {
|
2016-06-29 15:29:34 +02:00
|
|
|
// This should be the only dropped packet.
|
|
|
|
|
EXPECT_EQ(0u, retransmitted_timestamp_);
|
2014-01-24 09:30:53 +00:00
|
|
|
retransmitted_timestamp_ = header.timestamp;
|
2016-07-25 08:20:51 -07:00
|
|
|
if (std::find(rendered_timestamps_.begin(), rendered_timestamps_.end(),
|
|
|
|
|
retransmitted_timestamp_) != rendered_timestamps_.end()) {
|
|
|
|
|
// Frame was rendered before last packet was scheduled for sending.
|
|
|
|
|
// This is extremly rare but possible scenario because prober able to
|
|
|
|
|
// resend packet before it was send.
|
|
|
|
|
// TODO(danilchap): Remove this corner case when prober would not be
|
|
|
|
|
// able to sneak in between packet saved to history for resending and
|
|
|
|
|
// pacer notified about existance of that packet for sending.
|
|
|
|
|
// See https://bugs.chromium.org/p/webrtc/issues/detail?id=5540 for
|
|
|
|
|
// details.
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
2014-01-24 09:30:53 +00:00
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 09:37:41 -08:00
|
|
|
void OnFrame(const VideoFrame& frame) override {
|
2017-08-23 00:55:17 -07:00
|
|
|
EXPECT_EQ(kVideoRotation_90, frame.rotation());
|
2017-02-08 07:09:05 -08:00
|
|
|
{
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
if (frame.timestamp() == retransmitted_timestamp_)
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
rendered_timestamps_.push_back(frame.timestamp());
|
|
|
|
|
}
|
2017-02-07 09:37:41 -08:00
|
|
|
orig_renderer_->OnFrame(frame);
|
2014-01-24 09:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2014-06-27 08:47:52 +00:00
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2017-02-07 09:37:41 -08:00
|
|
|
|
|
|
|
|
// Insert ourselves into the rendering pipeline.
|
|
|
|
|
RTC_DCHECK(!orig_renderer_);
|
|
|
|
|
orig_renderer_ = (*receive_configs)[0].renderer;
|
|
|
|
|
RTC_DCHECK(orig_renderer_);
|
2017-02-08 07:09:05 -08:00
|
|
|
(*receive_configs)[0].disable_prerenderer_smoothing = true;
|
2017-02-07 09:37:41 -08:00
|
|
|
(*receive_configs)[0].renderer = this;
|
|
|
|
|
|
2014-06-30 13:19:09 +00:00
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2015-04-21 20:24:50 +08:00
|
|
|
|
|
|
|
|
if (payload_type_ == kRedPayloadType) {
|
2016-10-04 23:28:39 -07:00
|
|
|
send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
|
|
|
|
|
send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
|
2016-02-03 13:29:59 +01:00
|
|
|
if (retransmission_ssrc_ == kSendRtxSsrcs[0])
|
2016-10-04 23:28:39 -07:00
|
|
|
send_config->rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType;
|
2017-09-26 02:49:21 -07:00
|
|
|
(*receive_configs)[0].rtp.ulpfec_payload_type =
|
2016-10-04 23:28:39 -07:00
|
|
|
send_config->rtp.ulpfec.ulpfec_payload_type;
|
2017-09-26 02:49:21 -07:00
|
|
|
(*receive_configs)[0].rtp.red_payload_type =
|
2016-10-04 23:28:39 -07:00
|
|
|
send_config->rtp.ulpfec.red_payload_type;
|
2015-04-21 20:24:50 +08:00
|
|
|
}
|
|
|
|
|
|
2014-07-07 13:06:48 +00:00
|
|
|
if (retransmission_ssrc_ == kSendRtxSsrcs[0]) {
|
|
|
|
|
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
2014-06-27 08:47:52 +00:00
|
|
|
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
Reland of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #1 id:1 of https://codereview.webrtc.org/2649323010/ )
Reason for revert:
Downstream project relied on changed struct.
Transition made possible by https://codereview.webrtc.org/2655243006/.
Original issue's description:
> Revert of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #7 id:160001 of https://codereview.webrtc.org/2646073004/ )
>
> Reason for revert:
> Breaks internal downstream project.
>
> Original issue's description:
> > Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters.
> >
> > Prior to this CL, received RTX (associated) payload types were only configured
> > when WebRtcVideoChannel2::AddRecvStream was called. In the same method, the RTX
> > SSRC was set up.
> >
> > After this CL, the RTX (associated) payload types are set in
> > WebRtcVideoChannel2::SetRecvParameters, which is the appropriate place to set
> > them. The RTX SSRC is still set in WebRtcVideoChannel2::AddRecvStream, since
> > that is the code path that sets other SSRCs.
> >
> > As part of this fix, the VideoReceiveStream::Config::Rtp struct is changed.
> > We remove the possibility for each video payload type to have an associated
> > specific RTX SSRC. Although the config previously allowed for this, all payload
> > types always had the same RTX SSRC set, and the underlying RtpPayloadRegistry
> > did not support multiple SSRCs. This change to the config struct should thus not
> > have any functional impact. The change does however affect the RtcEventLog, since
> > that is used for storing the VideoReceiveStream::Configs. For simplicity,
> > this CL does not change the event log proto definitions, instead duplicating
> > the serialized RTX SSRCs such that they fit in the existing proto definition.
> >
> > BUG=webrtc:7011
> >
> > Review-Url: https://codereview.webrtc.org/2646073004
> > Cr-Commit-Position: refs/heads/master@{#16302}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/fe2bef39cd2a5c891a49f7320514fb04324dc66c
>
> TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,brandtr@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:7011
>
> Review-Url: https://codereview.webrtc.org/2649323010
> Cr-Commit-Position: refs/heads/master@{#16307}
> Committed: https://chromium.googlesource.com/external/webrtc/+/e4974953ce0d03a60fae7659b199a6a62a79fa30
TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,kjellander@webrtc.org,kjellander@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
# NOTREECHECKS=true
# NOTRY=true
BUG=webrtc:7011
Review-Url: https://codereview.webrtc.org/2654163006
Cr-Commit-Position: refs/heads/master@{#16322}
2017-01-27 04:53:07 -08:00
|
|
|
(*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
|
2017-08-25 04:44:25 -07:00
|
|
|
(*receive_configs)[0]
|
Reland of Use RtxReceiveStream. (patchset #1 id:1 of https://codereview.webrtc.org/3007303002/ )
Reason for revert:
Identified a configuration problem in the video quality tests. Intend to fix and reland.
Original issue's description:
> Revert of Use RtxReceiveStream. (patchset #5 id:320001 of https://codereview.webrtc.org/3006063002/ )
>
> Reason for revert:
> This change appears to break ulpfec, with severe regressions, e.g., for webrtc_perf_test FullStackTest.ForemanCifPlr5Ulpfec
>
> Original issue's description:
> > Reland of Use RtxReceiveStream. (patchset #1 id:1 of https://codereview.webrtc.org/3010983002/ )
> >
> > Reason for revert:
> > Intend to fix perf failures and reland.
> >
> > Original issue's description:
> > > Revert of Use RtxReceiveStream. (patchset #5 id:80001 of https://codereview.webrtc.org/3008773002/ )
> > >
> > > Reason for revert:
> > > A few perf tests broken, including
> > >
> > > RampUpTest.UpDownUpAbsSendTimeSimulcastRedRtx
> > > RampUpTest.UpDownUpTransportSequenceNumberRtx
> > > RampUpTest.UpDownUpTransportSequenceNumberPacketLoss
> > >
> > >
> > > Original issue's description:
> > > > Use RtxReceiveStream.
> > > >
> > > > This also has the beneficial side-effect that when a media stream
> > > > which is protected by FlexFEC receives an RTX retransmission, the
> > > > retransmitted media packet is passed into the FlexFEC machinery,
> > > > which should improve its ability to recover packets via FEC.
> > > >
> > > > BUG=webrtc:7135
> > > >
> > > > Review-Url: https://codereview.webrtc.org/3008773002
> > > > Cr-Commit-Position: refs/heads/master@{#19649}
> > > > Committed: https://chromium.googlesource.com/external/webrtc/+/5c0f6c62ea3b1d2c43f8fc152961af27033475f7
> > >
> > > TBR=brandtr@webrtc.org,danilchap@webrtc.org,stefan@webrtc.org,magjed@webrtc.org
> > > # Skipping CQ checks because original CL landed less than 1 days ago.
> > > NOPRESUBMIT=true
> > > NOTREECHECKS=true
> > > NOTRY=true
> > > BUG=webrtc:7135
> > >
> > > Review-Url: https://codereview.webrtc.org/3010983002
> > > Cr-Commit-Position: refs/heads/master@{#19653}
> > > Committed: https://chromium.googlesource.com/external/webrtc/+/3c39c0137afa274d1d524b150b50304b38a2847b
> >
> > TBR=brandtr@webrtc.org,danilchap@webrtc.org,stefan@webrtc.org,magjed@webrtc.org
> > # Skipping CQ checks because original CL landed less than 1 days ago.
> > NOPRESUBMIT=true
> > NOTREECHECKS=true
> > BUG=webrtc:7135
> >
> > Review-Url: https://codereview.webrtc.org/3006063002
> > Cr-Commit-Position: refs/heads/master@{#19715}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/35713eaf565c0fef07c8afc158d7b8fdf7ec3d78
>
> TBR=brandtr@webrtc.org,danilchap@webrtc.org,stefan@webrtc.org,magjed@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7135
>
> Review-Url: https://codereview.webrtc.org/3007303002
> Cr-Commit-Position: refs/heads/master@{#19744}
> Committed: https://chromium.googlesource.com/external/webrtc/+/8e7eee035178a7f10e19883681b5eaa4a7523107
TBR=brandtr@webrtc.org,danilchap@webrtc.org,stefan@webrtc.org,magjed@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7135
Review-Url: https://codereview.webrtc.org/3012963002
Cr-Commit-Position: refs/heads/master@{#19765}
2017-09-11 02:32:16 -07:00
|
|
|
.rtp.rtx_associated_payload_types[(payload_type_ == kRedPayloadType)
|
|
|
|
|
? kRtxRedPayloadType
|
|
|
|
|
: kSendRtxPayloadType] =
|
2017-08-25 04:44:25 -07:00
|
|
|
payload_type_;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2016-02-15 11:27:15 +01:00
|
|
|
// Configure encoding and decoding with VP8, since generic packetization
|
|
|
|
|
// doesn't support FEC with NACK.
|
2016-11-28 15:21:39 -08:00
|
|
|
RTC_DCHECK_EQ(1, (*receive_configs)[0].decoders.size());
|
2016-02-15 11:27:15 +01:00
|
|
|
send_config->encoder_settings.encoder = encoder_.get();
|
|
|
|
|
send_config->encoder_settings.payload_name = "VP8";
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_name = "VP8";
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2017-08-23 00:55:17 -07:00
|
|
|
void OnFrameGeneratorCapturerCreated(
|
|
|
|
|
test::FrameGeneratorCapturer* frame_generator_capturer) override {
|
|
|
|
|
frame_generator_capturer->SetFakeRotation(kVideoRotation_90);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2014-06-27 08:47:52 +00:00
|
|
|
<< "Timed out while waiting for retransmission to render.";
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-26 02:49:21 -07:00
|
|
|
int GetPayloadType(bool use_rtx, bool use_fec) {
|
|
|
|
|
if (use_fec) {
|
2016-02-03 13:29:59 +01:00
|
|
|
if (use_rtx)
|
|
|
|
|
return kRtxRedPayloadType;
|
|
|
|
|
return kRedPayloadType;
|
|
|
|
|
}
|
|
|
|
|
if (use_rtx)
|
|
|
|
|
return kSendRtxPayloadType;
|
|
|
|
|
return kFakeVideoSendPayloadType;
|
2015-04-21 20:24:50 +08:00
|
|
|
}
|
|
|
|
|
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CriticalSection crit_;
|
2017-02-07 09:37:41 -08:00
|
|
|
rtc::VideoSinkInterface<VideoFrame>* orig_renderer_ = nullptr;
|
2015-04-21 20:24:50 +08:00
|
|
|
const int payload_type_;
|
2014-01-24 09:30:53 +00:00
|
|
|
const uint32_t retransmission_ssrc_;
|
|
|
|
|
const int retransmission_payload_type_;
|
2016-03-01 11:52:33 -08:00
|
|
|
std::unique_ptr<VideoEncoder> encoder_;
|
2016-02-15 11:27:15 +01:00
|
|
|
const std::string payload_name_;
|
2014-01-24 09:30:53 +00:00
|
|
|
int marker_bits_observed_;
|
2017-09-09 04:17:22 -07:00
|
|
|
uint32_t retransmitted_timestamp_ RTC_GUARDED_BY(&crit_);
|
|
|
|
|
std::vector<uint32_t> rendered_timestamps_ RTC_GUARDED_BY(&crit_);
|
2016-02-15 11:27:15 +01:00
|
|
|
} test(enable_rtx, enable_red);
|
2014-01-24 09:30:53 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-01-24 09:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DecodesRetransmittedFrame) {
|
2015-04-21 20:24:50 +08:00
|
|
|
DecodesRetransmittedFrame(false, false);
|
2014-01-24 09:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DecodesRetransmittedFrameOverRtx) {
|
2015-04-21 20:24:50 +08:00
|
|
|
DecodesRetransmittedFrame(true, false);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DecodesRetransmittedFrameByRed) {
|
2015-04-21 20:24:50 +08:00
|
|
|
DecodesRetransmittedFrame(false, true);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DecodesRetransmittedFrameByRedOverRtx) {
|
2015-04-21 20:24:50 +08:00
|
|
|
DecodesRetransmittedFrame(true, true);
|
2014-01-24 09:30:53 +00:00
|
|
|
}
|
|
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
void EndToEndTest::ReceivesPliAndRecovers(int rtp_history_ms) {
|
|
|
|
|
static const int kPacketsToDrop = 1;
|
2013-08-19 16:09:34 +00:00
|
|
|
|
2016-03-23 04:48:10 -07:00
|
|
|
class PliObserver : public test::EndToEndTest,
|
|
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
2014-06-27 08:47:52 +00:00
|
|
|
public:
|
|
|
|
|
explicit PliObserver(int rtp_history_ms)
|
|
|
|
|
: EndToEndTest(kLongTimeoutMs),
|
|
|
|
|
rtp_history_ms_(rtp_history_ms),
|
|
|
|
|
nack_enabled_(rtp_history_ms > 0),
|
|
|
|
|
highest_dropped_timestamp_(0),
|
|
|
|
|
frames_to_drop_(0),
|
|
|
|
|
received_pli_(false) {}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2014-06-27 08:47:52 +00:00
|
|
|
RTPHeader header;
|
2014-07-08 12:10:51 +00:00
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
2013-08-19 16:09:34 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
// Drop all retransmitted packets to force a PLI.
|
|
|
|
|
if (header.timestamp <= highest_dropped_timestamp_)
|
|
|
|
|
return DROP_PACKET;
|
2013-08-19 16:09:34 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
if (frames_to_drop_ > 0) {
|
|
|
|
|
highest_dropped_timestamp_ = header.timestamp;
|
|
|
|
|
--frames_to_drop_;
|
|
|
|
|
return DROP_PACKET;
|
2013-08-19 16:09:34 +00:00
|
|
|
}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
2013-08-19 16:09:34 +00:00
|
|
|
}
|
2013-12-18 09:45:45 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
2016-11-02 08:21:59 -07:00
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
|
if (!nack_enabled_)
|
|
|
|
|
EXPECT_EQ(0, parser.nack()->num_packets());
|
|
|
|
|
if (parser.pli()->num_packets() > 0)
|
|
|
|
|
received_pli_ = true;
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2016-03-21 01:27:56 -07:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&crit_);
|
2014-06-27 08:47:52 +00:00
|
|
|
if (received_pli_ &&
|
|
|
|
|
video_frame.timestamp() > highest_dropped_timestamp_) {
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
|
|
|
|
if (!received_pli_)
|
|
|
|
|
frames_to_drop_ = kPacketsToDrop;
|
|
|
|
|
}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2014-06-27 08:47:52 +00:00
|
|
|
send_config->rtp.nack.rtp_history_ms = rtp_history_ms_;
|
2014-06-30 13:19:09 +00:00
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = rtp_history_ms_;
|
|
|
|
|
(*receive_configs)[0].renderer = this;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2013-08-05 12:01:36 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait()) << "Timed out waiting for PLI to be "
|
|
|
|
|
"received and a frame to be "
|
|
|
|
|
"rendered afterwards.";
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2013-08-19 16:09:34 +00:00
|
|
|
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CriticalSection crit_;
|
2014-06-27 08:47:52 +00:00
|
|
|
int rtp_history_ms_;
|
|
|
|
|
bool nack_enabled_;
|
2017-09-09 04:17:22 -07:00
|
|
|
uint32_t highest_dropped_timestamp_ RTC_GUARDED_BY(&crit_);
|
|
|
|
|
int frames_to_drop_ RTC_GUARDED_BY(&crit_);
|
|
|
|
|
bool received_pli_ RTC_GUARDED_BY(&crit_);
|
2014-06-27 08:47:52 +00:00
|
|
|
} test(rtp_history_ms);
|
2013-09-09 08:26:30 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2013-08-05 12:01:36 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceivesPliAndRecoversWithNack) {
|
2013-08-19 16:09:34 +00:00
|
|
|
ReceivesPliAndRecovers(1000);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceivesPliAndRecoversWithoutNack) {
|
2013-08-19 16:09:34 +00:00
|
|
|
ReceivesPliAndRecovers(0);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, UnknownRtpPacketGivesUnknownSsrcReturnCode) {
|
2013-09-05 12:38:54 +00:00
|
|
|
class PacketInputObserver : public PacketReceiver {
|
|
|
|
|
public:
|
|
|
|
|
explicit PacketInputObserver(PacketReceiver* receiver)
|
2015-12-10 13:02:50 +01:00
|
|
|
: receiver_(receiver), delivered_packet_(false, false) {}
|
2013-09-05 12:38:54 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
bool Wait() { return delivered_packet_.Wait(kDefaultTimeoutMs); }
|
2013-09-05 12:38:54 +00:00
|
|
|
|
|
|
|
|
private:
|
2015-09-08 05:36:15 -07:00
|
|
|
DeliveryStatus DeliverPacket(MediaType media_type,
|
|
|
|
|
const uint8_t* packet,
|
|
|
|
|
size_t length,
|
|
|
|
|
const PacketTime& packet_time) override {
|
2014-07-08 12:10:51 +00:00
|
|
|
if (RtpHeaderParser::IsRtcp(packet, length)) {
|
2015-09-08 05:36:15 -07:00
|
|
|
return receiver_->DeliverPacket(media_type, packet, length,
|
|
|
|
|
packet_time);
|
2013-09-05 12:38:54 +00:00
|
|
|
} else {
|
2014-05-14 13:57:12 +00:00
|
|
|
DeliveryStatus delivery_status =
|
2015-09-08 05:36:15 -07:00
|
|
|
receiver_->DeliverPacket(media_type, packet, length, packet_time);
|
2014-05-14 13:57:12 +00:00
|
|
|
EXPECT_EQ(DELIVERY_UNKNOWN_SSRC, delivery_status);
|
2015-12-10 13:02:50 +01:00
|
|
|
delivered_packet_.Set();
|
2014-05-14 13:57:12 +00:00
|
|
|
return delivery_status;
|
2013-09-05 12:38:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PacketReceiver* receiver_;
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event delivered_packet_;
|
2013-09-05 12:38:54 +00:00
|
|
|
};
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::DirectTransport> send_transport;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> receive_transport;
|
|
|
|
|
std::unique_ptr<PacketInputObserver> input_observer;
|
2013-09-05 12:38:54 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &send_transport, &receive_transport,
|
|
|
|
|
&input_observer]() {
|
|
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
2013-09-05 12:38:54 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
send_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, sender_call_.get(), payload_type_map_);
|
|
|
|
|
receive_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, receiver_call_.get(), payload_type_map_);
|
|
|
|
|
input_observer =
|
|
|
|
|
rtc::MakeUnique<PacketInputObserver>(receiver_call_->Receiver());
|
|
|
|
|
send_transport->SetReceiver(input_observer.get());
|
|
|
|
|
receive_transport->SetReceiver(sender_call_->Receiver());
|
2013-09-05 12:38:54 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateSendConfig(1, 0, 0, send_transport.get());
|
|
|
|
|
CreateMatchingReceiveConfigs(receive_transport.get());
|
2013-09-05 12:38:54 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateVideoStreams();
|
|
|
|
|
CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
|
|
|
|
|
kDefaultHeight);
|
|
|
|
|
Start();
|
2013-09-05 12:38:54 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
receiver_call_->DestroyVideoReceiveStream(video_receive_streams_[0]);
|
|
|
|
|
video_receive_streams_.clear();
|
|
|
|
|
});
|
2013-09-05 12:38:54 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// Wait() waits for a received packet.
|
|
|
|
|
EXPECT_TRUE(input_observer->Wait());
|
|
|
|
|
|
|
|
|
|
task_queue_.SendTask([this, &send_transport, &receive_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
send_transport.reset();
|
|
|
|
|
receive_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2013-09-05 12:38:54 +00:00
|
|
|
}
|
2013-10-01 11:33:24 +00:00
|
|
|
|
2015-10-02 02:36:56 -07:00
|
|
|
void EndToEndTest::RespectsRtcpMode(RtcpMode rtcp_mode) {
|
2013-10-17 14:14:42 +00:00
|
|
|
static const int kNumCompoundRtcpPacketsToObserve = 10;
|
2014-06-27 08:47:52 +00:00
|
|
|
class RtcpModeObserver : public test::EndToEndTest {
|
2013-10-17 14:14:42 +00:00
|
|
|
public:
|
2015-10-02 02:36:56 -07:00
|
|
|
explicit RtcpModeObserver(RtcpMode rtcp_mode)
|
2014-06-27 08:47:52 +00:00
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
2013-10-17 14:14:42 +00:00
|
|
|
rtcp_mode_(rtcp_mode),
|
|
|
|
|
sent_rtp_(0),
|
|
|
|
|
sent_rtcp_(0) {}
|
|
|
|
|
|
|
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2017-02-06 06:29:38 -08:00
|
|
|
rtc::CritScope lock(&crit_);
|
2013-10-17 14:14:42 +00:00
|
|
|
if (++sent_rtp_ % 3 == 0)
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2017-02-06 06:29:38 -08:00
|
|
|
rtc::CritScope lock(&crit_);
|
2013-10-17 14:14:42 +00:00
|
|
|
++sent_rtcp_;
|
2016-11-02 08:21:59 -07:00
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(0, parser.sender_report()->num_packets());
|
2013-10-17 14:14:42 +00:00
|
|
|
|
|
|
|
|
switch (rtcp_mode_) {
|
2015-10-02 02:36:56 -07:00
|
|
|
case RtcpMode::kCompound:
|
2017-02-06 06:29:38 -08:00
|
|
|
// TODO(holmer): We shouldn't send transport feedback alone if
|
|
|
|
|
// compound RTCP is negotiated.
|
|
|
|
|
if (parser.receiver_report()->num_packets() == 0 &&
|
|
|
|
|
parser.transport_feedback()->num_packets() == 0) {
|
2013-10-17 14:14:42 +00:00
|
|
|
ADD_FAILURE() << "Received RTCP packet without receiver report for "
|
2015-10-02 02:36:56 -07:00
|
|
|
"RtcpMode::kCompound.";
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2013-10-17 14:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sent_rtcp_ >= kNumCompoundRtcpPacketsToObserve)
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2013-10-17 14:14:42 +00:00
|
|
|
|
|
|
|
|
break;
|
2015-10-02 02:36:56 -07:00
|
|
|
case RtcpMode::kReducedSize:
|
2016-11-02 08:21:59 -07:00
|
|
|
if (parser.receiver_report()->num_packets() == 0)
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2013-10-17 14:14:42 +00:00
|
|
|
break;
|
2015-10-02 02:36:56 -07:00
|
|
|
case RtcpMode::kOff:
|
|
|
|
|
RTC_NOTREACHED();
|
|
|
|
|
break;
|
2013-10-17 14:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2014-06-27 08:47:52 +00:00
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2014-06-30 13:19:09 +00:00
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
(*receive_configs)[0].rtp.rtcp_mode = rtcp_mode_;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2015-10-02 02:36:56 -07:00
|
|
|
<< (rtcp_mode_ == RtcpMode::kCompound
|
2014-06-27 08:47:52 +00:00
|
|
|
? "Timed out before observing enough compound packets."
|
|
|
|
|
: "Timed out before receiving a non-compound RTCP packet.");
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-02 02:36:56 -07:00
|
|
|
RtcpMode rtcp_mode_;
|
2017-02-06 06:29:38 -08:00
|
|
|
rtc::CriticalSection crit_;
|
|
|
|
|
// Must be protected since RTCP can be sent by both the process thread
|
|
|
|
|
// and the pacer thread.
|
2017-09-09 04:17:22 -07:00
|
|
|
int sent_rtp_ RTC_GUARDED_BY(&crit_);
|
|
|
|
|
int sent_rtcp_ RTC_GUARDED_BY(&crit_);
|
2014-06-27 08:47:52 +00:00
|
|
|
} test(rtcp_mode);
|
2013-10-17 14:14:42 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2013-10-17 14:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, UsesRtcpCompoundMode) {
|
2015-10-02 02:36:56 -07:00
|
|
|
RespectsRtcpMode(RtcpMode::kCompound);
|
2013-10-17 14:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, UsesRtcpReducedSizeMode) {
|
2015-10-02 02:36:56 -07:00
|
|
|
RespectsRtcpMode(RtcpMode::kReducedSize);
|
2013-10-17 14:14:42 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-01 11:33:24 +00:00
|
|
|
// Test sets up a Call multiple senders with different resolutions and SSRCs.
|
|
|
|
|
// Another is set up to receive all three of these with different renderers.
|
2015-08-03 04:38:41 -07:00
|
|
|
class MultiStreamTest {
|
|
|
|
|
public:
|
2017-04-10 16:57:57 -07:00
|
|
|
static constexpr size_t kNumStreams = 3;
|
|
|
|
|
const uint8_t kVideoPayloadType = 124;
|
|
|
|
|
const std::map<uint8_t, MediaType> payload_type_map_ = {
|
|
|
|
|
{kVideoPayloadType, MediaType::VIDEO}};
|
|
|
|
|
|
2015-08-03 04:38:41 -07:00
|
|
|
struct CodecSettings {
|
|
|
|
|
uint32_t ssrc;
|
|
|
|
|
int width;
|
|
|
|
|
int height;
|
|
|
|
|
} codec_settings[kNumStreams];
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
explicit MultiStreamTest(test::SingleThreadedTaskQueueForTesting* task_queue)
|
|
|
|
|
: task_queue_(task_queue) {
|
2015-08-03 04:38:41 -07:00
|
|
|
// TODO(sprang): Cleanup when msvc supports explicit initializers for array.
|
|
|
|
|
codec_settings[0] = {1, 640, 480};
|
|
|
|
|
codec_settings[1] = {2, 320, 240};
|
|
|
|
|
codec_settings[2] = {3, 240, 160};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ~MultiStreamTest() {}
|
|
|
|
|
|
|
|
|
|
void RunTest() {
|
2016-10-07 11:53:05 -07:00
|
|
|
webrtc::RtcEventLogNullImpl event_log;
|
|
|
|
|
Call::Config config(&event_log);
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<Call> sender_call;
|
|
|
|
|
std::unique_ptr<Call> receiver_call;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> sender_transport;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> receiver_transport;
|
2015-08-03 04:38:41 -07:00
|
|
|
|
|
|
|
|
VideoSendStream* send_streams[kNumStreams];
|
|
|
|
|
VideoReceiveStream* receive_streams[kNumStreams];
|
|
|
|
|
test::FrameGeneratorCapturer* frame_generators[kNumStreams];
|
2016-03-31 10:24:26 -07:00
|
|
|
std::vector<std::unique_ptr<VideoDecoder>> allocated_decoders;
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<VideoEncoder> encoders[kNumStreams];
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_->SendTask([&]() {
|
|
|
|
|
sender_call = rtc::WrapUnique(Call::Create(config));
|
|
|
|
|
receiver_call = rtc::WrapUnique(Call::Create(config));
|
|
|
|
|
sender_transport =
|
|
|
|
|
rtc::WrapUnique(CreateSendTransport(task_queue_, sender_call.get()));
|
|
|
|
|
receiver_transport = rtc::WrapUnique(
|
|
|
|
|
CreateReceiveTransport(task_queue_, receiver_call.get()));
|
|
|
|
|
|
|
|
|
|
sender_transport->SetReceiver(receiver_call->Receiver());
|
|
|
|
|
receiver_transport->SetReceiver(sender_call->Receiver());
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < kNumStreams; ++i)
|
2017-11-13 14:10:02 +01:00
|
|
|
encoders[i] = VP8Encoder::Create();
|
2017-08-22 04:02:52 -07:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < kNumStreams; ++i) {
|
|
|
|
|
uint32_t ssrc = codec_settings[i].ssrc;
|
|
|
|
|
int width = codec_settings[i].width;
|
|
|
|
|
int height = codec_settings[i].height;
|
|
|
|
|
|
|
|
|
|
VideoSendStream::Config send_config(sender_transport.get());
|
|
|
|
|
send_config.rtp.ssrcs.push_back(ssrc);
|
|
|
|
|
send_config.encoder_settings.encoder = encoders[i].get();
|
|
|
|
|
send_config.encoder_settings.payload_name = "VP8";
|
|
|
|
|
send_config.encoder_settings.payload_type = kVideoPayloadType;
|
|
|
|
|
VideoEncoderConfig encoder_config;
|
|
|
|
|
test::FillEncoderConfiguration(1, &encoder_config);
|
|
|
|
|
encoder_config.max_bitrate_bps = 100000;
|
|
|
|
|
|
|
|
|
|
UpdateSendConfig(i, &send_config, &encoder_config,
|
|
|
|
|
&frame_generators[i]);
|
|
|
|
|
|
|
|
|
|
send_streams[i] = sender_call->CreateVideoSendStream(
|
|
|
|
|
send_config.Copy(), encoder_config.Copy());
|
|
|
|
|
send_streams[i]->Start();
|
|
|
|
|
|
|
|
|
|
VideoReceiveStream::Config receive_config(receiver_transport.get());
|
|
|
|
|
receive_config.rtp.remote_ssrc = ssrc;
|
|
|
|
|
receive_config.rtp.local_ssrc = test::CallTest::kReceiverLocalVideoSsrc;
|
|
|
|
|
VideoReceiveStream::Decoder decoder =
|
|
|
|
|
test::CreateMatchingDecoder(send_config.encoder_settings);
|
|
|
|
|
allocated_decoders.push_back(
|
|
|
|
|
std::unique_ptr<VideoDecoder>(decoder.decoder));
|
|
|
|
|
receive_config.decoders.push_back(decoder);
|
|
|
|
|
|
|
|
|
|
UpdateReceiveConfig(i, &receive_config);
|
|
|
|
|
|
|
|
|
|
receive_streams[i] =
|
|
|
|
|
receiver_call->CreateVideoReceiveStream(std::move(receive_config));
|
|
|
|
|
receive_streams[i]->Start();
|
|
|
|
|
|
|
|
|
|
frame_generators[i] = test::FrameGeneratorCapturer::Create(
|
|
|
|
|
width, height, 30, Clock::GetRealTimeClock());
|
|
|
|
|
send_streams[i]->SetSource(
|
|
|
|
|
frame_generators[i],
|
|
|
|
|
VideoSendStream::DegradationPreference::kMaintainFramerate);
|
|
|
|
|
frame_generators[i]->Start();
|
|
|
|
|
}
|
|
|
|
|
});
|
2015-08-03 04:38:41 -07:00
|
|
|
|
|
|
|
|
Wait();
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_->SendTask([&]() {
|
|
|
|
|
for (size_t i = 0; i < kNumStreams; ++i) {
|
|
|
|
|
frame_generators[i]->Stop();
|
|
|
|
|
sender_call->DestroyVideoSendStream(send_streams[i]);
|
|
|
|
|
receiver_call->DestroyVideoReceiveStream(receive_streams[i]);
|
|
|
|
|
delete frame_generators[i];
|
|
|
|
|
}
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
sender_transport.reset();
|
|
|
|
|
receiver_transport.reset();
|
|
|
|
|
|
|
|
|
|
sender_call.reset();
|
|
|
|
|
receiver_call.reset();
|
|
|
|
|
});
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual void Wait() = 0;
|
|
|
|
|
// Note: frame_generator is a point-to-pointer, since the actual instance
|
|
|
|
|
// hasn't been created at the time of this call. Only when packets/frames
|
|
|
|
|
// start flowing should this be dereferenced.
|
|
|
|
|
virtual void UpdateSendConfig(
|
|
|
|
|
size_t stream_index,
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
VideoEncoderConfig* encoder_config,
|
|
|
|
|
test::FrameGeneratorCapturer** frame_generator) {}
|
|
|
|
|
virtual void UpdateReceiveConfig(size_t stream_index,
|
|
|
|
|
VideoReceiveStream::Config* receive_config) {
|
|
|
|
|
}
|
2017-08-22 04:02:52 -07:00
|
|
|
virtual test::DirectTransport* CreateSendTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
|
|
|
|
Call* sender_call) {
|
|
|
|
|
return new test::DirectTransport(task_queue, sender_call,
|
|
|
|
|
payload_type_map_);
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
2017-08-22 04:02:52 -07:00
|
|
|
virtual test::DirectTransport* CreateReceiveTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
|
|
|
|
Call* receiver_call) {
|
|
|
|
|
return new test::DirectTransport(task_queue, receiver_call,
|
|
|
|
|
payload_type_map_);
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
2017-08-22 04:02:52 -07:00
|
|
|
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* const task_queue_;
|
2015-08-03 04:38:41 -07:00
|
|
|
};
|
|
|
|
|
|
2013-10-01 11:33:24 +00:00
|
|
|
// Each renderer verifies that it receives the expected resolution, and as soon
|
|
|
|
|
// as every renderer has received a frame, the test finishes.
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, SendsAndReceivesMultipleStreams) {
|
2016-03-23 04:48:10 -07:00
|
|
|
class VideoOutputObserver : public rtc::VideoSinkInterface<VideoFrame> {
|
2013-10-01 11:33:24 +00:00
|
|
|
public:
|
2015-08-03 04:38:41 -07:00
|
|
|
VideoOutputObserver(const MultiStreamTest::CodecSettings& settings,
|
|
|
|
|
uint32_t ssrc,
|
|
|
|
|
test::FrameGeneratorCapturer** frame_generator)
|
|
|
|
|
: settings_(settings),
|
|
|
|
|
ssrc_(ssrc),
|
|
|
|
|
frame_generator_(frame_generator),
|
2015-12-10 13:02:50 +01:00
|
|
|
done_(false, false) {}
|
2013-10-01 11:33:24 +00:00
|
|
|
|
2016-03-21 01:27:56 -07:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
2015-08-03 04:38:41 -07:00
|
|
|
EXPECT_EQ(settings_.width, video_frame.width());
|
|
|
|
|
EXPECT_EQ(settings_.height, video_frame.height());
|
|
|
|
|
(*frame_generator_)->Stop();
|
2015-12-10 13:02:50 +01:00
|
|
|
done_.Set();
|
2013-10-01 11:33:24 +00:00
|
|
|
}
|
|
|
|
|
|
2015-08-03 04:38:41 -07:00
|
|
|
uint32_t Ssrc() { return ssrc_; }
|
|
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
bool Wait() { return done_.Wait(kDefaultTimeoutMs); }
|
2013-10-01 11:33:24 +00:00
|
|
|
|
|
|
|
|
private:
|
2015-08-03 04:38:41 -07:00
|
|
|
const MultiStreamTest::CodecSettings& settings_;
|
|
|
|
|
const uint32_t ssrc_;
|
|
|
|
|
test::FrameGeneratorCapturer** const frame_generator_;
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event done_;
|
2013-10-01 11:33:24 +00:00
|
|
|
};
|
|
|
|
|
|
2015-08-03 04:38:41 -07:00
|
|
|
class Tester : public MultiStreamTest {
|
|
|
|
|
public:
|
2017-08-22 04:02:52 -07:00
|
|
|
explicit Tester(test::SingleThreadedTaskQueueForTesting* task_queue)
|
|
|
|
|
: MultiStreamTest(task_queue) {}
|
2015-08-03 04:38:41 -07:00
|
|
|
virtual ~Tester() {}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void Wait() override {
|
|
|
|
|
for (const auto& observer : observers_) {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(observer->Wait()) << "Time out waiting for from on ssrc "
|
|
|
|
|
<< observer->Ssrc();
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
2013-10-01 11:33:24 +00:00
|
|
|
|
2015-08-03 04:38:41 -07:00
|
|
|
void UpdateSendConfig(
|
|
|
|
|
size_t stream_index,
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
VideoEncoderConfig* encoder_config,
|
|
|
|
|
test::FrameGeneratorCapturer** frame_generator) override {
|
|
|
|
|
observers_[stream_index].reset(new VideoOutputObserver(
|
|
|
|
|
codec_settings[stream_index], send_config->rtp.ssrcs.front(),
|
|
|
|
|
frame_generator));
|
|
|
|
|
}
|
2013-10-01 11:33:24 +00:00
|
|
|
|
2015-08-03 04:38:41 -07:00
|
|
|
void UpdateReceiveConfig(
|
|
|
|
|
size_t stream_index,
|
|
|
|
|
VideoReceiveStream::Config* receive_config) override {
|
|
|
|
|
receive_config->renderer = observers_[stream_index].get();
|
|
|
|
|
}
|
2013-10-01 11:33:24 +00:00
|
|
|
|
2015-08-03 04:38:41 -07:00
|
|
|
private:
|
2016-03-01 11:52:33 -08:00
|
|
|
std::unique_ptr<VideoOutputObserver> observers_[kNumStreams];
|
2017-08-22 04:02:52 -07:00
|
|
|
} tester(&task_queue_);
|
2013-10-01 11:33:24 +00:00
|
|
|
|
2015-08-03 04:38:41 -07:00
|
|
|
tester.RunTest();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, AssignsTransportSequenceNumbers) {
|
2015-08-03 04:38:41 -07:00
|
|
|
static const int kExtensionId = 5;
|
|
|
|
|
|
|
|
|
|
class RtpExtensionHeaderObserver : public test::DirectTransport {
|
|
|
|
|
public:
|
2017-04-10 16:57:57 -07:00
|
|
|
RtpExtensionHeaderObserver(
|
2017-08-22 04:02:52 -07:00
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
2017-04-10 16:57:57 -07:00
|
|
|
Call* sender_call,
|
|
|
|
|
const uint32_t& first_media_ssrc,
|
|
|
|
|
const std::map<uint32_t, uint32_t>& ssrc_map,
|
|
|
|
|
const std::map<uint8_t, MediaType>& payload_type_map)
|
2017-08-22 04:02:52 -07:00
|
|
|
: DirectTransport(task_queue, sender_call, payload_type_map),
|
2015-12-10 13:02:50 +01:00
|
|
|
done_(false, false),
|
2015-08-03 04:38:41 -07:00
|
|
|
parser_(RtpHeaderParser::Create()),
|
2015-10-16 10:01:21 -07:00
|
|
|
first_media_ssrc_(first_media_ssrc),
|
|
|
|
|
rtx_to_media_ssrcs_(ssrc_map),
|
2015-08-03 04:38:41 -07:00
|
|
|
padding_observed_(false),
|
2015-10-16 10:01:21 -07:00
|
|
|
rtx_padding_observed_(false),
|
|
|
|
|
retransmit_observed_(false),
|
|
|
|
|
started_(false) {
|
2015-08-03 04:38:41 -07:00
|
|
|
parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
|
|
|
|
|
kExtensionId);
|
|
|
|
|
}
|
|
|
|
|
virtual ~RtpExtensionHeaderObserver() {}
|
|
|
|
|
|
2015-10-02 03:39:33 -07:00
|
|
|
bool SendRtp(const uint8_t* data,
|
|
|
|
|
size_t length,
|
|
|
|
|
const PacketOptions& options) override {
|
2015-10-16 10:01:21 -07:00
|
|
|
{
|
|
|
|
|
rtc::CritScope cs(&lock_);
|
2015-08-04 16:24:03 +02:00
|
|
|
|
2015-10-16 10:01:21 -07:00
|
|
|
if (IsDone())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (started_) {
|
|
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(data, length, &header));
|
|
|
|
|
bool drop_packet = false;
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
|
|
|
|
|
EXPECT_EQ(options.packet_id,
|
2015-08-03 04:38:41 -07:00
|
|
|
header.extension.transportSequenceNumber);
|
2015-10-16 10:01:21 -07:00
|
|
|
if (!streams_observed_.empty()) {
|
|
|
|
|
// Unwrap packet id and verify uniqueness.
|
|
|
|
|
int64_t packet_id = unwrapper_.Unwrap(options.packet_id);
|
|
|
|
|
EXPECT_TRUE(received_packed_ids_.insert(packet_id).second);
|
|
|
|
|
}
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2015-10-16 10:01:21 -07:00
|
|
|
// Drop (up to) every 17th packet, so we get retransmits.
|
|
|
|
|
// Only drop media, and not on the first stream (otherwise it will be
|
|
|
|
|
// hard to distinguish from padding, which is always sent on the first
|
|
|
|
|
// stream).
|
|
|
|
|
if (header.payloadType != kSendRtxPayloadType &&
|
|
|
|
|
header.ssrc != first_media_ssrc_ &&
|
|
|
|
|
header.extension.transportSequenceNumber % 17 == 0) {
|
|
|
|
|
dropped_seq_[header.ssrc].insert(header.sequenceNumber);
|
|
|
|
|
drop_packet = true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-27 06:52:10 -08:00
|
|
|
if (header.payloadType == kSendRtxPayloadType) {
|
2015-10-16 10:01:21 -07:00
|
|
|
uint16_t original_sequence_number =
|
|
|
|
|
ByteReader<uint16_t>::ReadBigEndian(&data[header.headerLength]);
|
|
|
|
|
uint32_t original_ssrc =
|
|
|
|
|
rtx_to_media_ssrcs_.find(header.ssrc)->second;
|
|
|
|
|
std::set<uint16_t>* seq_no_map = &dropped_seq_[original_ssrc];
|
|
|
|
|
auto it = seq_no_map->find(original_sequence_number);
|
|
|
|
|
if (it != seq_no_map->end()) {
|
|
|
|
|
retransmit_observed_ = true;
|
|
|
|
|
seq_no_map->erase(it);
|
|
|
|
|
} else {
|
|
|
|
|
rtx_padding_observed_ = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
streams_observed_.insert(header.ssrc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsDone())
|
2015-12-10 13:02:50 +01:00
|
|
|
done_.Set();
|
2015-10-16 10:01:21 -07:00
|
|
|
|
|
|
|
|
if (drop_packet)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
2015-10-16 10:01:21 -07:00
|
|
|
|
2015-10-02 03:39:33 -07:00
|
|
|
return test::DirectTransport::SendRtp(data, length, options);
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-04 16:24:03 +02:00
|
|
|
bool IsDone() {
|
2015-10-16 10:01:21 -07:00
|
|
|
bool observed_types_ok =
|
|
|
|
|
streams_observed_.size() == MultiStreamTest::kNumStreams &&
|
2017-02-27 06:52:10 -08:00
|
|
|
retransmit_observed_ && rtx_padding_observed_;
|
2015-10-16 10:01:21 -07:00
|
|
|
if (!observed_types_ok)
|
|
|
|
|
return false;
|
|
|
|
|
// We should not have any gaps in the sequence number range.
|
|
|
|
|
size_t seqno_range =
|
|
|
|
|
*received_packed_ids_.rbegin() - *received_packed_ids_.begin() + 1;
|
|
|
|
|
return seqno_range == received_packed_ids_.size();
|
2015-08-04 16:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
bool Wait() {
|
2015-10-16 10:01:21 -07:00
|
|
|
{
|
|
|
|
|
// Can't be sure until this point that rtx_to_media_ssrcs_ etc have
|
|
|
|
|
// been initialized and are OK to read.
|
|
|
|
|
rtc::CritScope cs(&lock_);
|
|
|
|
|
started_ = true;
|
|
|
|
|
}
|
2015-12-10 13:02:50 +01:00
|
|
|
return done_.Wait(kDefaultTimeoutMs);
|
2015-10-16 10:01:21 -07:00
|
|
|
}
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2015-10-16 10:01:21 -07:00
|
|
|
rtc::CriticalSection lock_;
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event done_;
|
2016-03-01 11:52:33 -08:00
|
|
|
std::unique_ptr<RtpHeaderParser> parser_;
|
2015-10-16 10:01:21 -07:00
|
|
|
SequenceNumberUnwrapper unwrapper_;
|
|
|
|
|
std::set<int64_t> received_packed_ids_;
|
2015-08-03 04:38:41 -07:00
|
|
|
std::set<uint32_t> streams_observed_;
|
2015-10-16 10:01:21 -07:00
|
|
|
std::map<uint32_t, std::set<uint16_t>> dropped_seq_;
|
|
|
|
|
const uint32_t& first_media_ssrc_;
|
|
|
|
|
const std::map<uint32_t, uint32_t>& rtx_to_media_ssrcs_;
|
2015-08-03 04:38:41 -07:00
|
|
|
bool padding_observed_;
|
|
|
|
|
bool rtx_padding_observed_;
|
2015-10-16 10:01:21 -07:00
|
|
|
bool retransmit_observed_;
|
|
|
|
|
bool started_;
|
2015-08-03 04:38:41 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TransportSequenceNumberTester : public MultiStreamTest {
|
|
|
|
|
public:
|
2017-08-22 04:02:52 -07:00
|
|
|
explicit TransportSequenceNumberTester(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue)
|
|
|
|
|
: MultiStreamTest(task_queue),
|
|
|
|
|
first_media_ssrc_(0),
|
|
|
|
|
observer_(nullptr) {}
|
2015-08-03 04:38:41 -07:00
|
|
|
virtual ~TransportSequenceNumberTester() {}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void Wait() override {
|
2016-04-04 17:56:10 +02:00
|
|
|
RTC_DCHECK(observer_);
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(observer_->Wait());
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UpdateSendConfig(
|
|
|
|
|
size_t stream_index,
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
VideoEncoderConfig* encoder_config,
|
|
|
|
|
test::FrameGeneratorCapturer** frame_generator) override {
|
|
|
|
|
send_config->rtp.extensions.clear();
|
2016-05-26 11:24:55 -07:00
|
|
|
send_config->rtp.extensions.push_back(RtpExtension(
|
|
|
|
|
RtpExtension::kTransportSequenceNumberUri, kExtensionId));
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2017-02-27 06:52:10 -08:00
|
|
|
// Force some padding to be sent. Note that since we do send media
|
|
|
|
|
// packets we can not guarantee that a padding only packet is sent.
|
|
|
|
|
// Instead, padding will most likely be send as an RTX packet.
|
2015-08-03 04:38:41 -07:00
|
|
|
const int kPaddingBitrateBps = 50000;
|
2017-02-27 06:52:10 -08:00
|
|
|
encoder_config->max_bitrate_bps = 200000;
|
2015-08-03 04:38:41 -07:00
|
|
|
encoder_config->min_transmit_bitrate_bps =
|
2016-10-02 23:45:26 -07:00
|
|
|
encoder_config->max_bitrate_bps + kPaddingBitrateBps;
|
2015-08-03 04:38:41 -07:00
|
|
|
|
|
|
|
|
// Configure RTX for redundant payload padding.
|
|
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2015-10-16 10:01:21 -07:00
|
|
|
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[stream_index]);
|
2015-08-03 04:38:41 -07:00
|
|
|
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
2015-10-16 10:01:21 -07:00
|
|
|
rtx_to_media_ssrcs_[kSendRtxSsrcs[stream_index]] =
|
|
|
|
|
send_config->rtp.ssrcs[0];
|
|
|
|
|
|
|
|
|
|
if (stream_index == 0)
|
|
|
|
|
first_media_ssrc_ = send_config->rtp.ssrcs[0];
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UpdateReceiveConfig(
|
|
|
|
|
size_t stream_index,
|
|
|
|
|
VideoReceiveStream::Config* receive_config) override {
|
2015-10-16 10:01:21 -07:00
|
|
|
receive_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2015-08-03 04:38:41 -07:00
|
|
|
receive_config->rtp.extensions.clear();
|
2016-05-26 11:24:55 -07:00
|
|
|
receive_config->rtp.extensions.push_back(RtpExtension(
|
|
|
|
|
RtpExtension::kTransportSequenceNumberUri, kExtensionId));
|
2016-09-30 06:19:08 -07:00
|
|
|
receive_config->renderer = &fake_renderer_;
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::DirectTransport* CreateSendTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
|
|
|
|
Call* sender_call) override {
|
2017-04-10 16:57:57 -07:00
|
|
|
std::map<uint8_t, MediaType> payload_type_map =
|
|
|
|
|
MultiStreamTest::payload_type_map_;
|
|
|
|
|
RTC_DCHECK(payload_type_map.find(kSendRtxPayloadType) ==
|
|
|
|
|
payload_type_map.end());
|
|
|
|
|
payload_type_map[kSendRtxPayloadType] = MediaType::VIDEO;
|
2017-08-22 04:02:52 -07:00
|
|
|
observer_ = new RtpExtensionHeaderObserver(
|
|
|
|
|
task_queue, sender_call, first_media_ssrc_, rtx_to_media_ssrcs_,
|
|
|
|
|
payload_type_map);
|
2015-08-03 04:38:41 -07:00
|
|
|
return observer_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-09-30 06:19:08 -07:00
|
|
|
test::FakeVideoRenderer fake_renderer_;
|
2015-10-16 10:01:21 -07:00
|
|
|
uint32_t first_media_ssrc_;
|
|
|
|
|
std::map<uint32_t, uint32_t> rtx_to_media_ssrcs_;
|
2015-08-03 04:38:41 -07:00
|
|
|
RtpExtensionHeaderObserver* observer_;
|
2017-08-22 04:02:52 -07:00
|
|
|
} tester(&task_queue_);
|
2015-08-03 04:38:41 -07:00
|
|
|
|
|
|
|
|
tester.RunTest();
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2013-11-18 11:45:11 +00:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
class TransportFeedbackTester : public test::EndToEndTest {
|
|
|
|
|
public:
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
TransportFeedbackTester(bool feedback_enabled,
|
|
|
|
|
size_t num_video_streams,
|
|
|
|
|
size_t num_audio_streams)
|
2016-01-14 20:34:30 +01:00
|
|
|
: EndToEndTest(::webrtc::EndToEndTest::kDefaultTimeoutMs),
|
|
|
|
|
feedback_enabled_(feedback_enabled),
|
|
|
|
|
num_video_streams_(num_video_streams),
|
2016-07-13 09:11:28 -07:00
|
|
|
num_audio_streams_(num_audio_streams),
|
|
|
|
|
receiver_call_(nullptr) {
|
2016-01-14 20:34:30 +01:00
|
|
|
// Only one stream of each supported for now.
|
|
|
|
|
EXPECT_LE(num_video_streams, 1u);
|
|
|
|
|
EXPECT_LE(num_audio_streams, 1u);
|
|
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
protected:
|
|
|
|
|
Action OnSendRtcp(const uint8_t* data, size_t length) override {
|
|
|
|
|
EXPECT_FALSE(HasTransportFeedback(data, length));
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
Action OnReceiveRtcp(const uint8_t* data, size_t length) override {
|
|
|
|
|
if (HasTransportFeedback(data, length))
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
bool HasTransportFeedback(const uint8_t* data, size_t length) const {
|
2016-11-02 08:21:59 -07:00
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(data, length));
|
|
|
|
|
return parser.transport_feedback()->num_packets() > 0;
|
2016-01-14 20:34:30 +01:00
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
void PerformTest() override {
|
|
|
|
|
const int64_t kDisabledFeedbackTimeoutMs = 5000;
|
|
|
|
|
EXPECT_EQ(feedback_enabled_,
|
|
|
|
|
observation_complete_.Wait(feedback_enabled_
|
|
|
|
|
? test::CallTest::kDefaultTimeoutMs
|
|
|
|
|
: kDisabledFeedbackTimeoutMs));
|
|
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
|
|
|
|
|
receiver_call_ = receiver_call;
|
|
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
size_t GetNumVideoStreams() const override { return num_video_streams_; }
|
|
|
|
|
size_t GetNumAudioStreams() const override { return num_audio_streams_; }
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
(*receive_configs)[0].rtp.transport_cc = feedback_enabled_;
|
|
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
void ModifyAudioConfigs(
|
|
|
|
|
AudioSendStream::Config* send_config,
|
|
|
|
|
std::vector<AudioReceiveStream::Config>* receive_configs) override {
|
|
|
|
|
send_config->rtp.extensions.clear();
|
|
|
|
|
send_config->rtp.extensions.push_back(
|
2016-05-26 11:24:55 -07:00
|
|
|
RtpExtension(RtpExtension::kTransportSequenceNumberUri, kExtensionId));
|
2016-01-14 20:34:30 +01:00
|
|
|
(*receive_configs)[0].rtp.extensions.clear();
|
|
|
|
|
(*receive_configs)[0].rtp.extensions = send_config->rtp.extensions;
|
|
|
|
|
(*receive_configs)[0].rtp.transport_cc = feedback_enabled_;
|
|
|
|
|
}
|
2015-09-24 15:06:57 +02:00
|
|
|
|
2016-01-14 20:34:30 +01:00
|
|
|
private:
|
|
|
|
|
static const int kExtensionId = 5;
|
|
|
|
|
const bool feedback_enabled_;
|
|
|
|
|
const size_t num_video_streams_;
|
|
|
|
|
const size_t num_audio_streams_;
|
|
|
|
|
Call* receiver_call_;
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VideoReceivesTransportFeedback) {
|
2016-01-14 20:34:30 +01:00
|
|
|
TransportFeedbackTester test(true, 1, 0);
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VideoTransportFeedbackNotConfigured) {
|
2016-01-14 20:34:30 +01:00
|
|
|
TransportFeedbackTester test(false, 1, 0);
|
|
|
|
|
RunBaseTest(&test);
|
2015-09-24 15:06:57 +02:00
|
|
|
}
|
2015-11-20 18:05:48 -08:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, AudioReceivesTransportFeedback) {
|
2016-01-14 20:34:30 +01:00
|
|
|
TransportFeedbackTester test(true, 0, 1);
|
|
|
|
|
RunBaseTest(&test);
|
2015-11-20 18:05:48 -08:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, AudioTransportFeedbackNotConfigured) {
|
2016-01-14 20:34:30 +01:00
|
|
|
TransportFeedbackTester test(false, 0, 1);
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, AudioVideoReceivesTransportFeedback) {
|
2016-01-14 20:34:30 +01:00
|
|
|
TransportFeedbackTester test(true, 1, 1);
|
|
|
|
|
RunBaseTest(&test);
|
2015-11-20 18:05:48 -08:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, StopsSendingMediaWithoutFeedback) {
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
test::ScopedFieldTrials override_field_trials(
|
2017-08-17 02:13:54 -07:00
|
|
|
"WebRTC-CwndExperiment/Enabled-250/");
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
|
|
|
|
|
class TransportFeedbackTester : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
TransportFeedbackTester(size_t num_video_streams, size_t num_audio_streams)
|
|
|
|
|
: EndToEndTest(::webrtc::EndToEndTest::kDefaultTimeoutMs),
|
|
|
|
|
num_video_streams_(num_video_streams),
|
|
|
|
|
num_audio_streams_(num_audio_streams),
|
|
|
|
|
media_sent_(0),
|
|
|
|
|
padding_sent_(0) {
|
|
|
|
|
// Only one stream of each supported for now.
|
|
|
|
|
EXPECT_LE(num_video_streams, 1u);
|
|
|
|
|
EXPECT_LE(num_audio_streams, 1u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
|
|
|
const bool only_padding =
|
|
|
|
|
header.headerLength + header.paddingLength == length;
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
if (only_padding) {
|
|
|
|
|
++padding_sent_;
|
|
|
|
|
} else {
|
|
|
|
|
++media_sent_;
|
|
|
|
|
EXPECT_LT(media_sent_, 40) << "Media sent without feedback.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Action OnReceiveRtcp(const uint8_t* data, size_t length) override {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
if (media_sent_ > 20 && HasTransportFeedback(data, length)) {
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool HasTransportFeedback(const uint8_t* data, size_t length) const {
|
|
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(data, length));
|
|
|
|
|
return parser.transport_feedback()->num_packets() > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Call::Config GetSenderCallConfig() override {
|
|
|
|
|
Call::Config config = EndToEndTest::GetSenderCallConfig();
|
|
|
|
|
config.bitrate_config.max_bitrate_bps = 300000;
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
const int64_t kDisabledFeedbackTimeoutMs = 10000;
|
|
|
|
|
observation_complete_.Wait(kDisabledFeedbackTimeoutMs);
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
EXPECT_GT(padding_sent_, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t GetNumVideoStreams() const override { return num_video_streams_; }
|
|
|
|
|
size_t GetNumAudioStreams() const override { return num_audio_streams_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const size_t num_video_streams_;
|
|
|
|
|
const size_t num_audio_streams_;
|
|
|
|
|
rtc::CriticalSection crit_;
|
2017-09-09 04:17:22 -07:00
|
|
|
int media_sent_ RTC_GUARDED_BY(crit_);
|
|
|
|
|
int padding_sent_ RTC_GUARDED_BY(crit_);
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
} test(1, 0);
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ObserversEncodedFrames) {
|
2013-11-26 11:41:59 +00:00
|
|
|
class EncodedFrameTestObserver : public EncodedFrameObserver {
|
|
|
|
|
public:
|
2014-01-24 09:30:53 +00:00
|
|
|
EncodedFrameTestObserver()
|
2015-12-10 13:02:50 +01:00
|
|
|
: length_(0), frame_type_(kEmptyFrame), called_(false, false) {}
|
2013-11-26 11:41:59 +00:00
|
|
|
virtual ~EncodedFrameTestObserver() {}
|
|
|
|
|
|
|
|
|
|
virtual void EncodedFrameCallback(const EncodedFrame& encoded_frame) {
|
|
|
|
|
frame_type_ = encoded_frame.frame_type_;
|
|
|
|
|
length_ = encoded_frame.length_;
|
|
|
|
|
buffer_.reset(new uint8_t[length_]);
|
|
|
|
|
memcpy(buffer_.get(), encoded_frame.data_, length_);
|
2015-12-10 13:02:50 +01:00
|
|
|
called_.Set();
|
2013-11-26 11:41:59 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
bool Wait() { return called_.Wait(kDefaultTimeoutMs); }
|
2013-11-26 11:41:59 +00:00
|
|
|
|
|
|
|
|
void ExpectEqualFrames(const EncodedFrameTestObserver& observer) {
|
|
|
|
|
ASSERT_EQ(length_, observer.length_)
|
|
|
|
|
<< "Observed frames are of different lengths.";
|
|
|
|
|
EXPECT_EQ(frame_type_, observer.frame_type_)
|
|
|
|
|
<< "Observed frames have different frame types.";
|
|
|
|
|
EXPECT_EQ(0, memcmp(buffer_.get(), observer.buffer_.get(), length_))
|
|
|
|
|
<< "Observed encoded frames have different content.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-03-01 11:52:33 -08:00
|
|
|
std::unique_ptr<uint8_t[]> buffer_;
|
2013-11-26 11:41:59 +00:00
|
|
|
size_t length_;
|
|
|
|
|
FrameType frame_type_;
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event called_;
|
2013-11-26 11:41:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EncodedFrameTestObserver post_encode_observer;
|
|
|
|
|
EncodedFrameTestObserver pre_decode_observer;
|
2017-08-22 04:02:52 -07:00
|
|
|
test::FrameForwarder forwarder;
|
|
|
|
|
std::unique_ptr<test::FrameGenerator> frame_generator;
|
2013-11-26 11:41:59 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::DirectTransport> sender_transport;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> receiver_transport;
|
2013-11-26 11:41:59 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([&]() {
|
|
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
2013-11-26 11:41:59 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
sender_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, sender_call_.get(), payload_type_map_);
|
|
|
|
|
receiver_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, receiver_call_.get(), payload_type_map_);
|
|
|
|
|
sender_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
receiver_transport->SetReceiver(sender_call_->Receiver());
|
2013-11-26 11:41:59 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateSendConfig(1, 0, 0, sender_transport.get());
|
|
|
|
|
CreateMatchingReceiveConfigs(receiver_transport.get());
|
|
|
|
|
video_send_config_.post_encode_callback = &post_encode_observer;
|
|
|
|
|
video_receive_configs_[0].pre_decode_callback = &pre_decode_observer;
|
2013-11-26 11:41:59 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateVideoStreams();
|
|
|
|
|
Start();
|
|
|
|
|
|
|
|
|
|
frame_generator = test::FrameGenerator::CreateSquareGenerator(
|
|
|
|
|
kDefaultWidth, kDefaultHeight);
|
|
|
|
|
video_send_stream_->SetSource(
|
|
|
|
|
&forwarder, VideoSendStream::DegradationPreference::kMaintainFramerate);
|
|
|
|
|
forwarder.IncomingCapturedFrame(*frame_generator->NextFrame());
|
|
|
|
|
});
|
2013-11-26 11:41:59 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(post_encode_observer.Wait())
|
2013-11-26 11:41:59 +00:00
|
|
|
<< "Timed out while waiting for send-side encoded-frame callback.";
|
|
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(pre_decode_observer.Wait())
|
2013-11-26 11:41:59 +00:00
|
|
|
<< "Timed out while waiting for pre-decode encoded-frame callback.";
|
|
|
|
|
|
|
|
|
|
post_encode_observer.ExpectEqualFrames(pre_decode_observer);
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &sender_transport, &receiver_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
sender_transport.reset();
|
|
|
|
|
receiver_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2013-11-26 11:41:59 +00:00
|
|
|
}
|
2013-12-13 16:36:28 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReceiveStreamSendsRemb) {
|
2014-06-27 08:47:52 +00:00
|
|
|
class RembObserver : public test::EndToEndTest {
|
2013-12-13 16:36:28 +00:00
|
|
|
public:
|
2014-06-27 08:47:52 +00:00
|
|
|
RembObserver() : EndToEndTest(kDefaultTimeoutMs) {}
|
2013-12-13 16:36:28 +00:00
|
|
|
|
2017-02-06 06:29:38 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
send_config->rtp.extensions.clear();
|
|
|
|
|
send_config->rtp.extensions.push_back(RtpExtension(
|
|
|
|
|
RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
|
|
|
|
|
(*receive_configs)[0].rtp.remb = true;
|
|
|
|
|
(*receive_configs)[0].rtp.transport_cc = false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2016-11-02 08:21:59 -07:00
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
|
|
|
|
|
|
if (parser.remb()->num_packets() > 0) {
|
|
|
|
|
EXPECT_EQ(kReceiverLocalVideoSsrc, parser.remb()->sender_ssrc());
|
|
|
|
|
EXPECT_LT(0U, parser.remb()->bitrate_bps());
|
|
|
|
|
EXPECT_EQ(1U, parser.remb()->ssrcs().size());
|
|
|
|
|
EXPECT_EQ(kVideoSendSsrcs[0], parser.remb()->ssrcs()[0]);
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2016-11-02 08:21:59 -07:00
|
|
|
}
|
|
|
|
|
|
2013-12-13 16:36:28 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait()) << "Timed out while waiting for a "
|
|
|
|
|
"receiver RTCP REMB packet to be "
|
|
|
|
|
"sent.";
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
|
|
|
|
} test;
|
2013-12-13 16:36:28 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2013-12-13 16:36:28 +00:00
|
|
|
}
|
2014-01-20 08:34:49 +00:00
|
|
|
|
2017-02-06 06:29:38 -08:00
|
|
|
class BandwidthStatsTest : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
explicit BandwidthStatsTest(bool send_side_bwe)
|
|
|
|
|
: EndToEndTest(test::CallTest::kDefaultTimeoutMs),
|
|
|
|
|
sender_call_(nullptr),
|
|
|
|
|
receiver_call_(nullptr),
|
|
|
|
|
has_seen_pacer_delay_(false),
|
|
|
|
|
send_side_bwe_(send_side_bwe) {}
|
2014-11-05 14:05:29 +00:00
|
|
|
|
2017-02-06 06:29:38 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
if (!send_side_bwe_) {
|
|
|
|
|
send_config->rtp.extensions.clear();
|
|
|
|
|
send_config->rtp.extensions.push_back(RtpExtension(
|
|
|
|
|
RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId));
|
|
|
|
|
(*receive_configs)[0].rtp.remb = true;
|
|
|
|
|
(*receive_configs)[0].rtp.transport_cc = false;
|
2014-11-05 14:05:29 +00:00
|
|
|
}
|
2017-02-06 06:29:38 -08:00
|
|
|
}
|
2014-11-05 14:05:29 +00:00
|
|
|
|
2017-02-06 06:29:38 -08:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
Call::Stats sender_stats = sender_call_->GetStats();
|
|
|
|
|
Call::Stats receiver_stats = receiver_call_->GetStats();
|
|
|
|
|
if (!has_seen_pacer_delay_)
|
|
|
|
|
has_seen_pacer_delay_ = sender_stats.pacer_delay_ms > 0;
|
|
|
|
|
if (sender_stats.send_bandwidth_bps > 0 && has_seen_pacer_delay_) {
|
|
|
|
|
if (send_side_bwe_ || receiver_stats.recv_bandwidth_bps > 0)
|
|
|
|
|
observation_complete_.Set();
|
2014-11-05 14:05:29 +00:00
|
|
|
}
|
2017-02-06 06:29:38 -08:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2014-11-05 14:05:29 +00:00
|
|
|
|
2017-02-06 06:29:38 -08:00
|
|
|
void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
|
|
|
|
|
sender_call_ = sender_call;
|
|
|
|
|
receiver_call_ = receiver_call;
|
|
|
|
|
}
|
2014-11-05 14:05:29 +00:00
|
|
|
|
2017-02-06 06:29:38 -08:00
|
|
|
void PerformTest() override {
|
|
|
|
|
EXPECT_TRUE(Wait()) << "Timed out while waiting for "
|
|
|
|
|
"non-zero bandwidth stats.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Call* sender_call_;
|
|
|
|
|
Call* receiver_call_;
|
|
|
|
|
bool has_seen_pacer_delay_;
|
|
|
|
|
const bool send_side_bwe_;
|
|
|
|
|
};
|
2014-11-05 14:05:29 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifySendSideBweStats) {
|
2017-02-06 06:29:38 -08:00
|
|
|
BandwidthStatsTest test(true);
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-11-05 14:05:29 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyRecvSideBweStats) {
|
2017-02-06 06:29:38 -08:00
|
|
|
BandwidthStatsTest test(false);
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
2016-01-20 07:13:58 -08:00
|
|
|
|
|
|
|
|
// Verifies that it's possible to limit the send BWE by sending a REMB.
|
|
|
|
|
// This is verified by allowing the send BWE to ramp-up to >1000 kbps,
|
|
|
|
|
// then have the test generate a REMB of 500 kbps and verify that the send BWE
|
|
|
|
|
// is reduced to exactly 500 kbps. Then a REMB of 1000 kbps is generated and the
|
|
|
|
|
// test verifies that the send BWE ramps back up to exactly 1000 kbps.
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RembWithSendSideBwe) {
|
2016-01-20 07:13:58 -08:00
|
|
|
class BweObserver : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
BweObserver()
|
|
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
|
|
|
|
sender_call_(nullptr),
|
|
|
|
|
clock_(Clock::GetRealTimeClock()),
|
|
|
|
|
sender_ssrc_(0),
|
|
|
|
|
remb_bitrate_bps_(1000000),
|
|
|
|
|
receive_transport_(nullptr),
|
2017-02-21 14:22:59 +01:00
|
|
|
stop_event_(false, false),
|
2016-01-20 07:13:58 -08:00
|
|
|
poller_thread_(&BitrateStatsPollingThread,
|
|
|
|
|
this,
|
|
|
|
|
"BitrateStatsPollingThread"),
|
2016-07-29 12:59:36 +02:00
|
|
|
state_(kWaitForFirstRampUp),
|
|
|
|
|
retransmission_rate_limiter_(clock_, 1000) {}
|
2016-01-20 07:13:58 -08:00
|
|
|
|
|
|
|
|
~BweObserver() {}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::PacketTransport* CreateReceiveTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue) override {
|
2016-01-20 07:13:58 -08:00
|
|
|
receive_transport_ = new test::PacketTransport(
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue, nullptr, this, test::PacketTransport::kReceiver,
|
|
|
|
|
payload_type_map_, FakeNetworkPipe::Config());
|
2016-01-20 07:13:58 -08:00
|
|
|
return receive_transport_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Call::Config GetSenderCallConfig() override {
|
2017-04-10 03:54:05 -07:00
|
|
|
Call::Config config(event_log_.get());
|
2016-01-20 07:13:58 -08:00
|
|
|
// Set a high start bitrate to reduce the test completion time.
|
|
|
|
|
config.bitrate_config.start_bitrate_bps = remb_bitrate_bps_;
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
ASSERT_EQ(1u, send_config->rtp.ssrcs.size());
|
|
|
|
|
sender_ssrc_ = send_config->rtp.ssrcs[0];
|
|
|
|
|
|
2016-10-02 23:45:26 -07:00
|
|
|
encoder_config->max_bitrate_bps = 2000000;
|
2016-01-20 07:13:58 -08:00
|
|
|
|
|
|
|
|
ASSERT_EQ(1u, receive_configs->size());
|
|
|
|
|
RtpRtcp::Configuration config;
|
|
|
|
|
config.receiver_only = true;
|
|
|
|
|
config.clock = clock_;
|
|
|
|
|
config.outgoing_transport = receive_transport_;
|
2016-07-29 12:59:36 +02:00
|
|
|
config.retransmission_rate_limiter = &retransmission_rate_limiter_;
|
2016-01-20 07:13:58 -08:00
|
|
|
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
|
|
|
|
|
rtp_rtcp_->SetRemoteSSRC((*receive_configs)[0].rtp.remote_ssrc);
|
|
|
|
|
rtp_rtcp_->SetSSRC((*receive_configs)[0].rtp.local_ssrc);
|
|
|
|
|
rtp_rtcp_->SetRTCPStatus(RtcpMode::kReducedSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
|
|
|
|
|
sender_call_ = sender_call;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-22 11:22:05 -08:00
|
|
|
static void BitrateStatsPollingThread(void* obj) {
|
|
|
|
|
static_cast<BweObserver*>(obj)->PollStats();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PollStats() {
|
|
|
|
|
do {
|
|
|
|
|
if (sender_call_) {
|
|
|
|
|
Call::Stats stats = sender_call_->GetStats();
|
|
|
|
|
switch (state_) {
|
|
|
|
|
case kWaitForFirstRampUp:
|
|
|
|
|
if (stats.send_bandwidth_bps >= remb_bitrate_bps_) {
|
|
|
|
|
state_ = kWaitForRemb;
|
|
|
|
|
remb_bitrate_bps_ /= 2;
|
2017-10-10 17:46:26 +02:00
|
|
|
rtp_rtcp_->SetRemb(
|
2017-02-22 11:22:05 -08:00
|
|
|
remb_bitrate_bps_,
|
|
|
|
|
std::vector<uint32_t>(&sender_ssrc_, &sender_ssrc_ + 1));
|
|
|
|
|
rtp_rtcp_->SendRTCP(kRtcpRr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kWaitForRemb:
|
|
|
|
|
if (stats.send_bandwidth_bps == remb_bitrate_bps_) {
|
|
|
|
|
state_ = kWaitForSecondRampUp;
|
|
|
|
|
remb_bitrate_bps_ *= 2;
|
2017-10-10 17:46:26 +02:00
|
|
|
rtp_rtcp_->SetRemb(
|
2017-02-22 11:22:05 -08:00
|
|
|
remb_bitrate_bps_,
|
|
|
|
|
std::vector<uint32_t>(&sender_ssrc_, &sender_ssrc_ + 1));
|
|
|
|
|
rtp_rtcp_->SendRTCP(kRtcpRr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kWaitForSecondRampUp:
|
|
|
|
|
if (stats.send_bandwidth_bps == remb_bitrate_bps_) {
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-01-20 07:13:58 -08:00
|
|
|
}
|
2017-02-22 11:22:05 -08:00
|
|
|
} while (!stop_event_.Wait(1000));
|
2016-01-20 07:13:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
poller_thread_.Start();
|
|
|
|
|
EXPECT_TRUE(Wait())
|
|
|
|
|
<< "Timed out while waiting for bitrate to change according to REMB.";
|
2017-02-21 14:22:59 +01:00
|
|
|
stop_event_.Set();
|
2016-01-20 07:13:58 -08:00
|
|
|
poller_thread_.Stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
enum TestState { kWaitForFirstRampUp, kWaitForRemb, kWaitForSecondRampUp };
|
|
|
|
|
|
|
|
|
|
Call* sender_call_;
|
|
|
|
|
Clock* const clock_;
|
|
|
|
|
uint32_t sender_ssrc_;
|
|
|
|
|
int remb_bitrate_bps_;
|
2016-03-01 11:52:33 -08:00
|
|
|
std::unique_ptr<RtpRtcp> rtp_rtcp_;
|
2016-01-20 07:13:58 -08:00
|
|
|
test::PacketTransport* receive_transport_;
|
2017-02-21 14:22:59 +01:00
|
|
|
rtc::Event stop_event_;
|
2016-01-20 07:13:58 -08:00
|
|
|
rtc::PlatformThread poller_thread_;
|
|
|
|
|
TestState state_;
|
2016-07-29 12:59:36 +02:00
|
|
|
RateLimiter retransmission_rate_limiter_;
|
2016-01-20 07:13:58 -08:00
|
|
|
} test;
|
|
|
|
|
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, StopSendingKeyframeRequestsForInactiveStream) {
|
2017-05-18 08:08:53 -07:00
|
|
|
class KeyframeRequestObserver : public test::EndToEndTest {
|
|
|
|
|
public:
|
2017-08-22 04:02:52 -07:00
|
|
|
explicit KeyframeRequestObserver(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue)
|
|
|
|
|
: clock_(Clock::GetRealTimeClock()), task_queue_(task_queue) {}
|
2017-05-18 08:08:53 -07:00
|
|
|
|
|
|
|
|
void OnVideoStreamsCreated(
|
|
|
|
|
VideoSendStream* send_stream,
|
|
|
|
|
const std::vector<VideoReceiveStream*>& receive_streams) override {
|
|
|
|
|
RTC_DCHECK_EQ(1, receive_streams.size());
|
|
|
|
|
send_stream_ = send_stream;
|
|
|
|
|
receive_stream_ = receive_streams[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
bool frame_decoded = false;
|
|
|
|
|
int64_t start_time = clock_->TimeInMilliseconds();
|
|
|
|
|
while (clock_->TimeInMilliseconds() - start_time <= 5000) {
|
|
|
|
|
if (receive_stream_->GetStats().frames_decoded > 0) {
|
|
|
|
|
frame_decoded = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
SleepMs(100);
|
|
|
|
|
}
|
|
|
|
|
ASSERT_TRUE(frame_decoded);
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_->SendTask([this]() { send_stream_->Stop(); });
|
2017-05-18 08:08:53 -07:00
|
|
|
SleepMs(10000);
|
|
|
|
|
ASSERT_EQ(
|
|
|
|
|
1U, receive_stream_->GetStats().rtcp_packet_type_counts.pli_packets);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Clock* clock_;
|
|
|
|
|
VideoSendStream* send_stream_;
|
|
|
|
|
VideoReceiveStream* receive_stream_;
|
2017-08-22 04:02:52 -07:00
|
|
|
test::SingleThreadedTaskQueueForTesting* const task_queue_;
|
|
|
|
|
} test(&task_queue_);
|
2017-05-18 08:08:53 -07:00
|
|
|
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 03:24:27 -07:00
|
|
|
class ProbingTest : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
explicit ProbingTest(int start_bitrate_bps)
|
|
|
|
|
: clock_(Clock::GetRealTimeClock()),
|
|
|
|
|
start_bitrate_bps_(start_bitrate_bps),
|
|
|
|
|
state_(0),
|
|
|
|
|
sender_call_(nullptr) {}
|
|
|
|
|
|
|
|
|
|
~ProbingTest() {}
|
|
|
|
|
|
|
|
|
|
Call::Config GetSenderCallConfig() override {
|
2017-04-10 03:54:05 -07:00
|
|
|
Call::Config config(event_log_.get());
|
2017-03-21 03:24:27 -07:00
|
|
|
config.bitrate_config.start_bitrate_bps = start_bitrate_bps_;
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
|
|
|
|
|
sender_call_ = sender_call;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
Clock* const clock_;
|
|
|
|
|
const int start_bitrate_bps_;
|
|
|
|
|
int state_;
|
|
|
|
|
Call* sender_call_;
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, MAYBE_InitialProbing) {
|
2017-03-21 03:24:27 -07:00
|
|
|
class InitialProbingTest : public ProbingTest {
|
|
|
|
|
public:
|
2017-03-30 05:06:22 -07:00
|
|
|
explicit InitialProbingTest(bool* success)
|
2017-08-10 10:42:53 -07:00
|
|
|
: ProbingTest(300000), success_(success) {
|
|
|
|
|
*success_ = false;
|
|
|
|
|
}
|
2017-03-21 03:24:27 -07:00
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
int64_t start_time_ms = clock_->TimeInMilliseconds();
|
|
|
|
|
do {
|
2017-03-30 05:06:22 -07:00
|
|
|
if (clock_->TimeInMilliseconds() - start_time_ms > kTimeoutMs)
|
2017-03-21 03:24:27 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
Call::Stats stats = sender_call_->GetStats();
|
|
|
|
|
// Initial probing is done with a x3 and x6 multiplier of the start
|
|
|
|
|
// bitrate, so a x4 multiplier is a high enough threshold.
|
2017-03-30 05:06:22 -07:00
|
|
|
if (stats.send_bandwidth_bps > 4 * 300000) {
|
|
|
|
|
*success_ = true;
|
2017-03-21 03:24:27 -07:00
|
|
|
break;
|
2017-03-30 05:06:22 -07:00
|
|
|
}
|
2017-03-21 03:24:27 -07:00
|
|
|
} while (!observation_complete_.Wait(20));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const int kTimeoutMs = 1000;
|
2017-03-30 05:06:22 -07:00
|
|
|
bool* const success_;
|
|
|
|
|
};
|
2017-03-21 03:24:27 -07:00
|
|
|
|
2017-08-10 10:42:53 -07:00
|
|
|
bool success = false;
|
2017-03-30 05:06:22 -07:00
|
|
|
const int kMaxAttempts = 3;
|
|
|
|
|
for (int i = 0; i < kMaxAttempts; ++i) {
|
|
|
|
|
InitialProbingTest test(&success);
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
if (success)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-10 10:42:53 -07:00
|
|
|
EXPECT_TRUE(success) << "Failed to perform mid initial probing ("
|
|
|
|
|
<< kMaxAttempts << " attempts).";
|
2017-03-21 03:24:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-03-30 04:24:08 -07:00
|
|
|
// Fails on Linux MSan: bugs.webrtc.org/7428
|
|
|
|
|
#if defined(MEMORY_SANITIZER)
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DISABLED_TriggerMidCallProbing) {
|
2017-06-22 01:47:20 -07:00
|
|
|
// Fails on iOS bots: bugs.webrtc.org/7851
|
|
|
|
|
#elif defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DISABLED_TriggerMidCallProbing) {
|
2017-03-30 04:24:08 -07:00
|
|
|
#else
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TriggerMidCallProbing) {
|
2017-03-30 04:24:08 -07:00
|
|
|
#endif
|
|
|
|
|
|
2017-03-21 03:24:27 -07:00
|
|
|
class TriggerMidCallProbingTest : public ProbingTest {
|
|
|
|
|
public:
|
2017-08-22 04:02:52 -07:00
|
|
|
TriggerMidCallProbingTest(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
|
|
|
|
bool* success)
|
|
|
|
|
: ProbingTest(300000), success_(success), task_queue_(task_queue) {}
|
2017-03-21 03:24:27 -07:00
|
|
|
|
|
|
|
|
void PerformTest() override {
|
2017-03-30 05:06:22 -07:00
|
|
|
*success_ = false;
|
2017-03-21 03:24:27 -07:00
|
|
|
int64_t start_time_ms = clock_->TimeInMilliseconds();
|
|
|
|
|
do {
|
2017-03-30 05:06:22 -07:00
|
|
|
if (clock_->TimeInMilliseconds() - start_time_ms > kTimeoutMs)
|
2017-03-21 03:24:27 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
Call::Stats stats = sender_call_->GetStats();
|
|
|
|
|
|
|
|
|
|
switch (state_) {
|
|
|
|
|
case 0:
|
|
|
|
|
if (stats.send_bandwidth_bps > 5 * 300000) {
|
|
|
|
|
Call::Config::BitrateConfig bitrate_config;
|
|
|
|
|
bitrate_config.max_bitrate_bps = 100000;
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_->SendTask([this, &bitrate_config]() {
|
|
|
|
|
sender_call_->SetBitrateConfig(bitrate_config);
|
|
|
|
|
});
|
2017-03-21 03:24:27 -07:00
|
|
|
++state_;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
if (stats.send_bandwidth_bps < 110000) {
|
|
|
|
|
Call::Config::BitrateConfig bitrate_config;
|
|
|
|
|
bitrate_config.max_bitrate_bps = 2500000;
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_->SendTask([this, &bitrate_config]() {
|
|
|
|
|
sender_call_->SetBitrateConfig(bitrate_config);
|
|
|
|
|
});
|
2017-03-21 03:24:27 -07:00
|
|
|
++state_;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
// During high cpu load the pacer will not be able to pace packets
|
|
|
|
|
// at the correct speed, but if we go from 110 to 1250 kbps
|
|
|
|
|
// in 5 seconds then it is due to probing.
|
2017-03-30 05:06:22 -07:00
|
|
|
if (stats.send_bandwidth_bps > 1250000) {
|
|
|
|
|
*success_ = true;
|
2017-03-21 03:24:27 -07:00
|
|
|
observation_complete_.Set();
|
2017-03-30 05:06:22 -07:00
|
|
|
}
|
2017-03-21 03:24:27 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while (!observation_complete_.Wait(20));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const int kTimeoutMs = 5000;
|
2017-03-30 05:06:22 -07:00
|
|
|
bool* const success_;
|
2017-08-22 04:02:52 -07:00
|
|
|
test::SingleThreadedTaskQueueForTesting* const task_queue_;
|
2017-03-30 05:06:22 -07:00
|
|
|
};
|
2017-03-21 03:24:27 -07:00
|
|
|
|
2017-08-10 10:42:53 -07:00
|
|
|
bool success = false;
|
2017-03-30 05:06:22 -07:00
|
|
|
const int kMaxAttempts = 3;
|
|
|
|
|
for (int i = 0; i < kMaxAttempts; ++i) {
|
2017-08-22 04:02:52 -07:00
|
|
|
TriggerMidCallProbingTest test(&task_queue_, &success);
|
2017-03-30 05:06:22 -07:00
|
|
|
RunBaseTest(&test);
|
|
|
|
|
if (success)
|
|
|
|
|
return;
|
|
|
|
|
}
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
EXPECT_TRUE(success) << "Failed to perform mid call probing (" << kMaxAttempts
|
|
|
|
|
<< " attempts).";
|
2017-03-21 03:24:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyNackStats) {
|
2015-04-15 18:00:40 +02:00
|
|
|
static const int kPacketNumberToDrop = 200;
|
|
|
|
|
class NackObserver : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
NackObserver()
|
|
|
|
|
: EndToEndTest(kLongTimeoutMs),
|
|
|
|
|
sent_rtp_packets_(0),
|
|
|
|
|
dropped_rtp_packet_(0),
|
|
|
|
|
dropped_rtp_packet_requested_(false),
|
|
|
|
|
send_stream_(nullptr),
|
|
|
|
|
start_runtime_ms_(-1) {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2015-11-01 14:56:10 -08:00
|
|
|
rtc::CritScope lock(&crit_);
|
2015-04-15 18:00:40 +02:00
|
|
|
if (++sent_rtp_packets_ == kPacketNumberToDrop) {
|
2016-03-01 11:52:33 -08:00
|
|
|
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
|
2015-04-15 18:00:40 +02:00
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser->Parse(packet, length, &header));
|
|
|
|
|
dropped_rtp_packet_ = header.sequenceNumber;
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
|
|
|
|
VerifyStats();
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2015-11-01 14:56:10 -08:00
|
|
|
rtc::CritScope lock(&crit_);
|
2015-04-15 18:00:40 +02:00
|
|
|
test::RtcpPacketParser rtcp_parser;
|
|
|
|
|
rtcp_parser.Parse(packet, length);
|
2016-09-02 18:29:10 +02:00
|
|
|
const std::vector<uint16_t>& nacks = rtcp_parser.nack()->packet_ids();
|
2015-04-15 18:00:40 +02:00
|
|
|
if (!nacks.empty() && std::find(
|
|
|
|
|
nacks.begin(), nacks.end(), dropped_rtp_packet_) != nacks.end()) {
|
|
|
|
|
dropped_rtp_packet_requested_ = true;
|
|
|
|
|
}
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-09 04:17:22 -07:00
|
|
|
void VerifyStats() RTC_EXCLUSIVE_LOCKS_REQUIRED(&crit_) {
|
2015-04-15 18:00:40 +02:00
|
|
|
if (!dropped_rtp_packet_requested_)
|
|
|
|
|
return;
|
|
|
|
|
int send_stream_nack_packets = 0;
|
|
|
|
|
int receive_stream_nack_packets = 0;
|
|
|
|
|
VideoSendStream::Stats stats = send_stream_->GetStats();
|
|
|
|
|
for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
|
|
|
|
|
stats.substreams.begin(); it != stats.substreams.end(); ++it) {
|
|
|
|
|
const VideoSendStream::StreamStats& stream_stats = it->second;
|
|
|
|
|
send_stream_nack_packets +=
|
|
|
|
|
stream_stats.rtcp_packet_type_counts.nack_packets;
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < receive_streams_.size(); ++i) {
|
|
|
|
|
VideoReceiveStream::Stats stats = receive_streams_[i]->GetStats();
|
|
|
|
|
receive_stream_nack_packets +=
|
|
|
|
|
stats.rtcp_packet_type_counts.nack_packets;
|
|
|
|
|
}
|
2016-01-07 17:43:18 +01:00
|
|
|
if (send_stream_nack_packets >= 1 && receive_stream_nack_packets >= 1) {
|
2015-04-15 18:00:40 +02:00
|
|
|
// NACK packet sent on receive stream and received on sent stream.
|
|
|
|
|
if (MinMetricRunTimePassed())
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2015-04-15 18:00:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MinMetricRunTimePassed() {
|
|
|
|
|
int64_t now = Clock::GetRealTimeClock()->TimeInMilliseconds();
|
|
|
|
|
if (start_runtime_ms_ == -1) {
|
|
|
|
|
start_runtime_ms_ = now;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
int64_t elapsed_sec = (now - start_runtime_ms_) / 1000;
|
|
|
|
|
return elapsed_sec > metrics::kMinRunTimeInSeconds;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2015-04-15 18:00:40 +02:00
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
2016-09-30 06:19:08 -07:00
|
|
|
(*receive_configs)[0].renderer = &fake_renderer_;
|
2015-04-15 18:00:40 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void OnVideoStreamsCreated(
|
2015-04-15 18:00:40 +02:00
|
|
|
VideoSendStream* send_stream,
|
|
|
|
|
const std::vector<VideoReceiveStream*>& receive_streams) override {
|
|
|
|
|
send_stream_ = send_stream;
|
|
|
|
|
receive_streams_ = receive_streams;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait()) << "Timed out waiting for packet to be NACKed.";
|
2015-04-15 18:00:40 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-30 06:19:08 -07:00
|
|
|
test::FakeVideoRenderer fake_renderer_;
|
2015-11-01 14:56:10 -08:00
|
|
|
rtc::CriticalSection crit_;
|
2015-04-15 18:00:40 +02:00
|
|
|
uint64_t sent_rtp_packets_;
|
2017-09-09 04:17:22 -07:00
|
|
|
uint16_t dropped_rtp_packet_ RTC_GUARDED_BY(&crit_);
|
|
|
|
|
bool dropped_rtp_packet_requested_ RTC_GUARDED_BY(&crit_);
|
2015-04-15 18:00:40 +02:00
|
|
|
std::vector<VideoReceiveStream*> receive_streams_;
|
|
|
|
|
VideoSendStream* send_stream_;
|
|
|
|
|
int64_t start_runtime_ms_;
|
|
|
|
|
} test;
|
|
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
metrics::Reset();
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2015-04-15 18:00:40 +02:00
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(
|
|
|
|
|
1, metrics::NumSamples("WebRTC.Video.UniqueNackRequestsSentInPercent"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(
|
|
|
|
|
"WebRTC.Video.UniqueNackRequestsReceivedInPercent"));
|
|
|
|
|
EXPECT_GT(metrics::MinSample("WebRTC.Video.NackPacketsSentPerMinute"), 0);
|
2015-04-15 18:00:40 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-03 08:10:08 -08:00
|
|
|
void EndToEndTest::VerifyHistogramStats(bool use_rtx,
|
2017-09-26 02:49:21 -07:00
|
|
|
bool use_fec,
|
2015-12-03 08:10:08 -08:00
|
|
|
bool screenshare) {
|
Reland of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #1 id:1 of https://codereview.webrtc.org/2084873002/ )
Reason for revert:
Reverting the revert. This change is not related to the failure on the Windows FYI bots. The cause of the failure has been reverted in Chromium:
https://codereview.chromium.org/2081653004/
Original issue's description:
> Revert of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #5 id:340001 of https://codereview.webrtc.org/2078873002/ )
>
> Reason for revert:
> Breaks chromium.webrtc.fyi
>
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win7%20Tester/builds/4719
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win10%20Tester/builds/3120
>
> Original issue's description:
> > Reland of IncomingVideoStream refactoring.
> > This reland does not contain the non-smoothing part of the original implementation. Instead, when smoothing is turned off, frame callbacks run on the decoder thread, as they did before. This code path is used in Chrome. As far as Chrome goes, the difference now is that there won't be an instance of IncomingVideoStream in between the decoder and the callback (i.e. fewer locks). Other than that, no change for Chrome.
> >
> > Original issue's description (with non-smoothing references removed):
> >
> > Split IncomingVideoStream into two implementations, with smoothing and without.
> >
> > * Added TODOs and documentation for VideoReceiveStream::OnFrame, where we today grab 6 locks.
> >
> > * Removed the Start/Stop methods from the IncomingVideoStream implementations. Now, when an instance is created, it should be considered to be "running" and when it is deleted, it's "not running". This saves on resources and also reduces the amount of locking required and I could remove one critical section altogether.
> >
> > * Changed the VideoStreamDecoder class to not depend on IncomingVideoStream but rather use the generic rtc::VideoSinkInterface<VideoFrame> interface. This means that any implementation of that interface can be used and the decoder can be made to just use the 'renderer' from the config. Once we do that, we can decouple the IncomingVideoStream implementations from the decoder and VideoReceiveStream implementations and leave it up to the application for how to do smoothing. The app can choose to use the Incoming* classes or roll its own (which may be preferable since applications often have their own scheduling mechanisms).
> >
> > * The lifetime of the VideoStreamDecoder instance is now bound to Start/Stop in VideoReceiveStream and not all of the lifetime of VideoReceiveStream.
> >
> > * Fixed VideoStreamDecoder to unregister callbacks in the dtor that were registered in the ctor. (this was open to a use-after-free regression)
> >
> > * Delay and callback pointers are now passed via the ctors to the IncomingVideoStream classes. The thread primitives in the IncomingVideoStream classes are also constructed/destructed at the same time as the owning object, which allowed me to remove one more lock.
> >
> > * Removed code in the VideoStreamDecoder that could overwrite the VideoReceiveStream render delay with a fixed value of 10ms on construction. This wasn't a problem with the previous implementation (it would be now though) but seemed to me like the wrong place to be setting that value.
> >
> > * Made the render delay value in VideoRenderFrames, const.
> >
> > BUG=chromium:620232
> > R=mflodman@webrtc.org, nisse@webrtc.org
> >
> > Committed: https://crrev.com/884c336c345d988974c2a69cea402b0fb8b07a63
> > Cr-Commit-Position: refs/heads/master@{#13219}
>
> TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,tommi@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=chromium:620232
>
> Committed: https://crrev.com/a536bfe70de38fe877245317a7f0b00bcf69cbd0
> Cr-Commit-Position: refs/heads/master@{#13229}
TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,sakal@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:620232
Review-Url: https://codereview.webrtc.org/2089613002
Cr-Commit-Position: refs/heads/master@{#13230}
2016-06-21 00:26:43 -07:00
|
|
|
class StatsObserver : public test::EndToEndTest,
|
|
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
2015-04-27 10:09:49 +02:00
|
|
|
public:
|
2017-09-26 02:49:21 -07:00
|
|
|
StatsObserver(bool use_rtx, bool use_fec, bool screenshare)
|
2015-04-27 10:09:49 +02:00
|
|
|
: EndToEndTest(kLongTimeoutMs),
|
|
|
|
|
use_rtx_(use_rtx),
|
2017-09-26 02:49:21 -07:00
|
|
|
use_fec_(use_fec),
|
2015-12-03 08:10:08 -08:00
|
|
|
screenshare_(screenshare),
|
2016-02-15 11:27:15 +01:00
|
|
|
// This test uses NACK, so to send FEC we can't use a fake encoder.
|
2017-09-26 02:49:21 -07:00
|
|
|
vp8_encoder_(use_fec ? VP8Encoder::Create() : nullptr),
|
2015-04-27 10:09:49 +02:00
|
|
|
sender_call_(nullptr),
|
|
|
|
|
receiver_call_(nullptr),
|
2016-10-18 11:50:50 -07:00
|
|
|
start_runtime_ms_(-1),
|
|
|
|
|
num_frames_received_(0) {}
|
2015-04-27 10:09:49 +02:00
|
|
|
|
|
|
|
|
private:
|
2016-10-18 11:50:50 -07:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
|
|
|
|
// The RTT is needed to estimate |ntp_time_ms| which is used by
|
|
|
|
|
// end-to-end delay stats. Therefore, start counting received frames once
|
|
|
|
|
// |ntp_time_ms| is valid.
|
|
|
|
|
if (video_frame.ntp_time_ms() > 0 &&
|
|
|
|
|
Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() >=
|
|
|
|
|
video_frame.ntp_time_ms()) {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
++num_frames_received_;
|
|
|
|
|
}
|
|
|
|
|
}
|
Reland of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #1 id:1 of https://codereview.webrtc.org/2084873002/ )
Reason for revert:
Reverting the revert. This change is not related to the failure on the Windows FYI bots. The cause of the failure has been reverted in Chromium:
https://codereview.chromium.org/2081653004/
Original issue's description:
> Revert of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #5 id:340001 of https://codereview.webrtc.org/2078873002/ )
>
> Reason for revert:
> Breaks chromium.webrtc.fyi
>
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win7%20Tester/builds/4719
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win10%20Tester/builds/3120
>
> Original issue's description:
> > Reland of IncomingVideoStream refactoring.
> > This reland does not contain the non-smoothing part of the original implementation. Instead, when smoothing is turned off, frame callbacks run on the decoder thread, as they did before. This code path is used in Chrome. As far as Chrome goes, the difference now is that there won't be an instance of IncomingVideoStream in between the decoder and the callback (i.e. fewer locks). Other than that, no change for Chrome.
> >
> > Original issue's description (with non-smoothing references removed):
> >
> > Split IncomingVideoStream into two implementations, with smoothing and without.
> >
> > * Added TODOs and documentation for VideoReceiveStream::OnFrame, where we today grab 6 locks.
> >
> > * Removed the Start/Stop methods from the IncomingVideoStream implementations. Now, when an instance is created, it should be considered to be "running" and when it is deleted, it's "not running". This saves on resources and also reduces the amount of locking required and I could remove one critical section altogether.
> >
> > * Changed the VideoStreamDecoder class to not depend on IncomingVideoStream but rather use the generic rtc::VideoSinkInterface<VideoFrame> interface. This means that any implementation of that interface can be used and the decoder can be made to just use the 'renderer' from the config. Once we do that, we can decouple the IncomingVideoStream implementations from the decoder and VideoReceiveStream implementations and leave it up to the application for how to do smoothing. The app can choose to use the Incoming* classes or roll its own (which may be preferable since applications often have their own scheduling mechanisms).
> >
> > * The lifetime of the VideoStreamDecoder instance is now bound to Start/Stop in VideoReceiveStream and not all of the lifetime of VideoReceiveStream.
> >
> > * Fixed VideoStreamDecoder to unregister callbacks in the dtor that were registered in the ctor. (this was open to a use-after-free regression)
> >
> > * Delay and callback pointers are now passed via the ctors to the IncomingVideoStream classes. The thread primitives in the IncomingVideoStream classes are also constructed/destructed at the same time as the owning object, which allowed me to remove one more lock.
> >
> > * Removed code in the VideoStreamDecoder that could overwrite the VideoReceiveStream render delay with a fixed value of 10ms on construction. This wasn't a problem with the previous implementation (it would be now though) but seemed to me like the wrong place to be setting that value.
> >
> > * Made the render delay value in VideoRenderFrames, const.
> >
> > BUG=chromium:620232
> > R=mflodman@webrtc.org, nisse@webrtc.org
> >
> > Committed: https://crrev.com/884c336c345d988974c2a69cea402b0fb8b07a63
> > Cr-Commit-Position: refs/heads/master@{#13219}
>
> TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,tommi@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=chromium:620232
>
> Committed: https://crrev.com/a536bfe70de38fe877245317a7f0b00bcf69cbd0
> Cr-Commit-Position: refs/heads/master@{#13229}
TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,sakal@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:620232
Review-Url: https://codereview.webrtc.org/2089613002
Cr-Commit-Position: refs/heads/master@{#13230}
2016-06-21 00:26:43 -07:00
|
|
|
|
2015-04-27 10:09:49 +02:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2016-10-18 11:50:50 -07:00
|
|
|
if (MinMetricRunTimePassed() && MinNumberOfFramesReceived())
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2015-04-27 10:09:49 +02:00
|
|
|
|
2015-10-27 08:29:42 -07:00
|
|
|
return SEND_PACKET;
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MinMetricRunTimePassed() {
|
|
|
|
|
int64_t now = Clock::GetRealTimeClock()->TimeInMilliseconds();
|
|
|
|
|
if (start_runtime_ms_ == -1) {
|
|
|
|
|
start_runtime_ms_ = now;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
int64_t elapsed_sec = (now - start_runtime_ms_) / 1000;
|
|
|
|
|
return elapsed_sec > metrics::kMinRunTimeInSeconds * 2;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 11:50:50 -07:00
|
|
|
bool MinNumberOfFramesReceived() const {
|
|
|
|
|
const int kMinRequiredHistogramSamples = 200;
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
return num_frames_received_ > kMinRequiredHistogramSamples;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2015-04-27 10:09:49 +02:00
|
|
|
// NACK
|
|
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
Reland of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #1 id:1 of https://codereview.webrtc.org/2084873002/ )
Reason for revert:
Reverting the revert. This change is not related to the failure on the Windows FYI bots. The cause of the failure has been reverted in Chromium:
https://codereview.chromium.org/2081653004/
Original issue's description:
> Revert of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #5 id:340001 of https://codereview.webrtc.org/2078873002/ )
>
> Reason for revert:
> Breaks chromium.webrtc.fyi
>
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win7%20Tester/builds/4719
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win10%20Tester/builds/3120
>
> Original issue's description:
> > Reland of IncomingVideoStream refactoring.
> > This reland does not contain the non-smoothing part of the original implementation. Instead, when smoothing is turned off, frame callbacks run on the decoder thread, as they did before. This code path is used in Chrome. As far as Chrome goes, the difference now is that there won't be an instance of IncomingVideoStream in between the decoder and the callback (i.e. fewer locks). Other than that, no change for Chrome.
> >
> > Original issue's description (with non-smoothing references removed):
> >
> > Split IncomingVideoStream into two implementations, with smoothing and without.
> >
> > * Added TODOs and documentation for VideoReceiveStream::OnFrame, where we today grab 6 locks.
> >
> > * Removed the Start/Stop methods from the IncomingVideoStream implementations. Now, when an instance is created, it should be considered to be "running" and when it is deleted, it's "not running". This saves on resources and also reduces the amount of locking required and I could remove one critical section altogether.
> >
> > * Changed the VideoStreamDecoder class to not depend on IncomingVideoStream but rather use the generic rtc::VideoSinkInterface<VideoFrame> interface. This means that any implementation of that interface can be used and the decoder can be made to just use the 'renderer' from the config. Once we do that, we can decouple the IncomingVideoStream implementations from the decoder and VideoReceiveStream implementations and leave it up to the application for how to do smoothing. The app can choose to use the Incoming* classes or roll its own (which may be preferable since applications often have their own scheduling mechanisms).
> >
> > * The lifetime of the VideoStreamDecoder instance is now bound to Start/Stop in VideoReceiveStream and not all of the lifetime of VideoReceiveStream.
> >
> > * Fixed VideoStreamDecoder to unregister callbacks in the dtor that were registered in the ctor. (this was open to a use-after-free regression)
> >
> > * Delay and callback pointers are now passed via the ctors to the IncomingVideoStream classes. The thread primitives in the IncomingVideoStream classes are also constructed/destructed at the same time as the owning object, which allowed me to remove one more lock.
> >
> > * Removed code in the VideoStreamDecoder that could overwrite the VideoReceiveStream render delay with a fixed value of 10ms on construction. This wasn't a problem with the previous implementation (it would be now though) but seemed to me like the wrong place to be setting that value.
> >
> > * Made the render delay value in VideoRenderFrames, const.
> >
> > BUG=chromium:620232
> > R=mflodman@webrtc.org, nisse@webrtc.org
> >
> > Committed: https://crrev.com/884c336c345d988974c2a69cea402b0fb8b07a63
> > Cr-Commit-Position: refs/heads/master@{#13219}
>
> TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,tommi@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=chromium:620232
>
> Committed: https://crrev.com/a536bfe70de38fe877245317a7f0b00bcf69cbd0
> Cr-Commit-Position: refs/heads/master@{#13229}
TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,sakal@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:620232
Review-Url: https://codereview.webrtc.org/2089613002
Cr-Commit-Position: refs/heads/master@{#13230}
2016-06-21 00:26:43 -07:00
|
|
|
(*receive_configs)[0].renderer = this;
|
2015-04-27 10:09:49 +02:00
|
|
|
// FEC
|
2017-09-26 02:49:21 -07:00
|
|
|
if (use_fec_) {
|
2016-10-04 23:28:39 -07:00
|
|
|
send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
|
|
|
|
|
send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
|
2016-02-15 11:27:15 +01:00
|
|
|
send_config->encoder_settings.encoder = vp8_encoder_.get();
|
|
|
|
|
send_config->encoder_settings.payload_name = "VP8";
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_name = "VP8";
|
2017-09-26 02:49:21 -07:00
|
|
|
(*receive_configs)[0].rtp.red_payload_type = kRedPayloadType;
|
|
|
|
|
(*receive_configs)[0].rtp.ulpfec_payload_type = kUlpfecPayloadType;
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
|
|
|
|
// RTX
|
|
|
|
|
if (use_rtx_) {
|
|
|
|
|
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
|
|
|
|
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
Reland of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #1 id:1 of https://codereview.webrtc.org/2649323010/ )
Reason for revert:
Downstream project relied on changed struct.
Transition made possible by https://codereview.webrtc.org/2655243006/.
Original issue's description:
> Revert of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #7 id:160001 of https://codereview.webrtc.org/2646073004/ )
>
> Reason for revert:
> Breaks internal downstream project.
>
> Original issue's description:
> > Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters.
> >
> > Prior to this CL, received RTX (associated) payload types were only configured
> > when WebRtcVideoChannel2::AddRecvStream was called. In the same method, the RTX
> > SSRC was set up.
> >
> > After this CL, the RTX (associated) payload types are set in
> > WebRtcVideoChannel2::SetRecvParameters, which is the appropriate place to set
> > them. The RTX SSRC is still set in WebRtcVideoChannel2::AddRecvStream, since
> > that is the code path that sets other SSRCs.
> >
> > As part of this fix, the VideoReceiveStream::Config::Rtp struct is changed.
> > We remove the possibility for each video payload type to have an associated
> > specific RTX SSRC. Although the config previously allowed for this, all payload
> > types always had the same RTX SSRC set, and the underlying RtpPayloadRegistry
> > did not support multiple SSRCs. This change to the config struct should thus not
> > have any functional impact. The change does however affect the RtcEventLog, since
> > that is used for storing the VideoReceiveStream::Configs. For simplicity,
> > this CL does not change the event log proto definitions, instead duplicating
> > the serialized RTX SSRCs such that they fit in the existing proto definition.
> >
> > BUG=webrtc:7011
> >
> > Review-Url: https://codereview.webrtc.org/2646073004
> > Cr-Commit-Position: refs/heads/master@{#16302}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/fe2bef39cd2a5c891a49f7320514fb04324dc66c
>
> TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,brandtr@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:7011
>
> Review-Url: https://codereview.webrtc.org/2649323010
> Cr-Commit-Position: refs/heads/master@{#16307}
> Committed: https://chromium.googlesource.com/external/webrtc/+/e4974953ce0d03a60fae7659b199a6a62a79fa30
TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,kjellander@webrtc.org,kjellander@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
# NOTREECHECKS=true
# NOTRY=true
BUG=webrtc:7011
Review-Url: https://codereview.webrtc.org/2654163006
Cr-Commit-Position: refs/heads/master@{#16322}
2017-01-27 04:53:07 -08:00
|
|
|
(*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
|
2017-08-25 04:44:25 -07:00
|
|
|
(*receive_configs)[0]
|
|
|
|
|
.rtp.rtx_associated_payload_types[kSendRtxPayloadType] =
|
|
|
|
|
kFakeVideoSendPayloadType;
|
2017-09-26 02:49:21 -07:00
|
|
|
if (use_fec_) {
|
|
|
|
|
send_config->rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType;
|
|
|
|
|
(*receive_configs)[0]
|
|
|
|
|
.rtp.rtx_associated_payload_types[kRtxRedPayloadType] =
|
|
|
|
|
kSendRtxPayloadType;
|
|
|
|
|
}
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
2016-09-23 02:09:46 -07:00
|
|
|
// RTT needed for RemoteNtpTimeEstimator for the receive stream.
|
|
|
|
|
(*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true;
|
2015-12-03 08:10:08 -08:00
|
|
|
encoder_config->content_type =
|
|
|
|
|
screenshare_ ? VideoEncoderConfig::ContentType::kScreen
|
|
|
|
|
: VideoEncoderConfig::ContentType::kRealtimeVideo;
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
|
|
|
|
|
sender_call_ = sender_call;
|
|
|
|
|
receiver_call_ = receiver_call;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait()) << "Timed out waiting for packet to be NACKed.";
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-18 11:50:50 -07:00
|
|
|
rtc::CriticalSection crit_;
|
2015-12-03 08:10:08 -08:00
|
|
|
const bool use_rtx_;
|
2017-09-26 02:49:21 -07:00
|
|
|
const bool use_fec_;
|
2015-12-03 08:10:08 -08:00
|
|
|
const bool screenshare_;
|
2016-03-01 11:52:33 -08:00
|
|
|
const std::unique_ptr<VideoEncoder> vp8_encoder_;
|
2015-04-27 10:09:49 +02:00
|
|
|
Call* sender_call_;
|
|
|
|
|
Call* receiver_call_;
|
|
|
|
|
int64_t start_runtime_ms_;
|
2017-09-09 04:17:22 -07:00
|
|
|
int num_frames_received_ RTC_GUARDED_BY(&crit_);
|
2017-09-26 02:49:21 -07:00
|
|
|
} test(use_rtx, use_fec, screenshare);
|
2015-04-27 10:09:49 +02:00
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
metrics::Reset();
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2015-04-27 10:09:49 +02:00
|
|
|
|
2015-12-03 08:10:08 -08:00
|
|
|
std::string video_prefix =
|
|
|
|
|
screenshare ? "WebRTC.Video.Screenshare." : "WebRTC.Video.";
|
2017-08-30 03:32:14 -07:00
|
|
|
// The content type extension is disabled in non screenshare test,
|
|
|
|
|
// therefore no slicing on simulcast id should be present.
|
|
|
|
|
std::string video_suffix = screenshare ? ".S0" : "";
|
2015-04-27 10:09:49 +02:00
|
|
|
// Verify that stats have been updated once.
|
2016-07-27 00:39:09 -07:00
|
|
|
EXPECT_EQ(2, metrics::NumSamples("WebRTC.Call.LifetimeInSeconds"));
|
2017-07-04 04:05:06 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples(
|
|
|
|
|
"WebRTC.Call.TimeReceivingVideoRtpPacketsInSeconds"));
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Call.VideoBitrateReceivedInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Call.RtcpBitrateReceivedInBps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Call.BitrateReceivedInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Call.EstimatedSendBitrateInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Call.PacerBitrateInKbps"));
|
2016-07-27 00:39:09 -07:00
|
|
|
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SendStreamLifetimeInSeconds"));
|
|
|
|
|
EXPECT_EQ(1,
|
|
|
|
|
metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
|
2015-04-27 10:09:49 +02:00
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
|
2015-07-22 06:52:00 -07:00
|
|
|
EXPECT_EQ(1,
|
2016-05-20 06:29:46 -07:00
|
|
|
metrics::NumSamples(video_prefix + "NackPacketsReceivedPerMinute"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
|
2015-12-03 08:10:08 -08:00
|
|
|
EXPECT_EQ(1,
|
2016-05-20 06:29:46 -07:00
|
|
|
metrics::NumSamples(video_prefix + "FirPacketsReceivedPerMinute"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
|
|
|
|
|
EXPECT_EQ(1,
|
|
|
|
|
metrics::NumSamples(video_prefix + "PliPacketsReceivedPerMinute"));
|
2015-11-16 00:40:49 -08:00
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "KeyFramesSentInPermille"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
|
2015-07-24 00:20:58 -07:00
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "SentPacketsLostInPercent"));
|
2016-03-01 09:40:42 +01:00
|
|
|
EXPECT_EQ(1,
|
2016-05-20 06:29:46 -07:00
|
|
|
metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "InputWidthInPixels"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "InputHeightInPixels"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "SentWidthInPixels"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "SentHeightInPixels"));
|
2017-08-30 03:32:14 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "ReceivedWidthInPixels"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "ReceivedHeightInPixels"));
|
2016-05-20 06:29:46 -07:00
|
|
|
|
2016-10-02 23:45:26 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumEvents(video_prefix + "InputWidthInPixels",
|
|
|
|
|
kDefaultWidth));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumEvents(video_prefix + "InputHeightInPixels",
|
|
|
|
|
kDefaultHeight));
|
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
1, metrics::NumEvents(video_prefix + "SentWidthInPixels", kDefaultWidth));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumEvents(video_prefix + "SentHeightInPixels",
|
|
|
|
|
kDefaultHeight));
|
2017-08-30 03:32:14 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumEvents(video_prefix + "ReceivedWidthInPixels",
|
2016-10-02 23:45:26 -07:00
|
|
|
kDefaultWidth));
|
2017-08-30 03:32:14 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumEvents(video_prefix + "ReceivedHeightInPixels",
|
2016-10-02 23:45:26 -07:00
|
|
|
kDefaultHeight));
|
2016-05-20 06:29:46 -07:00
|
|
|
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "InputFramesPerSecond"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "SentFramesPerSecond"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
|
|
|
|
|
|
2017-08-30 03:32:14 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "EndToEndDelayInMs" +
|
|
|
|
|
video_suffix));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "EndToEndDelayMaxInMs" +
|
|
|
|
|
video_suffix));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "InterframeDelayInMs" +
|
|
|
|
|
video_suffix));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "InterframeDelayMaxInMs" +
|
|
|
|
|
video_suffix));
|
2017-07-03 01:15:58 -07:00
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "EncodeTimeInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DecodeTimeInMs"));
|
|
|
|
|
|
2016-12-19 06:50:53 -08:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "NumberOfPauseEvents"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "PausedTimeInPercent"));
|
|
|
|
|
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "BitrateSentInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateReceivedInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "MediaBitrateSentInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.MediaBitrateReceivedInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "PaddingBitrateSentInKbps"));
|
2015-12-03 08:10:08 -08:00
|
|
|
EXPECT_EQ(1,
|
2016-05-20 06:29:46 -07:00
|
|
|
metrics::NumSamples("WebRTC.Video.PaddingBitrateReceivedInKbps"));
|
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
1, metrics::NumSamples(video_prefix + "RetransmittedBitrateSentInKbps"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(
|
|
|
|
|
"WebRTC.Video.RetransmittedBitrateReceivedInKbps"));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SendDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "SendSideDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples(video_prefix + "SendSideDelayMaxInMs"));
|
2015-11-16 00:40:49 -08:00
|
|
|
|
2015-04-27 10:09:49 +02:00
|
|
|
int num_rtx_samples = use_rtx ? 1 : 0;
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(num_rtx_samples,
|
|
|
|
|
metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
|
|
|
|
|
EXPECT_EQ(num_rtx_samples,
|
|
|
|
|
metrics::NumSamples("WebRTC.Video.RtxBitrateReceivedInKbps"));
|
2015-04-27 10:09:49 +02:00
|
|
|
|
2017-09-26 02:49:21 -07:00
|
|
|
int num_red_samples = use_fec ? 1 : 0;
|
2016-05-20 06:29:46 -07:00
|
|
|
EXPECT_EQ(num_red_samples,
|
|
|
|
|
metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
|
|
|
|
|
EXPECT_EQ(num_red_samples,
|
|
|
|
|
metrics::NumSamples("WebRTC.Video.FecBitrateReceivedInKbps"));
|
|
|
|
|
EXPECT_EQ(num_red_samples,
|
|
|
|
|
metrics::NumSamples("WebRTC.Video.ReceivedFecPacketsInPercent"));
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-13 14:09:56 -07:00
|
|
|
#if defined(WEBRTC_WIN)
|
|
|
|
|
// Disabled due to flakiness on Windows (bugs.webrtc.org/7483).
|
|
|
|
|
#define MAYBE_ContentTypeSwitches DISABLED_ContentTypeSwitches
|
|
|
|
|
#else
|
|
|
|
|
#define MAYBE_ContentTypeSwitches ContentTypeSwitches
|
|
|
|
|
#endif
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, MAYBE_ContentTypeSwitches) {
|
2017-04-11 10:34:31 -07:00
|
|
|
class StatsObserver : public test::BaseTest,
|
|
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
|
|
|
|
public:
|
|
|
|
|
StatsObserver() : BaseTest(kLongTimeoutMs), num_frames_received_(0) {}
|
|
|
|
|
|
|
|
|
|
bool ShouldCreateReceivers() const override { return true; }
|
|
|
|
|
|
|
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
|
|
|
|
// The RTT is needed to estimate |ntp_time_ms| which is used by
|
|
|
|
|
// end-to-end delay stats. Therefore, start counting received frames once
|
|
|
|
|
// |ntp_time_ms| is valid.
|
|
|
|
|
if (video_frame.ntp_time_ms() > 0 &&
|
|
|
|
|
Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() >=
|
|
|
|
|
video_frame.ntp_time_ms()) {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
++num_frames_received_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
if (MinNumberOfFramesReceived())
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MinNumberOfFramesReceived() const {
|
2017-04-18 09:17:53 -07:00
|
|
|
// Have some room for frames with wrong content type during switch.
|
|
|
|
|
const int kMinRequiredHistogramSamples = 200+50;
|
2017-04-11 10:34:31 -07:00
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
return num_frames_received_ > kMinRequiredHistogramSamples;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// May be called several times.
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
EXPECT_TRUE(Wait()) << "Timed out waiting for enough packets.";
|
|
|
|
|
// Reset frame counter so next PerformTest() call will do something.
|
|
|
|
|
{
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
num_frames_received_ = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtc::CriticalSection crit_;
|
2017-09-09 04:17:22 -07:00
|
|
|
int num_frames_received_ RTC_GUARDED_BY(&crit_);
|
2017-04-11 10:34:31 -07:00
|
|
|
} test;
|
|
|
|
|
|
|
|
|
|
metrics::Reset();
|
|
|
|
|
|
|
|
|
|
Call::Config send_config(test.GetSenderCallConfig());
|
|
|
|
|
Call::Config recv_config(test.GetReceiverCallConfig());
|
2017-08-22 04:02:52 -07:00
|
|
|
VideoEncoderConfig encoder_config_with_screenshare;
|
|
|
|
|
|
2017-08-23 00:44:27 -07:00
|
|
|
task_queue_.SendTask([this, &test, &send_config,
|
2017-08-22 04:02:52 -07:00
|
|
|
&recv_config, &encoder_config_with_screenshare]() {
|
|
|
|
|
CreateSenderCall(send_config);
|
|
|
|
|
CreateReceiverCall(recv_config);
|
|
|
|
|
|
|
|
|
|
receive_transport_.reset(test.CreateReceiveTransport(&task_queue_));
|
|
|
|
|
send_transport_.reset(
|
|
|
|
|
test.CreateSendTransport(&task_queue_, sender_call_.get()));
|
|
|
|
|
send_transport_->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
receive_transport_->SetReceiver(sender_call_->Receiver());
|
|
|
|
|
|
|
|
|
|
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
|
|
|
|
CreateSendConfig(1, 0, 0, send_transport_.get());
|
|
|
|
|
CreateMatchingReceiveConfigs(receive_transport_.get());
|
|
|
|
|
|
|
|
|
|
// Modify send and receive configs.
|
|
|
|
|
video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
video_receive_configs_[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
video_receive_configs_[0].renderer = &test;
|
|
|
|
|
// RTT needed for RemoteNtpTimeEstimator for the receive stream.
|
|
|
|
|
video_receive_configs_[0].rtp.rtcp_xr.receiver_reference_time_report = true;
|
|
|
|
|
// Start with realtime video.
|
|
|
|
|
video_encoder_config_.content_type =
|
|
|
|
|
VideoEncoderConfig::ContentType::kRealtimeVideo;
|
|
|
|
|
// Second encoder config for the second part of the test uses screenshare
|
|
|
|
|
encoder_config_with_screenshare = video_encoder_config_.Copy();
|
|
|
|
|
encoder_config_with_screenshare.content_type =
|
|
|
|
|
VideoEncoderConfig::ContentType::kScreen;
|
|
|
|
|
|
|
|
|
|
CreateVideoStreams();
|
|
|
|
|
CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
|
|
|
|
|
kDefaultHeight);
|
|
|
|
|
Start();
|
|
|
|
|
});
|
2017-04-11 10:34:31 -07:00
|
|
|
|
|
|
|
|
test.PerformTest();
|
|
|
|
|
|
|
|
|
|
// Replace old send stream.
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &encoder_config_with_screenshare]() {
|
|
|
|
|
sender_call_->DestroyVideoSendStream(video_send_stream_);
|
|
|
|
|
video_send_stream_ = sender_call_->CreateVideoSendStream(
|
|
|
|
|
video_send_config_.Copy(), encoder_config_with_screenshare.Copy());
|
|
|
|
|
video_send_stream_->SetSource(
|
|
|
|
|
frame_generator_capturer_.get(),
|
|
|
|
|
VideoSendStream::DegradationPreference::kBalanced);
|
|
|
|
|
video_send_stream_->Start();
|
|
|
|
|
});
|
2017-04-11 10:34:31 -07:00
|
|
|
|
|
|
|
|
// Continue to run test but now with screenshare.
|
|
|
|
|
test.PerformTest();
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
send_transport_.reset();
|
|
|
|
|
receive_transport_.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2017-04-11 10:34:31 -07:00
|
|
|
|
|
|
|
|
// Verify that stats have been updated for both screenshare and video.
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.EndToEndDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1,
|
|
|
|
|
metrics::NumSamples("WebRTC.Video.Screenshare.EndToEndDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.EndToEndDelayMaxInMs"));
|
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
1, metrics::NumSamples("WebRTC.Video.Screenshare.EndToEndDelayMaxInMs"));
|
2017-07-03 01:15:58 -07:00
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InterframeDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1,
|
|
|
|
|
metrics::NumSamples(
|
|
|
|
|
"WebRTC.Video.Screenshare.InterframeDelayInMs"));
|
|
|
|
|
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InterframeDelayMaxInMs"));
|
|
|
|
|
EXPECT_EQ(1,
|
|
|
|
|
metrics::NumSamples(
|
|
|
|
|
"WebRTC.Video.Screenshare.InterframeDelayMaxInMs"));
|
2017-04-11 10:34:31 -07:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyHistogramStatsWithRtx) {
|
2015-04-27 10:09:49 +02:00
|
|
|
const bool kEnabledRtx = true;
|
|
|
|
|
const bool kEnabledRed = false;
|
2015-12-03 08:10:08 -08:00
|
|
|
const bool kScreenshare = false;
|
|
|
|
|
VerifyHistogramStats(kEnabledRtx, kEnabledRed, kScreenshare);
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyHistogramStatsWithRed) {
|
2015-04-27 10:09:49 +02:00
|
|
|
const bool kEnabledRtx = false;
|
|
|
|
|
const bool kEnabledRed = true;
|
2015-12-03 08:10:08 -08:00
|
|
|
const bool kScreenshare = false;
|
|
|
|
|
VerifyHistogramStats(kEnabledRtx, kEnabledRed, kScreenshare);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyHistogramStatsWithScreenshare) {
|
2015-12-03 08:10:08 -08:00
|
|
|
const bool kEnabledRtx = false;
|
|
|
|
|
const bool kEnabledRed = false;
|
|
|
|
|
const bool kScreenshare = true;
|
|
|
|
|
VerifyHistogramStats(kEnabledRtx, kEnabledRed, kScreenshare);
|
2015-04-27 10:09:49 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-30 13:19:09 +00:00
|
|
|
void EndToEndTest::TestSendsSetSsrcs(size_t num_ssrcs,
|
|
|
|
|
bool send_single_ssrc_first) {
|
|
|
|
|
class SendsSetSsrcs : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
SendsSetSsrcs(const uint32_t* ssrcs,
|
|
|
|
|
size_t num_ssrcs,
|
|
|
|
|
bool send_single_ssrc_first)
|
|
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
|
|
|
|
num_ssrcs_(num_ssrcs),
|
|
|
|
|
send_single_ssrc_first_(send_single_ssrc_first),
|
|
|
|
|
ssrcs_to_observe_(num_ssrcs),
|
2015-08-03 04:38:41 -07:00
|
|
|
expect_single_ssrc_(send_single_ssrc_first),
|
|
|
|
|
send_stream_(nullptr) {
|
2014-06-30 13:19:09 +00:00
|
|
|
for (size_t i = 0; i < num_ssrcs; ++i)
|
|
|
|
|
valid_ssrcs_[ssrcs[i]] = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2014-06-30 13:19:09 +00:00
|
|
|
RTPHeader header;
|
2014-07-08 12:10:51 +00:00
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
2014-06-30 13:19:09 +00:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(valid_ssrcs_[header.ssrc])
|
|
|
|
|
<< "Received unknown SSRC: " << header.ssrc;
|
|
|
|
|
|
|
|
|
|
if (!valid_ssrcs_[header.ssrc])
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2014-06-30 13:19:09 +00:00
|
|
|
|
|
|
|
|
if (!is_observed_[header.ssrc]) {
|
|
|
|
|
is_observed_[header.ssrc] = true;
|
|
|
|
|
--ssrcs_to_observe_;
|
|
|
|
|
if (expect_single_ssrc_) {
|
|
|
|
|
expect_single_ssrc_ = false;
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2014-06-30 13:19:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ssrcs_to_observe_ == 0)
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2014-06-30 13:19:09 +00:00
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-07 17:43:18 +01:00
|
|
|
size_t GetNumVideoStreams() const override { return num_ssrcs_; }
|
2014-06-30 13:19:09 +00:00
|
|
|
|
2016-10-02 23:45:26 -07:00
|
|
|
// This test use other VideoStream settings than the the default settings
|
|
|
|
|
// implemented in DefaultVideoStreamFactory. Therefore this test implement
|
|
|
|
|
// its own VideoEncoderConfig::VideoStreamFactoryInterface which is created
|
|
|
|
|
// in ModifyVideoConfigs.
|
|
|
|
|
class VideoStreamFactory
|
|
|
|
|
: public VideoEncoderConfig::VideoStreamFactoryInterface {
|
|
|
|
|
public:
|
|
|
|
|
VideoStreamFactory() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::vector<VideoStream> CreateEncoderStreams(
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
const VideoEncoderConfig& encoder_config) override {
|
|
|
|
|
std::vector<VideoStream> streams =
|
|
|
|
|
test::CreateVideoStreams(width, height, encoder_config);
|
2016-09-29 23:25:40 -07:00
|
|
|
// Set low simulcast bitrates to not have to wait for bandwidth ramp-up.
|
2016-10-02 23:45:26 -07:00
|
|
|
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
|
|
|
|
streams[i].min_bitrate_bps = 10000;
|
|
|
|
|
streams[i].target_bitrate_bps = 15000;
|
|
|
|
|
streams[i].max_bitrate_bps = 20000;
|
2016-09-29 23:25:40 -07:00
|
|
|
}
|
2016-10-02 23:45:26 -07:00
|
|
|
return streams;
|
2016-09-29 23:25:40 -07:00
|
|
|
}
|
2016-10-02 23:45:26 -07:00
|
|
|
};
|
2016-09-29 23:25:40 -07:00
|
|
|
|
2016-10-02 23:45:26 -07:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
encoder_config->video_stream_factory =
|
|
|
|
|
new rtc::RefCountedObject<VideoStreamFactory>();
|
2016-09-01 01:17:40 -07:00
|
|
|
video_encoder_config_all_streams_ = encoder_config->Copy();
|
2014-06-30 13:19:09 +00:00
|
|
|
if (send_single_ssrc_first_)
|
2016-10-02 23:45:26 -07:00
|
|
|
encoder_config->number_of_streams = 1;
|
2014-06-30 13:19:09 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void OnVideoStreamsCreated(
|
2014-06-30 13:19:09 +00:00
|
|
|
VideoSendStream* send_stream,
|
2015-02-09 15:14:36 +00:00
|
|
|
const std::vector<VideoReceiveStream*>& receive_streams) override {
|
2014-06-30 13:19:09 +00:00
|
|
|
send_stream_ = send_stream;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait()) << "Timed out while waiting for "
|
|
|
|
|
<< (send_single_ssrc_first_ ? "first SSRC."
|
|
|
|
|
: "SSRCs.");
|
2014-06-30 13:19:09 +00:00
|
|
|
|
|
|
|
|
if (send_single_ssrc_first_) {
|
|
|
|
|
// Set full simulcast and continue with the rest of the SSRCs.
|
2015-12-21 03:14:00 -08:00
|
|
|
send_stream_->ReconfigureVideoEncoder(
|
2016-09-01 01:17:40 -07:00
|
|
|
std::move(video_encoder_config_all_streams_));
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait()) << "Timed out while waiting on additional SSRCs.";
|
2014-06-30 13:19:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::map<uint32_t, bool> valid_ssrcs_;
|
|
|
|
|
std::map<uint32_t, bool> is_observed_;
|
|
|
|
|
|
|
|
|
|
const size_t num_ssrcs_;
|
|
|
|
|
const bool send_single_ssrc_first_;
|
|
|
|
|
|
|
|
|
|
size_t ssrcs_to_observe_;
|
|
|
|
|
bool expect_single_ssrc_;
|
|
|
|
|
|
|
|
|
|
VideoSendStream* send_stream_;
|
2015-12-21 03:14:00 -08:00
|
|
|
VideoEncoderConfig video_encoder_config_all_streams_;
|
2016-01-07 17:43:18 +01:00
|
|
|
} test(kVideoSendSsrcs, num_ssrcs, send_single_ssrc_first);
|
2014-06-30 13:19:09 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-06-30 13:19:09 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, ReportsSetEncoderRates) {
|
2015-02-26 13:15:22 +00:00
|
|
|
class EncoderRateStatsTest : public test::EndToEndTest,
|
|
|
|
|
public test::FakeEncoder {
|
|
|
|
|
public:
|
2017-08-22 04:02:52 -07:00
|
|
|
explicit EncoderRateStatsTest(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue)
|
2015-02-26 13:15:22 +00:00
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
2015-08-03 04:38:41 -07:00
|
|
|
FakeEncoder(Clock::GetRealTimeClock()),
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_(task_queue),
|
2015-08-03 04:38:41 -07:00
|
|
|
send_stream_(nullptr),
|
|
|
|
|
bitrate_kbps_(0) {}
|
2015-02-26 13:15:22 +00:00
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void OnVideoStreamsCreated(
|
2015-02-26 13:15:22 +00:00
|
|
|
VideoSendStream* send_stream,
|
|
|
|
|
const std::vector<VideoReceiveStream*>& receive_streams) override {
|
|
|
|
|
send_stream_ = send_stream;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2015-02-26 13:15:22 +00:00
|
|
|
send_config->encoder_settings.encoder = this;
|
2016-11-28 15:21:39 -08:00
|
|
|
RTC_DCHECK_EQ(1, encoder_config->number_of_streams);
|
2015-02-26 13:15:22 +00:00
|
|
|
}
|
|
|
|
|
|
2016-11-16 16:41:30 +01:00
|
|
|
int32_t SetRateAllocation(const BitrateAllocation& rate_allocation,
|
|
|
|
|
uint32_t framerate) override {
|
2015-02-26 13:15:22 +00:00
|
|
|
// Make sure not to trigger on any default zero bitrates.
|
2016-11-16 16:41:30 +01:00
|
|
|
if (rate_allocation.get_sum_bps() == 0)
|
2015-02-26 13:15:22 +00:00
|
|
|
return 0;
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&crit_);
|
2016-11-16 16:41:30 +01:00
|
|
|
bitrate_kbps_ = rate_allocation.get_sum_kbps();
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2015-02-26 13:15:22 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
ASSERT_TRUE(Wait())
|
2015-02-26 13:15:22 +00:00
|
|
|
<< "Timed out while waiting for encoder SetRates() call.";
|
2017-08-22 04:02:52 -07:00
|
|
|
|
|
|
|
|
task_queue_->SendTask([this]() {
|
|
|
|
|
WaitForEncoderTargetBitrateMatchStats();
|
|
|
|
|
send_stream_->Stop();
|
|
|
|
|
WaitForStatsReportZeroTargetBitrate();
|
|
|
|
|
send_stream_->Start();
|
|
|
|
|
WaitForEncoderTargetBitrateMatchStats();
|
|
|
|
|
});
|
2016-07-05 08:34:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WaitForEncoderTargetBitrateMatchStats() {
|
2015-12-10 13:02:50 +01:00
|
|
|
for (int i = 0; i < kDefaultTimeoutMs; ++i) {
|
2015-02-26 13:15:22 +00:00
|
|
|
VideoSendStream::Stats stats = send_stream_->GetStats();
|
|
|
|
|
{
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&crit_);
|
2015-02-26 13:15:22 +00:00
|
|
|
if ((stats.target_media_bitrate_bps + 500) / 1000 ==
|
|
|
|
|
static_cast<int>(bitrate_kbps_)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SleepMs(1);
|
|
|
|
|
}
|
|
|
|
|
FAIL()
|
|
|
|
|
<< "Timed out waiting for stats reporting the currently set bitrate.";
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-05 08:34:04 -07:00
|
|
|
void WaitForStatsReportZeroTargetBitrate() {
|
|
|
|
|
for (int i = 0; i < kDefaultTimeoutMs; ++i) {
|
|
|
|
|
if (send_stream_->GetStats().target_media_bitrate_bps == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SleepMs(1);
|
|
|
|
|
}
|
|
|
|
|
FAIL() << "Timed out waiting for stats reporting zero bitrate.";
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 13:15:22 +00:00
|
|
|
private:
|
2017-08-22 04:02:52 -07:00
|
|
|
test::SingleThreadedTaskQueueForTesting* const task_queue_;
|
2015-10-27 08:29:42 -07:00
|
|
|
rtc::CriticalSection crit_;
|
2015-02-26 13:15:22 +00:00
|
|
|
VideoSendStream* send_stream_;
|
2017-09-09 04:17:22 -07:00
|
|
|
uint32_t bitrate_kbps_ RTC_GUARDED_BY(crit_);
|
2017-08-22 04:02:52 -07:00
|
|
|
} test(&task_queue_);
|
2015-02-26 13:15:22 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2015-02-26 13:15:22 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, GetStats) {
|
2014-11-25 09:39:04 +00:00
|
|
|
static const int kStartBitrateBps = 3000000;
|
2015-05-27 17:59:11 +02:00
|
|
|
static const int kExpectedRenderDelayMs = 20;
|
Reland of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #1 id:1 of https://codereview.webrtc.org/2084873002/ )
Reason for revert:
Reverting the revert. This change is not related to the failure on the Windows FYI bots. The cause of the failure has been reverted in Chromium:
https://codereview.chromium.org/2081653004/
Original issue's description:
> Revert of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #5 id:340001 of https://codereview.webrtc.org/2078873002/ )
>
> Reason for revert:
> Breaks chromium.webrtc.fyi
>
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win7%20Tester/builds/4719
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win10%20Tester/builds/3120
>
> Original issue's description:
> > Reland of IncomingVideoStream refactoring.
> > This reland does not contain the non-smoothing part of the original implementation. Instead, when smoothing is turned off, frame callbacks run on the decoder thread, as they did before. This code path is used in Chrome. As far as Chrome goes, the difference now is that there won't be an instance of IncomingVideoStream in between the decoder and the callback (i.e. fewer locks). Other than that, no change for Chrome.
> >
> > Original issue's description (with non-smoothing references removed):
> >
> > Split IncomingVideoStream into two implementations, with smoothing and without.
> >
> > * Added TODOs and documentation for VideoReceiveStream::OnFrame, where we today grab 6 locks.
> >
> > * Removed the Start/Stop methods from the IncomingVideoStream implementations. Now, when an instance is created, it should be considered to be "running" and when it is deleted, it's "not running". This saves on resources and also reduces the amount of locking required and I could remove one critical section altogether.
> >
> > * Changed the VideoStreamDecoder class to not depend on IncomingVideoStream but rather use the generic rtc::VideoSinkInterface<VideoFrame> interface. This means that any implementation of that interface can be used and the decoder can be made to just use the 'renderer' from the config. Once we do that, we can decouple the IncomingVideoStream implementations from the decoder and VideoReceiveStream implementations and leave it up to the application for how to do smoothing. The app can choose to use the Incoming* classes or roll its own (which may be preferable since applications often have their own scheduling mechanisms).
> >
> > * The lifetime of the VideoStreamDecoder instance is now bound to Start/Stop in VideoReceiveStream and not all of the lifetime of VideoReceiveStream.
> >
> > * Fixed VideoStreamDecoder to unregister callbacks in the dtor that were registered in the ctor. (this was open to a use-after-free regression)
> >
> > * Delay and callback pointers are now passed via the ctors to the IncomingVideoStream classes. The thread primitives in the IncomingVideoStream classes are also constructed/destructed at the same time as the owning object, which allowed me to remove one more lock.
> >
> > * Removed code in the VideoStreamDecoder that could overwrite the VideoReceiveStream render delay with a fixed value of 10ms on construction. This wasn't a problem with the previous implementation (it would be now though) but seemed to me like the wrong place to be setting that value.
> >
> > * Made the render delay value in VideoRenderFrames, const.
> >
> > BUG=chromium:620232
> > R=mflodman@webrtc.org, nisse@webrtc.org
> >
> > Committed: https://crrev.com/884c336c345d988974c2a69cea402b0fb8b07a63
> > Cr-Commit-Position: refs/heads/master@{#13219}
>
> TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,tommi@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=chromium:620232
>
> Committed: https://crrev.com/a536bfe70de38fe877245317a7f0b00bcf69cbd0
> Cr-Commit-Position: refs/heads/master@{#13229}
TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,sakal@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:620232
Review-Url: https://codereview.webrtc.org/2089613002
Cr-Commit-Position: refs/heads/master@{#13230}
2016-06-21 00:26:43 -07:00
|
|
|
|
|
|
|
|
class ReceiveStreamRenderer : public rtc::VideoSinkInterface<VideoFrame> {
|
|
|
|
|
public:
|
|
|
|
|
ReceiveStreamRenderer() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void OnFrame(const VideoFrame& video_frame) override {}
|
|
|
|
|
};
|
|
|
|
|
|
2016-04-18 05:15:22 -07:00
|
|
|
class StatsObserver : public test::EndToEndTest,
|
|
|
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
2014-06-27 08:47:52 +00:00
|
|
|
public:
|
2015-10-27 08:29:42 -07:00
|
|
|
StatsObserver()
|
|
|
|
|
: EndToEndTest(kLongTimeoutMs),
|
2016-02-05 14:15:53 +01:00
|
|
|
encoder_(Clock::GetRealTimeClock(), 10),
|
2015-03-23 13:12:24 +00:00
|
|
|
send_stream_(nullptr),
|
2014-06-27 08:47:52 +00:00
|
|
|
expected_send_ssrcs_(),
|
2015-12-10 13:02:50 +01:00
|
|
|
check_stats_event_(false, false) {}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2016-07-13 09:11:28 -07:00
|
|
|
// Drop every 25th packet => 4% loss.
|
|
|
|
|
static const int kPacketLossFrac = 25;
|
|
|
|
|
RTPHeader header;
|
|
|
|
|
RtpUtility::RtpHeaderParser parser(packet, length);
|
|
|
|
|
if (parser.Parse(&header) &&
|
|
|
|
|
expected_send_ssrcs_.find(header.ssrc) !=
|
|
|
|
|
expected_send_ssrcs_.end() &&
|
|
|
|
|
header.sequenceNumber % kPacketLossFrac == 0) {
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
2015-12-10 13:02:50 +01:00
|
|
|
check_stats_event_.Set();
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
2014-02-07 12:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtcp(const uint8_t* packet, size_t length) override {
|
2015-12-10 13:02:50 +01:00
|
|
|
check_stats_event_.Set();
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
2014-02-07 12:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtp(const uint8_t* packet, size_t length) override {
|
2015-12-10 13:02:50 +01:00
|
|
|
check_stats_event_.Set();
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
2014-02-07 12:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2015-12-10 13:02:50 +01:00
|
|
|
check_stats_event_.Set();
|
2014-06-27 08:47:52 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2016-04-18 05:15:22 -07:00
|
|
|
void OnFrame(const VideoFrame& video_frame) override {
|
2014-06-27 08:47:52 +00:00
|
|
|
// Ensure that we have at least 5ms send side delay.
|
2016-04-18 05:15:22 -07:00
|
|
|
SleepMs(5);
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
bool CheckReceiveStats() {
|
2015-02-19 12:47:00 +00:00
|
|
|
for (size_t i = 0; i < receive_streams_.size(); ++i) {
|
|
|
|
|
VideoReceiveStream::Stats stats = receive_streams_[i]->GetStats();
|
|
|
|
|
EXPECT_EQ(expected_receive_ssrcs_[i], stats.ssrc);
|
|
|
|
|
|
|
|
|
|
// Make sure all fields have been populated.
|
|
|
|
|
// TODO(pbos): Use CompoundKey if/when we ever know that all stats are
|
|
|
|
|
// always filled for all receivers.
|
|
|
|
|
receive_stats_filled_["IncomingRate"] |=
|
|
|
|
|
stats.network_frame_rate != 0 || stats.total_bitrate_bps != 0;
|
|
|
|
|
|
2015-12-18 16:01:11 +01:00
|
|
|
send_stats_filled_["DecoderImplementationName"] |=
|
|
|
|
|
stats.decoder_implementation_name ==
|
|
|
|
|
test::FakeDecoder::kImplementationName;
|
2015-05-27 17:59:11 +02:00
|
|
|
receive_stats_filled_["RenderDelayAsHighAsExpected"] |=
|
|
|
|
|
stats.render_delay_ms >= kExpectedRenderDelayMs;
|
|
|
|
|
|
2015-02-19 12:47:00 +00:00
|
|
|
receive_stats_filled_["FrameCallback"] |= stats.decode_frame_rate != 0;
|
|
|
|
|
|
|
|
|
|
receive_stats_filled_["FrameRendered"] |= stats.render_frame_rate != 0;
|
|
|
|
|
|
|
|
|
|
receive_stats_filled_["StatisticsUpdated"] |=
|
2017-08-04 05:03:53 -07:00
|
|
|
stats.rtcp_stats.packets_lost != 0 ||
|
|
|
|
|
stats.rtcp_stats.extended_highest_sequence_number != 0 ||
|
2015-02-19 12:47:00 +00:00
|
|
|
stats.rtcp_stats.fraction_lost != 0 || stats.rtcp_stats.jitter != 0;
|
|
|
|
|
|
|
|
|
|
receive_stats_filled_["DataCountersUpdated"] |=
|
|
|
|
|
stats.rtp_stats.transmitted.payload_bytes != 0 ||
|
|
|
|
|
stats.rtp_stats.fec.packets != 0 ||
|
|
|
|
|
stats.rtp_stats.transmitted.header_bytes != 0 ||
|
|
|
|
|
stats.rtp_stats.transmitted.packets != 0 ||
|
|
|
|
|
stats.rtp_stats.transmitted.padding_bytes != 0 ||
|
|
|
|
|
stats.rtp_stats.retransmitted.packets != 0;
|
|
|
|
|
|
|
|
|
|
receive_stats_filled_["CodecStats"] |=
|
2015-02-25 10:42:16 +00:00
|
|
|
stats.target_delay_ms != 0 || stats.discarded_packets != 0;
|
2015-02-19 12:47:00 +00:00
|
|
|
|
|
|
|
|
receive_stats_filled_["FrameCounts"] |=
|
|
|
|
|
stats.frame_counts.key_frames != 0 ||
|
|
|
|
|
stats.frame_counts.delta_frames != 0;
|
|
|
|
|
|
2015-07-09 07:48:14 -07:00
|
|
|
receive_stats_filled_["CName"] |= !stats.c_name.empty();
|
2015-02-19 12:47:00 +00:00
|
|
|
|
|
|
|
|
receive_stats_filled_["RtcpPacketTypeCount"] |=
|
|
|
|
|
stats.rtcp_packet_type_counts.fir_packets != 0 ||
|
|
|
|
|
stats.rtcp_packet_type_counts.nack_packets != 0 ||
|
|
|
|
|
stats.rtcp_packet_type_counts.pli_packets != 0 ||
|
|
|
|
|
stats.rtcp_packet_type_counts.nack_requests != 0 ||
|
|
|
|
|
stats.rtcp_packet_type_counts.unique_nack_requests != 0;
|
2015-08-28 07:35:32 -07:00
|
|
|
|
|
|
|
|
assert(stats.current_payload_type == -1 ||
|
2016-01-07 17:43:18 +01:00
|
|
|
stats.current_payload_type == kFakeVideoSendPayloadType);
|
2015-08-28 07:35:32 -07:00
|
|
|
receive_stats_filled_["IncomingPayloadType"] |=
|
2016-01-07 17:43:18 +01:00
|
|
|
stats.current_payload_type == kFakeVideoSendPayloadType;
|
2015-02-19 12:47:00 +00:00
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
return AllStatsFilled(receive_stats_filled_);
|
|
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
bool CheckSendStats() {
|
2016-04-04 17:56:10 +02:00
|
|
|
RTC_DCHECK(send_stream_);
|
2014-06-27 08:47:52 +00:00
|
|
|
VideoSendStream::Stats stats = send_stream_->GetStats();
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2016-12-19 04:17:27 -08:00
|
|
|
size_t expected_num_streams = kNumSsrcs + expected_send_ssrcs_.size();
|
2014-06-27 08:47:52 +00:00
|
|
|
send_stats_filled_["NumStreams"] |=
|
2016-12-19 04:17:27 -08:00
|
|
|
stats.substreams.size() == expected_num_streams;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2015-02-26 12:19:31 +00:00
|
|
|
send_stats_filled_["CpuOveruseMetrics"] |=
|
2016-02-05 11:13:28 +01:00
|
|
|
stats.avg_encode_time_ms != 0 && stats.encode_usage_percent != 0;
|
2015-02-26 12:19:31 +00:00
|
|
|
|
2015-12-18 16:01:11 +01:00
|
|
|
send_stats_filled_["EncoderImplementationName"] |=
|
|
|
|
|
stats.encoder_implementation_name ==
|
|
|
|
|
test::FakeEncoder::kImplementationName;
|
|
|
|
|
|
2016-09-29 11:48:50 +02:00
|
|
|
send_stats_filled_["EncoderPreferredBitrate"] |=
|
|
|
|
|
stats.preferred_media_bitrate_bps > 0;
|
|
|
|
|
|
2015-02-25 10:42:16 +00:00
|
|
|
for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
|
2014-06-27 08:47:52 +00:00
|
|
|
stats.substreams.begin();
|
2015-02-25 10:42:16 +00:00
|
|
|
it != stats.substreams.end(); ++it) {
|
2016-07-13 09:11:28 -07:00
|
|
|
if (expected_send_ssrcs_.find(it->first) == expected_send_ssrcs_.end())
|
|
|
|
|
continue; // Probably RTX.
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2015-02-19 12:47:00 +00:00
|
|
|
send_stats_filled_[CompoundKey("CapturedFrameRate", it->first)] |=
|
2014-06-27 08:47:52 +00:00
|
|
|
stats.input_frame_rate != 0;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2015-02-25 10:42:16 +00:00
|
|
|
const VideoSendStream::StreamStats& stream_stats = it->second;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
send_stats_filled_[CompoundKey("StatisticsUpdated", it->first)] |=
|
2017-08-04 05:03:53 -07:00
|
|
|
stream_stats.rtcp_stats.packets_lost != 0 ||
|
|
|
|
|
stream_stats.rtcp_stats.extended_highest_sequence_number != 0 ||
|
2014-06-27 08:47:52 +00:00
|
|
|
stream_stats.rtcp_stats.fraction_lost != 0;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
send_stats_filled_[CompoundKey("DataCountersUpdated", it->first)] |=
|
2015-01-22 09:39:59 +00:00
|
|
|
stream_stats.rtp_stats.fec.packets != 0 ||
|
|
|
|
|
stream_stats.rtp_stats.transmitted.padding_bytes != 0 ||
|
|
|
|
|
stream_stats.rtp_stats.retransmitted.packets != 0 ||
|
|
|
|
|
stream_stats.rtp_stats.transmitted.packets != 0;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2016-07-13 09:11:28 -07:00
|
|
|
send_stats_filled_[CompoundKey("BitrateStatisticsObserver.Total",
|
2014-06-27 08:47:52 +00:00
|
|
|
it->first)] |=
|
2014-11-05 14:05:29 +00:00
|
|
|
stream_stats.total_bitrate_bps != 0;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2016-07-13 09:11:28 -07:00
|
|
|
send_stats_filled_[CompoundKey("BitrateStatisticsObserver.Retransmit",
|
|
|
|
|
it->first)] |=
|
|
|
|
|
stream_stats.retransmit_bitrate_bps != 0;
|
|
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
send_stats_filled_[CompoundKey("FrameCountObserver", it->first)] |=
|
2014-12-18 13:50:16 +00:00
|
|
|
stream_stats.frame_counts.delta_frames != 0 ||
|
|
|
|
|
stream_stats.frame_counts.key_frames != 0;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
send_stats_filled_[CompoundKey("OutgoingRate", it->first)] |=
|
|
|
|
|
stats.encode_frame_rate != 0;
|
2014-07-11 13:44:02 +00:00
|
|
|
|
|
|
|
|
send_stats_filled_[CompoundKey("Delay", it->first)] |=
|
|
|
|
|
stream_stats.avg_delay_ms != 0 || stream_stats.max_delay_ms != 0;
|
2015-02-19 12:47:00 +00:00
|
|
|
|
|
|
|
|
// TODO(pbos): Use CompoundKey when the test makes sure that all SSRCs
|
|
|
|
|
// report dropped packets.
|
|
|
|
|
send_stats_filled_["RtcpPacketTypeCount"] |=
|
|
|
|
|
stream_stats.rtcp_packet_type_counts.fir_packets != 0 ||
|
|
|
|
|
stream_stats.rtcp_packet_type_counts.nack_packets != 0 ||
|
|
|
|
|
stream_stats.rtcp_packet_type_counts.pli_packets != 0 ||
|
|
|
|
|
stream_stats.rtcp_packet_type_counts.nack_requests != 0 ||
|
|
|
|
|
stream_stats.rtcp_packet_type_counts.unique_nack_requests != 0;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
return AllStatsFilled(send_stats_filled_);
|
2014-02-07 12:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
std::string CompoundKey(const char* name, uint32_t ssrc) {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << name << "_" << ssrc;
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
bool AllStatsFilled(const std::map<std::string, bool>& stats_map) {
|
2016-07-13 09:11:28 -07:00
|
|
|
for (const auto& stat : stats_map) {
|
|
|
|
|
if (!stat.second)
|
2014-06-27 08:47:52 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2014-02-07 12:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::PacketTransport* CreateSendTransport(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue,
|
|
|
|
|
Call* sender_call) override {
|
2016-01-08 06:47:13 -08:00
|
|
|
FakeNetworkPipe::Config network_config;
|
|
|
|
|
network_config.loss_percent = 5;
|
2017-08-22 04:02:52 -07:00
|
|
|
return new test::PacketTransport(task_queue, sender_call, this,
|
2017-04-10 16:57:57 -07:00
|
|
|
test::PacketTransport::kSender,
|
|
|
|
|
payload_type_map_, network_config);
|
2016-01-08 06:47:13 -08:00
|
|
|
}
|
|
|
|
|
|
2015-02-09 15:14:36 +00:00
|
|
|
Call::Config GetSenderCallConfig() override {
|
2014-11-25 09:39:04 +00:00
|
|
|
Call::Config config = EndToEndTest::GetSenderCallConfig();
|
2015-03-26 11:11:06 +01:00
|
|
|
config.bitrate_config.start_bitrate_bps = kStartBitrateBps;
|
2014-11-25 09:39:04 +00:00
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 23:45:26 -07:00
|
|
|
// This test use other VideoStream settings than the the default settings
|
|
|
|
|
// implemented in DefaultVideoStreamFactory. Therefore this test implement
|
|
|
|
|
// its own VideoEncoderConfig::VideoStreamFactoryInterface which is created
|
|
|
|
|
// in ModifyVideoConfigs.
|
|
|
|
|
class VideoStreamFactory
|
|
|
|
|
: public VideoEncoderConfig::VideoStreamFactoryInterface {
|
|
|
|
|
public:
|
|
|
|
|
VideoStreamFactory() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::vector<VideoStream> CreateEncoderStreams(
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
const VideoEncoderConfig& encoder_config) override {
|
|
|
|
|
std::vector<VideoStream> streams =
|
|
|
|
|
test::CreateVideoStreams(width, height, encoder_config);
|
|
|
|
|
// Set low simulcast bitrates to not have to wait for bandwidth ramp-up.
|
|
|
|
|
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
|
|
|
|
streams[i].min_bitrate_bps = 10000;
|
|
|
|
|
streams[i].target_bitrate_bps = 15000;
|
|
|
|
|
streams[i].max_bitrate_bps = 20000;
|
|
|
|
|
}
|
|
|
|
|
return streams;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2016-10-02 23:45:26 -07:00
|
|
|
encoder_config->video_stream_factory =
|
|
|
|
|
new rtc::RefCountedObject<VideoStreamFactory>();
|
2014-06-27 08:47:52 +00:00
|
|
|
send_config->pre_encode_callback = this; // Used to inject delay.
|
2015-02-19 12:47:00 +00:00
|
|
|
expected_cname_ = send_config->rtp.c_name = "SomeCName";
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2016-07-13 09:11:28 -07:00
|
|
|
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
|
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
const std::vector<uint32_t>& ssrcs = send_config->rtp.ssrcs;
|
2015-02-19 12:47:00 +00:00
|
|
|
for (size_t i = 0; i < ssrcs.size(); ++i) {
|
2014-06-27 08:47:52 +00:00
|
|
|
expected_send_ssrcs_.insert(ssrcs[i]);
|
2015-02-19 12:47:00 +00:00
|
|
|
expected_receive_ssrcs_.push_back(
|
|
|
|
|
(*receive_configs)[i].rtp.remote_ssrc);
|
2015-05-27 17:59:11 +02:00
|
|
|
(*receive_configs)[i].render_delay_ms = kExpectedRenderDelayMs;
|
Reland of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #1 id:1 of https://codereview.webrtc.org/2084873002/ )
Reason for revert:
Reverting the revert. This change is not related to the failure on the Windows FYI bots. The cause of the failure has been reverted in Chromium:
https://codereview.chromium.org/2081653004/
Original issue's description:
> Revert of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #5 id:340001 of https://codereview.webrtc.org/2078873002/ )
>
> Reason for revert:
> Breaks chromium.webrtc.fyi
>
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win7%20Tester/builds/4719
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win10%20Tester/builds/3120
>
> Original issue's description:
> > Reland of IncomingVideoStream refactoring.
> > This reland does not contain the non-smoothing part of the original implementation. Instead, when smoothing is turned off, frame callbacks run on the decoder thread, as they did before. This code path is used in Chrome. As far as Chrome goes, the difference now is that there won't be an instance of IncomingVideoStream in between the decoder and the callback (i.e. fewer locks). Other than that, no change for Chrome.
> >
> > Original issue's description (with non-smoothing references removed):
> >
> > Split IncomingVideoStream into two implementations, with smoothing and without.
> >
> > * Added TODOs and documentation for VideoReceiveStream::OnFrame, where we today grab 6 locks.
> >
> > * Removed the Start/Stop methods from the IncomingVideoStream implementations. Now, when an instance is created, it should be considered to be "running" and when it is deleted, it's "not running". This saves on resources and also reduces the amount of locking required and I could remove one critical section altogether.
> >
> > * Changed the VideoStreamDecoder class to not depend on IncomingVideoStream but rather use the generic rtc::VideoSinkInterface<VideoFrame> interface. This means that any implementation of that interface can be used and the decoder can be made to just use the 'renderer' from the config. Once we do that, we can decouple the IncomingVideoStream implementations from the decoder and VideoReceiveStream implementations and leave it up to the application for how to do smoothing. The app can choose to use the Incoming* classes or roll its own (which may be preferable since applications often have their own scheduling mechanisms).
> >
> > * The lifetime of the VideoStreamDecoder instance is now bound to Start/Stop in VideoReceiveStream and not all of the lifetime of VideoReceiveStream.
> >
> > * Fixed VideoStreamDecoder to unregister callbacks in the dtor that were registered in the ctor. (this was open to a use-after-free regression)
> >
> > * Delay and callback pointers are now passed via the ctors to the IncomingVideoStream classes. The thread primitives in the IncomingVideoStream classes are also constructed/destructed at the same time as the owning object, which allowed me to remove one more lock.
> >
> > * Removed code in the VideoStreamDecoder that could overwrite the VideoReceiveStream render delay with a fixed value of 10ms on construction. This wasn't a problem with the previous implementation (it would be now though) but seemed to me like the wrong place to be setting that value.
> >
> > * Made the render delay value in VideoRenderFrames, const.
> >
> > BUG=chromium:620232
> > R=mflodman@webrtc.org, nisse@webrtc.org
> >
> > Committed: https://crrev.com/884c336c345d988974c2a69cea402b0fb8b07a63
> > Cr-Commit-Position: refs/heads/master@{#13219}
>
> TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,tommi@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=chromium:620232
>
> Committed: https://crrev.com/a536bfe70de38fe877245317a7f0b00bcf69cbd0
> Cr-Commit-Position: refs/heads/master@{#13229}
TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,sakal@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:620232
Review-Url: https://codereview.webrtc.org/2089613002
Cr-Commit-Position: refs/heads/master@{#13230}
2016-06-21 00:26:43 -07:00
|
|
|
(*receive_configs)[i].renderer = &receive_stream_renderer_;
|
2016-07-13 09:11:28 -07:00
|
|
|
(*receive_configs)[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
|
Reland of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #1 id:1 of https://codereview.webrtc.org/2649323010/ )
Reason for revert:
Downstream project relied on changed struct.
Transition made possible by https://codereview.webrtc.org/2655243006/.
Original issue's description:
> Revert of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #7 id:160001 of https://codereview.webrtc.org/2646073004/ )
>
> Reason for revert:
> Breaks internal downstream project.
>
> Original issue's description:
> > Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters.
> >
> > Prior to this CL, received RTX (associated) payload types were only configured
> > when WebRtcVideoChannel2::AddRecvStream was called. In the same method, the RTX
> > SSRC was set up.
> >
> > After this CL, the RTX (associated) payload types are set in
> > WebRtcVideoChannel2::SetRecvParameters, which is the appropriate place to set
> > them. The RTX SSRC is still set in WebRtcVideoChannel2::AddRecvStream, since
> > that is the code path that sets other SSRCs.
> >
> > As part of this fix, the VideoReceiveStream::Config::Rtp struct is changed.
> > We remove the possibility for each video payload type to have an associated
> > specific RTX SSRC. Although the config previously allowed for this, all payload
> > types always had the same RTX SSRC set, and the underlying RtpPayloadRegistry
> > did not support multiple SSRCs. This change to the config struct should thus not
> > have any functional impact. The change does however affect the RtcEventLog, since
> > that is used for storing the VideoReceiveStream::Configs. For simplicity,
> > this CL does not change the event log proto definitions, instead duplicating
> > the serialized RTX SSRCs such that they fit in the existing proto definition.
> >
> > BUG=webrtc:7011
> >
> > Review-Url: https://codereview.webrtc.org/2646073004
> > Cr-Commit-Position: refs/heads/master@{#16302}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/fe2bef39cd2a5c891a49f7320514fb04324dc66c
>
> TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,brandtr@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:7011
>
> Review-Url: https://codereview.webrtc.org/2649323010
> Cr-Commit-Position: refs/heads/master@{#16307}
> Committed: https://chromium.googlesource.com/external/webrtc/+/e4974953ce0d03a60fae7659b199a6a62a79fa30
TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,kjellander@webrtc.org,kjellander@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
# NOTREECHECKS=true
# NOTRY=true
BUG=webrtc:7011
Review-Url: https://codereview.webrtc.org/2654163006
Cr-Commit-Position: refs/heads/master@{#16322}
2017-01-27 04:53:07 -08:00
|
|
|
(*receive_configs)[i].rtp.rtx_ssrc = kSendRtxSsrcs[i];
|
2017-08-25 04:44:25 -07:00
|
|
|
(*receive_configs)[i]
|
|
|
|
|
.rtp.rtx_associated_payload_types[kSendRtxPayloadType] =
|
|
|
|
|
kFakeVideoSendPayloadType;
|
2015-02-19 12:47:00 +00:00
|
|
|
}
|
2016-07-13 09:11:28 -07:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < kNumSsrcs; ++i)
|
|
|
|
|
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]);
|
|
|
|
|
|
2016-02-05 14:15:53 +01:00
|
|
|
// Use a delayed encoder to make sure we see CpuOveruseMetrics stats that
|
|
|
|
|
// are non-zero.
|
|
|
|
|
send_config->encoder_settings.encoder = &encoder_;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2016-01-07 17:43:18 +01:00
|
|
|
size_t GetNumVideoStreams() const override { return kNumSsrcs; }
|
2014-11-14 11:52:04 +00:00
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void OnVideoStreamsCreated(
|
2014-06-30 13:19:09 +00:00
|
|
|
VideoSendStream* send_stream,
|
2015-02-09 15:14:36 +00:00
|
|
|
const std::vector<VideoReceiveStream*>& receive_streams) override {
|
2014-06-27 08:47:52 +00:00
|
|
|
send_stream_ = send_stream;
|
2015-02-19 12:47:00 +00:00
|
|
|
receive_streams_ = receive_streams;
|
2014-06-27 08:47:52 +00:00
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2014-06-27 08:47:52 +00:00
|
|
|
Clock* clock = Clock::GetRealTimeClock();
|
|
|
|
|
int64_t now = clock->TimeInMilliseconds();
|
|
|
|
|
int64_t stop_time = now + test::CallTest::kLongTimeoutMs;
|
|
|
|
|
bool receive_ok = false;
|
|
|
|
|
bool send_ok = false;
|
|
|
|
|
|
|
|
|
|
while (now < stop_time) {
|
|
|
|
|
if (!receive_ok)
|
|
|
|
|
receive_ok = CheckReceiveStats();
|
|
|
|
|
if (!send_ok)
|
|
|
|
|
send_ok = CheckSendStats();
|
|
|
|
|
|
|
|
|
|
if (receive_ok && send_ok)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int64_t time_until_timout_ = stop_time - now;
|
|
|
|
|
if (time_until_timout_ > 0)
|
2015-12-10 13:02:50 +01:00
|
|
|
check_stats_event_.Wait(time_until_timout_);
|
2014-06-27 08:47:52 +00:00
|
|
|
now = clock->TimeInMilliseconds();
|
|
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
ADD_FAILURE() << "Timed out waiting for filled stats.";
|
|
|
|
|
for (std::map<std::string, bool>::const_iterator it =
|
|
|
|
|
receive_stats_filled_.begin();
|
2017-08-22 04:02:52 -07:00
|
|
|
it != receive_stats_filled_.end(); ++it) {
|
2014-06-27 08:47:52 +00:00
|
|
|
if (!it->second) {
|
|
|
|
|
ADD_FAILURE() << "Missing receive stats: " << it->first;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
for (std::map<std::string, bool>::const_iterator it =
|
|
|
|
|
send_stats_filled_.begin();
|
2017-08-22 04:02:52 -07:00
|
|
|
it != send_stats_filled_.end(); ++it) {
|
2014-06-27 08:47:52 +00:00
|
|
|
if (!it->second) {
|
|
|
|
|
ADD_FAILURE() << "Missing send stats: " << it->first;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2016-02-05 14:15:53 +01:00
|
|
|
test::DelayedEncoder encoder_;
|
2015-02-19 12:47:00 +00:00
|
|
|
std::vector<VideoReceiveStream*> receive_streams_;
|
2014-06-27 08:47:52 +00:00
|
|
|
std::map<std::string, bool> receive_stats_filled_;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
VideoSendStream* send_stream_;
|
|
|
|
|
std::map<std::string, bool> send_stats_filled_;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2015-02-19 12:47:00 +00:00
|
|
|
std::vector<uint32_t> expected_receive_ssrcs_;
|
2014-06-27 08:47:52 +00:00
|
|
|
std::set<uint32_t> expected_send_ssrcs_;
|
|
|
|
|
std::string expected_cname_;
|
2014-02-07 12:06:29 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event check_stats_event_;
|
Reland of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #1 id:1 of https://codereview.webrtc.org/2084873002/ )
Reason for revert:
Reverting the revert. This change is not related to the failure on the Windows FYI bots. The cause of the failure has been reverted in Chromium:
https://codereview.chromium.org/2081653004/
Original issue's description:
> Revert of Split IncomingVideoStream into two implementations, with smoothing and without. (patchset #5 id:340001 of https://codereview.webrtc.org/2078873002/ )
>
> Reason for revert:
> Breaks chromium.webrtc.fyi
>
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win7%20Tester/builds/4719
> https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win10%20Tester/builds/3120
>
> Original issue's description:
> > Reland of IncomingVideoStream refactoring.
> > This reland does not contain the non-smoothing part of the original implementation. Instead, when smoothing is turned off, frame callbacks run on the decoder thread, as they did before. This code path is used in Chrome. As far as Chrome goes, the difference now is that there won't be an instance of IncomingVideoStream in between the decoder and the callback (i.e. fewer locks). Other than that, no change for Chrome.
> >
> > Original issue's description (with non-smoothing references removed):
> >
> > Split IncomingVideoStream into two implementations, with smoothing and without.
> >
> > * Added TODOs and documentation for VideoReceiveStream::OnFrame, where we today grab 6 locks.
> >
> > * Removed the Start/Stop methods from the IncomingVideoStream implementations. Now, when an instance is created, it should be considered to be "running" and when it is deleted, it's "not running". This saves on resources and also reduces the amount of locking required and I could remove one critical section altogether.
> >
> > * Changed the VideoStreamDecoder class to not depend on IncomingVideoStream but rather use the generic rtc::VideoSinkInterface<VideoFrame> interface. This means that any implementation of that interface can be used and the decoder can be made to just use the 'renderer' from the config. Once we do that, we can decouple the IncomingVideoStream implementations from the decoder and VideoReceiveStream implementations and leave it up to the application for how to do smoothing. The app can choose to use the Incoming* classes or roll its own (which may be preferable since applications often have their own scheduling mechanisms).
> >
> > * The lifetime of the VideoStreamDecoder instance is now bound to Start/Stop in VideoReceiveStream and not all of the lifetime of VideoReceiveStream.
> >
> > * Fixed VideoStreamDecoder to unregister callbacks in the dtor that were registered in the ctor. (this was open to a use-after-free regression)
> >
> > * Delay and callback pointers are now passed via the ctors to the IncomingVideoStream classes. The thread primitives in the IncomingVideoStream classes are also constructed/destructed at the same time as the owning object, which allowed me to remove one more lock.
> >
> > * Removed code in the VideoStreamDecoder that could overwrite the VideoReceiveStream render delay with a fixed value of 10ms on construction. This wasn't a problem with the previous implementation (it would be now though) but seemed to me like the wrong place to be setting that value.
> >
> > * Made the render delay value in VideoRenderFrames, const.
> >
> > BUG=chromium:620232
> > R=mflodman@webrtc.org, nisse@webrtc.org
> >
> > Committed: https://crrev.com/884c336c345d988974c2a69cea402b0fb8b07a63
> > Cr-Commit-Position: refs/heads/master@{#13219}
>
> TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,tommi@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=chromium:620232
>
> Committed: https://crrev.com/a536bfe70de38fe877245317a7f0b00bcf69cbd0
> Cr-Commit-Position: refs/heads/master@{#13229}
TBR=nisse@webrtc.org,philipel@webrtc.org,mflodman@webrtc.org,sakal@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=chromium:620232
Review-Url: https://codereview.webrtc.org/2089613002
Cr-Commit-Position: refs/heads/master@{#13230}
2016-06-21 00:26:43 -07:00
|
|
|
ReceiveStreamRenderer receive_stream_renderer_;
|
2015-10-27 08:29:42 -07:00
|
|
|
} test;
|
2015-02-19 12:47:00 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-02-07 12:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TimingFramesAreReported) {
|
2017-07-06 03:06:50 -07:00
|
|
|
static const int kExtensionId = 5;
|
|
|
|
|
|
|
|
|
|
class StatsObserver : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
StatsObserver() : EndToEndTest(kLongTimeoutMs) {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
|
|
|
|
send_config->rtp.extensions.clear();
|
|
|
|
|
send_config->rtp.extensions.push_back(
|
|
|
|
|
RtpExtension(RtpExtension::kVideoTimingUri, kExtensionId));
|
|
|
|
|
for (size_t i = 0; i < receive_configs->size(); ++i) {
|
|
|
|
|
(*receive_configs)[i].rtp.extensions.clear();
|
|
|
|
|
(*receive_configs)[i].rtp.extensions.push_back(
|
|
|
|
|
RtpExtension(RtpExtension::kVideoTimingUri, kExtensionId));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnVideoStreamsCreated(
|
|
|
|
|
VideoSendStream* send_stream,
|
|
|
|
|
const std::vector<VideoReceiveStream*>& receive_streams) override {
|
|
|
|
|
receive_streams_ = receive_streams;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
// No frames reported initially.
|
|
|
|
|
for (size_t i = 0; i < receive_streams_.size(); ++i) {
|
2017-09-04 03:35:40 -07:00
|
|
|
EXPECT_FALSE(receive_streams_[i]->GetStats().timing_frame_info);
|
2017-07-06 03:06:50 -07:00
|
|
|
}
|
|
|
|
|
// Wait for at least one timing frame to be sent with 100ms grace period.
|
|
|
|
|
SleepMs(kDefaultTimingFramesDelayMs + 100);
|
|
|
|
|
// Check that timing frames are reported for each stream.
|
|
|
|
|
for (size_t i = 0; i < receive_streams_.size(); ++i) {
|
2017-09-04 03:35:40 -07:00
|
|
|
EXPECT_TRUE(receive_streams_[i]->GetStats().timing_frame_info);
|
2017-07-06 03:06:50 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<VideoReceiveStream*> receive_streams_;
|
|
|
|
|
} test;
|
|
|
|
|
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-01 06:34:11 -08:00
|
|
|
class RtcpXrObserver : public test::EndToEndTest {
|
|
|
|
|
public:
|
2017-11-15 14:58:23 +01:00
|
|
|
RtcpXrObserver(bool enable_rrtr, bool enable_target_bitrate,
|
|
|
|
|
bool enable_zero_target_bitrate)
|
2016-12-01 06:34:11 -08:00
|
|
|
: EndToEndTest(test::CallTest::kDefaultTimeoutMs),
|
|
|
|
|
enable_rrtr_(enable_rrtr),
|
2017-01-13 07:30:25 -08:00
|
|
|
enable_target_bitrate_(enable_target_bitrate),
|
2017-11-15 14:58:23 +01:00
|
|
|
enable_zero_target_bitrate_(enable_zero_target_bitrate),
|
2016-12-01 06:34:11 -08:00
|
|
|
sent_rtcp_sr_(0),
|
|
|
|
|
sent_rtcp_rr_(0),
|
|
|
|
|
sent_rtcp_rrtr_(0),
|
|
|
|
|
sent_rtcp_target_bitrate_(false),
|
2017-11-15 14:58:23 +01:00
|
|
|
sent_zero_rtcp_target_bitrate_(false),
|
2016-12-01 06:34:11 -08:00
|
|
|
sent_rtcp_dlrr_(0) {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// Receive stream should send RR packets (and RRTR packets if enabled).
|
|
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
|
|
|
|
|
|
sent_rtcp_rr_ += parser.receiver_report()->num_packets();
|
|
|
|
|
EXPECT_EQ(0, parser.sender_report()->num_packets());
|
|
|
|
|
EXPECT_GE(1, parser.xr()->num_packets());
|
|
|
|
|
if (parser.xr()->num_packets() > 0) {
|
|
|
|
|
if (parser.xr()->rrtr())
|
|
|
|
|
++sent_rtcp_rrtr_;
|
|
|
|
|
EXPECT_FALSE(parser.xr()->dlrr());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
// Send stream should send SR packets (and DLRR packets if enabled).
|
|
|
|
|
Action OnSendRtcp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
test::RtcpPacketParser parser;
|
|
|
|
|
EXPECT_TRUE(parser.Parse(packet, length));
|
|
|
|
|
|
|
|
|
|
sent_rtcp_sr_ += parser.sender_report()->num_packets();
|
|
|
|
|
EXPECT_LE(parser.xr()->num_packets(), 1);
|
|
|
|
|
if (parser.xr()->num_packets() > 0) {
|
|
|
|
|
EXPECT_FALSE(parser.xr()->rrtr());
|
|
|
|
|
if (parser.xr()->dlrr())
|
|
|
|
|
++sent_rtcp_dlrr_;
|
2017-11-15 14:58:23 +01:00
|
|
|
if (parser.xr()->target_bitrate()) {
|
2016-12-01 06:34:11 -08:00
|
|
|
sent_rtcp_target_bitrate_ = true;
|
2017-11-15 14:58:23 +01:00
|
|
|
for (const rtcp::TargetBitrate::BitrateItem& item :
|
|
|
|
|
parser.xr()->target_bitrate()->GetTargetBitrates()) {
|
|
|
|
|
if (item.target_bitrate_kbps == 0) {
|
|
|
|
|
sent_zero_rtcp_target_bitrate_ = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-01 06:34:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sent_rtcp_sr_ > kNumRtcpReportPacketsToObserve &&
|
|
|
|
|
sent_rtcp_rr_ > kNumRtcpReportPacketsToObserve &&
|
2017-11-15 14:58:23 +01:00
|
|
|
(sent_rtcp_target_bitrate_ || !enable_target_bitrate_) &&
|
|
|
|
|
(sent_zero_rtcp_target_bitrate_ || !enable_zero_target_bitrate_)) {
|
2016-12-01 06:34:11 -08:00
|
|
|
if (enable_rrtr_) {
|
|
|
|
|
EXPECT_GT(sent_rtcp_rrtr_, 0);
|
|
|
|
|
EXPECT_GT(sent_rtcp_dlrr_, 0);
|
|
|
|
|
} else {
|
|
|
|
|
EXPECT_EQ(sent_rtcp_rrtr_, 0);
|
|
|
|
|
EXPECT_EQ(sent_rtcp_dlrr_, 0);
|
|
|
|
|
}
|
2017-01-13 07:30:25 -08:00
|
|
|
EXPECT_EQ(enable_target_bitrate_, sent_rtcp_target_bitrate_);
|
2017-11-15 14:58:23 +01:00
|
|
|
EXPECT_EQ(enable_zero_target_bitrate_, sent_zero_rtcp_target_bitrate_);
|
2016-12-01 06:34:11 -08:00
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-15 14:58:23 +01:00
|
|
|
size_t GetNumVideoStreams() const override {
|
|
|
|
|
// When sending a zero target bitrate, we use two spatial layers so that
|
|
|
|
|
// we'll still have a layer with non-zero bitrate.
|
|
|
|
|
return enable_zero_target_bitrate_ ? 2 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This test uses VideoStream settings different from the the default one
|
|
|
|
|
// implemented in DefaultVideoStreamFactory, so it implements its own
|
|
|
|
|
// VideoEncoderConfig::VideoStreamFactoryInterface which is created
|
|
|
|
|
// in ModifyVideoConfigs.
|
|
|
|
|
class ZeroTargetVideoStreamFactory
|
|
|
|
|
: public VideoEncoderConfig::VideoStreamFactoryInterface {
|
|
|
|
|
public:
|
|
|
|
|
ZeroTargetVideoStreamFactory() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::vector<VideoStream> CreateEncoderStreams(
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
const VideoEncoderConfig& encoder_config) override {
|
|
|
|
|
std::vector<VideoStream> streams =
|
|
|
|
|
test::CreateVideoStreams(width, height, encoder_config);
|
|
|
|
|
// Set one of the streams' target bitrates to zero to test that a
|
|
|
|
|
// bitrate of 0 can be signalled.
|
|
|
|
|
streams[encoder_config.number_of_streams-1].min_bitrate_bps = 0;
|
|
|
|
|
streams[encoder_config.number_of_streams-1].target_bitrate_bps = 0;
|
|
|
|
|
streams[encoder_config.number_of_streams-1].max_bitrate_bps = 0;
|
|
|
|
|
return streams;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-12-01 06:34:11 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2017-11-15 14:58:23 +01:00
|
|
|
if (enable_zero_target_bitrate_) {
|
|
|
|
|
encoder_config->video_stream_factory =
|
|
|
|
|
new rtc::RefCountedObject<ZeroTargetVideoStreamFactory>();
|
|
|
|
|
|
|
|
|
|
// Configure VP8 to be able to use simulcast.
|
|
|
|
|
send_config->encoder_settings.payload_name = "VP8";
|
|
|
|
|
(*receive_configs)[0].decoders.resize(1);
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_type =
|
|
|
|
|
send_config->encoder_settings.payload_type;
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_name =
|
|
|
|
|
send_config->encoder_settings.payload_name;
|
|
|
|
|
}
|
2017-01-13 07:30:25 -08:00
|
|
|
if (enable_target_bitrate_) {
|
|
|
|
|
// TargetBitrate only signaled for screensharing.
|
|
|
|
|
encoder_config->content_type = VideoEncoderConfig::ContentType::kScreen;
|
|
|
|
|
}
|
2016-12-01 06:34:11 -08:00
|
|
|
(*receive_configs)[0].rtp.rtcp_mode = RtcpMode::kReducedSize;
|
|
|
|
|
(*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report =
|
|
|
|
|
enable_rrtr_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
EXPECT_TRUE(Wait())
|
|
|
|
|
<< "Timed out while waiting for RTCP SR/RR packets to be sent.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const int kNumRtcpReportPacketsToObserve = 5;
|
|
|
|
|
|
|
|
|
|
rtc::CriticalSection crit_;
|
2017-01-13 07:30:25 -08:00
|
|
|
const bool enable_rrtr_;
|
|
|
|
|
const bool enable_target_bitrate_;
|
2017-11-15 14:58:23 +01:00
|
|
|
const bool enable_zero_target_bitrate_;
|
2016-12-01 06:34:11 -08:00
|
|
|
int sent_rtcp_sr_;
|
2017-09-09 04:17:22 -07:00
|
|
|
int sent_rtcp_rr_ RTC_GUARDED_BY(&crit_);
|
|
|
|
|
int sent_rtcp_rrtr_ RTC_GUARDED_BY(&crit_);
|
|
|
|
|
bool sent_rtcp_target_bitrate_ RTC_GUARDED_BY(&crit_);
|
2017-11-15 14:58:23 +01:00
|
|
|
bool sent_zero_rtcp_target_bitrate_ RTC_GUARDED_BY(&crit_);
|
2016-12-01 06:34:11 -08:00
|
|
|
int sent_rtcp_dlrr_;
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TestExtendedReportsWithRrtrWithoutTargetBitrate) {
|
2017-11-15 14:58:23 +01:00
|
|
|
RtcpXrObserver test(/*enable_rrtr=*/true, /*enable_target_bitrate=*/false,
|
|
|
|
|
/*enable_zero_target_bitrate=*/false);
|
2017-01-13 07:30:25 -08:00
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TestExtendedReportsWithoutRrtrWithoutTargetBitrate) {
|
2017-11-15 14:58:23 +01:00
|
|
|
RtcpXrObserver test(/*enable_rrtr=*/false, /*enable_target_bitrate=*/false,
|
|
|
|
|
/*enable_zero_target_bitrate=*/false);
|
2017-01-13 07:30:25 -08:00
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TestExtendedReportsWithRrtrWithTargetBitrate) {
|
2017-11-15 14:58:23 +01:00
|
|
|
RtcpXrObserver test(/*enable_rrtr=*/true, /*enable_target_bitrate=*/true,
|
|
|
|
|
/*enable_zero_target_bitrate=*/false);
|
2016-12-01 06:34:11 -08:00
|
|
|
RunBaseTest(&test);
|
2014-01-20 08:34:49 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TestExtendedReportsWithoutRrtrWithTargetBitrate) {
|
2017-11-15 14:58:23 +01:00
|
|
|
RtcpXrObserver test(/*enable_rrtr=*/false, /*enable_target_bitrate=*/true,
|
|
|
|
|
/*enable_zero_target_bitrate=*/false);
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_P(EndToEndTest, TestExtendedReportsCanSignalZeroTargetBitrate) {
|
|
|
|
|
RtcpXrObserver test(/*enable_rrtr=*/false, /*enable_target_bitrate=*/true,
|
|
|
|
|
/*enable_zero_target_bitrate=*/true);
|
2016-12-01 06:34:11 -08:00
|
|
|
RunBaseTest(&test);
|
2014-01-20 08:34:49 +00:00
|
|
|
}
|
2014-03-13 12:52:27 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TestReceivedRtpPacketStats) {
|
2014-05-26 13:06:04 +00:00
|
|
|
static const size_t kNumRtpPacketsToSend = 5;
|
2014-06-27 08:47:52 +00:00
|
|
|
class ReceivedRtpStatsObserver : public test::EndToEndTest {
|
2014-05-26 13:06:04 +00:00
|
|
|
public:
|
|
|
|
|
ReceivedRtpStatsObserver()
|
2014-06-27 08:47:52 +00:00
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
2015-03-23 13:12:24 +00:00
|
|
|
receive_stream_(nullptr),
|
2014-05-26 13:06:04 +00:00
|
|
|
sent_rtp_(0) {}
|
|
|
|
|
|
2014-06-27 08:47:52 +00:00
|
|
|
private:
|
2015-12-21 03:14:00 -08:00
|
|
|
void OnVideoStreamsCreated(
|
2014-06-30 13:19:09 +00:00
|
|
|
VideoSendStream* send_stream,
|
2015-02-09 15:14:36 +00:00
|
|
|
const std::vector<VideoReceiveStream*>& receive_streams) override {
|
2014-06-30 13:19:09 +00:00
|
|
|
receive_stream_ = receive_streams[0];
|
2014-05-26 13:06:04 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2014-05-26 13:06:04 +00:00
|
|
|
if (sent_rtp_ >= kNumRtpPacketsToSend) {
|
|
|
|
|
VideoReceiveStream::Stats stats = receive_stream_->GetStats();
|
2015-01-22 09:39:59 +00:00
|
|
|
if (kNumRtpPacketsToSend == stats.rtp_stats.transmitted.packets) {
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2014-05-26 13:06:04 +00:00
|
|
|
}
|
|
|
|
|
return DROP_PACKET;
|
|
|
|
|
}
|
|
|
|
|
++sent_rtp_;
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2014-06-27 08:47:52 +00:00
|
|
|
<< "Timed out while verifying number of received RTP packets.";
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-26 13:06:04 +00:00
|
|
|
VideoReceiveStream* receive_stream_;
|
|
|
|
|
uint32_t sent_rtp_;
|
2014-06-27 08:47:52 +00:00
|
|
|
} test;
|
2014-05-26 13:06:04 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-05-26 13:06:04 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, SendsSetSsrc) {
|
2016-11-28 08:49:07 -08:00
|
|
|
TestSendsSetSsrcs(1, false);
|
|
|
|
|
}
|
2014-06-30 13:19:09 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, SendsSetSimulcastSsrcs) {
|
2014-06-30 13:19:09 +00:00
|
|
|
TestSendsSetSsrcs(kNumSsrcs, false);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, CanSwitchToUseAllSsrcs) {
|
2014-06-30 13:19:09 +00:00
|
|
|
TestSendsSetSsrcs(kNumSsrcs, true);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DISABLED_RedundantPayloadsTransmittedOnAllSsrcs) {
|
2014-07-04 10:58:12 +00:00
|
|
|
class ObserveRedundantPayloads: public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
ObserveRedundantPayloads()
|
|
|
|
|
: EndToEndTest(kDefaultTimeoutMs), ssrcs_to_observe_(kNumSsrcs) {
|
2014-08-05 23:35:43 +00:00
|
|
|
for (size_t i = 0; i < kNumSsrcs; ++i) {
|
2014-07-04 10:58:12 +00:00
|
|
|
registered_rtx_ssrc_[kSendRtxSsrcs[i]] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2014-07-04 10:58:12 +00:00
|
|
|
RTPHeader header;
|
2014-07-08 12:10:51 +00:00
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
2014-07-04 10:58:12 +00:00
|
|
|
|
|
|
|
|
if (!registered_rtx_ssrc_[header.ssrc])
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
EXPECT_LE(header.headerLength + header.paddingLength, length);
|
2014-07-04 10:58:12 +00:00
|
|
|
const bool packet_is_redundant_payload =
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
header.headerLength + header.paddingLength < length;
|
2014-07-04 10:58:12 +00:00
|
|
|
|
|
|
|
|
if (!packet_is_redundant_payload)
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
|
|
|
|
|
if (!observed_redundant_retransmission_[header.ssrc]) {
|
|
|
|
|
observed_redundant_retransmission_[header.ssrc] = true;
|
|
|
|
|
if (--ssrcs_to_observe_ == 0)
|
2015-12-10 13:02:50 +01:00
|
|
|
observation_complete_.Set();
|
2014-07-04 10:58:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-07 17:43:18 +01:00
|
|
|
size_t GetNumVideoStreams() const override { return kNumSsrcs; }
|
2014-07-04 10:58:12 +00:00
|
|
|
|
2016-10-02 23:45:26 -07:00
|
|
|
// This test use other VideoStream settings than the the default settings
|
|
|
|
|
// implemented in DefaultVideoStreamFactory. Therefore this test implement
|
|
|
|
|
// its own VideoEncoderConfig::VideoStreamFactoryInterface which is created
|
|
|
|
|
// in ModifyVideoConfigs.
|
|
|
|
|
class VideoStreamFactory
|
|
|
|
|
: public VideoEncoderConfig::VideoStreamFactoryInterface {
|
|
|
|
|
public:
|
|
|
|
|
VideoStreamFactory() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::vector<VideoStream> CreateEncoderStreams(
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
const VideoEncoderConfig& encoder_config) override {
|
|
|
|
|
std::vector<VideoStream> streams =
|
|
|
|
|
test::CreateVideoStreams(width, height, encoder_config);
|
|
|
|
|
// Set low simulcast bitrates to not have to wait for bandwidth ramp-up.
|
|
|
|
|
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
|
|
|
|
streams[i].min_bitrate_bps = 10000;
|
|
|
|
|
streams[i].target_bitrate_bps = 15000;
|
|
|
|
|
streams[i].max_bitrate_bps = 20000;
|
|
|
|
|
}
|
|
|
|
|
return streams;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2014-07-04 10:58:12 +00:00
|
|
|
// Set low simulcast bitrates to not have to wait for bandwidth ramp-up.
|
2016-10-02 23:45:26 -07:00
|
|
|
encoder_config->video_stream_factory =
|
|
|
|
|
new rtc::RefCountedObject<VideoStreamFactory>();
|
2014-07-04 10:58:12 +00:00
|
|
|
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < kNumSsrcs; ++i)
|
|
|
|
|
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]);
|
2014-10-24 09:23:21 +00:00
|
|
|
|
|
|
|
|
// Significantly higher than max bitrates for all video streams -> forcing
|
|
|
|
|
// padding to trigger redundant padding on all RTX SSRCs.
|
|
|
|
|
encoder_config->min_transmit_bitrate_bps = 100000;
|
2014-07-04 10:58:12 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(Wait())
|
2014-07-04 10:58:12 +00:00
|
|
|
<< "Timed out while waiting for redundant payloads on all SSRCs.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
size_t ssrcs_to_observe_;
|
|
|
|
|
std::map<uint32_t, bool> observed_redundant_retransmission_;
|
|
|
|
|
std::map<uint32_t, bool> registered_rtx_ssrc_;
|
|
|
|
|
} test;
|
|
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-07-04 10:58:12 +00:00
|
|
|
}
|
|
|
|
|
|
2016-07-20 15:26:59 +02:00
|
|
|
void EndToEndTest::TestRtpStatePreservation(bool use_rtx,
|
|
|
|
|
bool provoke_rtcpsr_before_rtp) {
|
Reland of use allocated encoders in SimulcastEncoderAdapter. (patchset #1 id:1 of https://codereview.webrtc.org/2893003002/ )
Reason for reland:
Chrome encoder implementation fixed.
Original issue's description:
> Revert of Reuse allocated encoders in SimulcastEncoderAdapter. (patchset #15 id:320001 of https://codereview.webrtc.org/2830793005/ )
>
> Reason for revert:
> Breaks Chrome tests.
>
> Original issue's description:
> > Reuse allocated encoders in SimulcastEncoderAdapter.
> >
> > Prior to this change, the SimulcastEncoderAdapter would destroy and create
> > encoders whenever it is being reinitialized. After this change, the
> > SimulcastEncoderAdapter will cache the already allocated encoders, and reuse
> > them after reinitialization.
> >
> > This change will help in reducing the number of PictureID "jumps" that have
> > been seen around encoder reinitialization.
> >
> > TESTED=AppRTCMobile, Chrome desktop, and internal app, with forced encoder reinits every 30 frames and https://codereview.webrtc.org/2833493003/ applied.
> > BUG=webrtc:7475
> >
> > Review-Url: https://codereview.webrtc.org/2830793005
> > Cr-Commit-Position: refs/heads/master@{#18215}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/0b8bfb9d98b7a2011d80bcdf3f430bc040370dad
>
> TBR=stefan@webrtc.org,noahric@chromium.org,glaznev@webrtc.org,sprang@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:7475
>
> Review-Url: https://codereview.webrtc.org/2893003002
> Cr-Commit-Position: refs/heads/master@{#18216}
> Committed: https://chromium.googlesource.com/external/webrtc/+/56e119e2e8b30d2d41c55c3a7983b077a5262718
TBR=stefan@webrtc.org,noahric@chromium.org,glaznev@webrtc.org,sprang@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7475
Review-Url: https://codereview.webrtc.org/2901493002
Cr-Commit-Position: refs/heads/master@{#18228}
2017-05-23 03:32:16 -07:00
|
|
|
// This test uses other VideoStream settings than the the default settings
|
|
|
|
|
// implemented in DefaultVideoStreamFactory. Therefore this test implements
|
2016-10-02 23:45:26 -07:00
|
|
|
// its own VideoEncoderConfig::VideoStreamFactoryInterface which is created
|
|
|
|
|
// in ModifyVideoConfigs.
|
|
|
|
|
class VideoStreamFactory
|
|
|
|
|
: public VideoEncoderConfig::VideoStreamFactoryInterface {
|
|
|
|
|
public:
|
|
|
|
|
VideoStreamFactory() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::vector<VideoStream> CreateEncoderStreams(
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
const VideoEncoderConfig& encoder_config) override {
|
|
|
|
|
std::vector<VideoStream> streams =
|
|
|
|
|
test::CreateVideoStreams(width, height, encoder_config);
|
|
|
|
|
|
|
|
|
|
if (encoder_config.number_of_streams > 1) {
|
|
|
|
|
// Lower bitrates so that all streams send initially.
|
2016-11-28 15:21:39 -08:00
|
|
|
RTC_DCHECK_EQ(3, encoder_config.number_of_streams);
|
2016-10-02 23:45:26 -07:00
|
|
|
for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
|
|
|
|
|
streams[i].min_bitrate_bps = 10000;
|
|
|
|
|
streams[i].target_bitrate_bps = 15000;
|
|
|
|
|
streams[i].max_bitrate_bps = 20000;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Use the same total bitrates when sending a single stream to avoid
|
|
|
|
|
// lowering
|
|
|
|
|
// the bitrate estimate and requiring a subsequent rampup.
|
|
|
|
|
streams[0].min_bitrate_bps = 3 * 10000;
|
|
|
|
|
streams[0].target_bitrate_bps = 3 * 15000;
|
|
|
|
|
streams[0].max_bitrate_bps = 3 * 20000;
|
|
|
|
|
}
|
|
|
|
|
return streams;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-07-07 13:06:48 +00:00
|
|
|
class RtpSequenceObserver : public test::RtpRtcpObserver {
|
|
|
|
|
public:
|
2014-08-05 23:35:43 +00:00
|
|
|
explicit RtpSequenceObserver(bool use_rtx)
|
2014-07-07 13:06:48 +00:00
|
|
|
: test::RtpRtcpObserver(kDefaultTimeoutMs),
|
|
|
|
|
ssrcs_to_observe_(kNumSsrcs) {
|
|
|
|
|
for (size_t i = 0; i < kNumSsrcs; ++i) {
|
2016-08-01 06:58:34 -07:00
|
|
|
ssrc_is_rtx_[kVideoSendSsrcs[i]] = false;
|
2014-07-07 13:06:48 +00:00
|
|
|
if (use_rtx)
|
2016-08-01 06:58:34 -07:00
|
|
|
ssrc_is_rtx_[kSendRtxSsrcs[i]] = true;
|
2014-07-07 13:06:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResetExpectedSsrcs(size_t num_expected_ssrcs) {
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&crit_);
|
2016-02-01 08:25:04 -08:00
|
|
|
ssrc_observed_.clear();
|
2014-07-07 13:06:48 +00:00
|
|
|
ssrcs_to_observe_ = num_expected_ssrcs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-07-20 15:26:59 +02:00
|
|
|
void ValidateTimestampGap(uint32_t ssrc,
|
|
|
|
|
uint32_t timestamp,
|
|
|
|
|
bool only_padding)
|
2017-09-09 04:17:22 -07:00
|
|
|
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_) {
|
2016-07-20 15:26:59 +02:00
|
|
|
static const int32_t kMaxTimestampGap = kDefaultTimeoutMs * 90;
|
|
|
|
|
auto timestamp_it = last_observed_timestamp_.find(ssrc);
|
|
|
|
|
if (timestamp_it == last_observed_timestamp_.end()) {
|
|
|
|
|
EXPECT_FALSE(only_padding);
|
|
|
|
|
last_observed_timestamp_[ssrc] = timestamp;
|
|
|
|
|
} else {
|
|
|
|
|
// Verify timestamps are reasonably close.
|
|
|
|
|
uint32_t latest_observed = timestamp_it->second;
|
|
|
|
|
// Wraparound handling is unnecessary here as long as an int variable
|
|
|
|
|
// is used to store the result.
|
|
|
|
|
int32_t timestamp_gap = timestamp - latest_observed;
|
|
|
|
|
EXPECT_LE(std::abs(timestamp_gap), kMaxTimestampGap)
|
|
|
|
|
<< "Gap in timestamps (" << latest_observed << " -> " << timestamp
|
|
|
|
|
<< ") too large for SSRC: " << ssrc << ".";
|
|
|
|
|
timestamp_it->second = timestamp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2014-07-07 13:06:48 +00:00
|
|
|
RTPHeader header;
|
2014-07-08 12:10:51 +00:00
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
2014-07-07 13:06:48 +00:00
|
|
|
const uint32_t ssrc = header.ssrc;
|
2016-02-03 14:14:49 -08:00
|
|
|
const int64_t sequence_number =
|
|
|
|
|
seq_numbers_unwrapper_.Unwrap(header.sequenceNumber);
|
2014-07-07 13:06:48 +00:00
|
|
|
const uint32_t timestamp = header.timestamp;
|
2016-02-01 08:25:04 -08:00
|
|
|
const bool only_padding =
|
|
|
|
|
header.headerLength + header.paddingLength == length;
|
2014-07-07 13:06:48 +00:00
|
|
|
|
2016-08-01 06:58:34 -07:00
|
|
|
EXPECT_TRUE(ssrc_is_rtx_.find(ssrc) != ssrc_is_rtx_.end())
|
2014-07-07 13:06:48 +00:00
|
|
|
<< "Received SSRC that wasn't configured: " << ssrc;
|
|
|
|
|
|
2016-02-03 14:14:49 -08:00
|
|
|
static const int64_t kMaxSequenceNumberGap = 100;
|
|
|
|
|
std::list<int64_t>* seq_numbers = &last_observed_seq_numbers_[ssrc];
|
|
|
|
|
if (seq_numbers->empty()) {
|
|
|
|
|
seq_numbers->push_back(sequence_number);
|
2014-07-07 13:06:48 +00:00
|
|
|
} else {
|
2016-02-03 14:14:49 -08:00
|
|
|
// We shouldn't get replays of previous sequence numbers.
|
|
|
|
|
for (int64_t observed : *seq_numbers) {
|
|
|
|
|
EXPECT_NE(observed, sequence_number)
|
|
|
|
|
<< "Received sequence number " << sequence_number
|
|
|
|
|
<< " for SSRC " << ssrc << " 2nd time.";
|
|
|
|
|
}
|
2014-07-07 13:06:48 +00:00
|
|
|
// Verify sequence numbers are reasonably close.
|
2016-02-03 14:14:49 -08:00
|
|
|
int64_t latest_observed = seq_numbers->back();
|
|
|
|
|
int64_t sequence_number_gap = sequence_number - latest_observed;
|
|
|
|
|
EXPECT_LE(std::abs(sequence_number_gap), kMaxSequenceNumberGap)
|
|
|
|
|
<< "Gap in sequence numbers (" << latest_observed << " -> "
|
|
|
|
|
<< sequence_number << ") too large for SSRC: " << ssrc << ".";
|
|
|
|
|
seq_numbers->push_back(sequence_number);
|
|
|
|
|
if (seq_numbers->size() >= kMaxSequenceNumberGap) {
|
|
|
|
|
seq_numbers->pop_front();
|
2016-02-01 08:25:04 -08:00
|
|
|
}
|
2016-02-03 14:14:49 -08:00
|
|
|
}
|
|
|
|
|
|
2016-08-01 06:58:34 -07:00
|
|
|
if (!ssrc_is_rtx_[ssrc]) {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
ValidateTimestampGap(ssrc, timestamp, only_padding);
|
2016-07-20 15:26:59 +02:00
|
|
|
|
2016-08-01 06:58:34 -07:00
|
|
|
// Wait for media packets on all ssrcs.
|
|
|
|
|
if (!ssrc_observed_[ssrc] && !only_padding) {
|
|
|
|
|
ssrc_observed_[ssrc] = true;
|
|
|
|
|
if (--ssrcs_to_observe_ == 0)
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
2014-07-07 13:06:48 +00:00
|
|
|
}
|
2016-02-01 08:25:04 -08:00
|
|
|
|
2014-07-07 13:06:48 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-20 15:26:59 +02:00
|
|
|
Action OnSendRtcp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
test::RtcpPacketParser rtcp_parser;
|
|
|
|
|
rtcp_parser.Parse(packet, length);
|
|
|
|
|
if (rtcp_parser.sender_report()->num_packets() > 0) {
|
2016-09-02 18:29:10 +02:00
|
|
|
uint32_t ssrc = rtcp_parser.sender_report()->sender_ssrc();
|
|
|
|
|
uint32_t rtcp_timestamp = rtcp_parser.sender_report()->rtp_timestamp();
|
2016-07-20 15:26:59 +02:00
|
|
|
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
ValidateTimestampGap(ssrc, rtcp_timestamp, false);
|
|
|
|
|
}
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-03 14:14:49 -08:00
|
|
|
SequenceNumberUnwrapper seq_numbers_unwrapper_;
|
|
|
|
|
std::map<uint32_t, std::list<int64_t>> last_observed_seq_numbers_;
|
2016-02-01 08:25:04 -08:00
|
|
|
std::map<uint32_t, uint32_t> last_observed_timestamp_;
|
2016-08-01 06:58:34 -07:00
|
|
|
std::map<uint32_t, bool> ssrc_is_rtx_;
|
2014-07-07 13:06:48 +00:00
|
|
|
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CriticalSection crit_;
|
2017-09-09 04:17:22 -07:00
|
|
|
size_t ssrcs_to_observe_ RTC_GUARDED_BY(crit_);
|
|
|
|
|
std::map<uint32_t, bool> ssrc_observed_ RTC_GUARDED_BY(crit_);
|
2014-07-07 13:06:48 +00:00
|
|
|
} observer(use_rtx);
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::PacketTransport> send_transport;
|
|
|
|
|
std::unique_ptr<test::PacketTransport> receive_transport;
|
|
|
|
|
|
2017-04-10 03:54:05 -07:00
|
|
|
Call::Config config(event_log_.get());
|
2017-08-22 04:02:52 -07:00
|
|
|
VideoEncoderConfig one_stream;
|
2014-07-07 13:06:48 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &observer, &send_transport, &receive_transport,
|
|
|
|
|
&config, &one_stream, use_rtx]() {
|
|
|
|
|
CreateCalls(config, config);
|
2015-10-27 08:29:42 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
send_transport = rtc::MakeUnique<test::PacketTransport>(
|
|
|
|
|
&task_queue_, sender_call_.get(), &observer,
|
|
|
|
|
test::PacketTransport::kSender, payload_type_map_,
|
|
|
|
|
FakeNetworkPipe::Config());
|
|
|
|
|
receive_transport = rtc::MakeUnique<test::PacketTransport>(
|
|
|
|
|
&task_queue_, nullptr, &observer, test::PacketTransport::kReceiver,
|
|
|
|
|
payload_type_map_, FakeNetworkPipe::Config());
|
|
|
|
|
send_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
receive_transport->SetReceiver(sender_call_->Receiver());
|
2014-07-07 13:06:48 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateSendConfig(kNumSsrcs, 0, 0, send_transport.get());
|
|
|
|
|
|
|
|
|
|
if (use_rtx) {
|
|
|
|
|
for (size_t i = 0; i < kNumSsrcs; ++i) {
|
|
|
|
|
video_send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]);
|
|
|
|
|
}
|
|
|
|
|
video_send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
|
2014-07-07 13:06:48 +00:00
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
video_encoder_config_.video_stream_factory =
|
|
|
|
|
new rtc::RefCountedObject<VideoStreamFactory>();
|
|
|
|
|
// Use the same total bitrates when sending a single stream to avoid
|
|
|
|
|
// lowering the bitrate estimate and requiring a subsequent rampup.
|
|
|
|
|
one_stream = video_encoder_config_.Copy();
|
|
|
|
|
// one_stream.streams.resize(1);
|
|
|
|
|
one_stream.number_of_streams = 1;
|
|
|
|
|
CreateMatchingReceiveConfigs(receive_transport.get());
|
2014-07-07 13:06:48 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateVideoStreams();
|
|
|
|
|
CreateFrameGeneratorCapturer(30, 1280, 720);
|
|
|
|
|
|
|
|
|
|
Start();
|
|
|
|
|
});
|
2014-07-07 13:06:48 +00:00
|
|
|
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(observer.Wait())
|
2014-07-07 13:06:48 +00:00
|
|
|
<< "Timed out waiting for all SSRCs to send packets.";
|
|
|
|
|
|
|
|
|
|
// Test stream resetting more than once to make sure that the state doesn't
|
|
|
|
|
// get set once (this could be due to using std::map::insert for instance).
|
|
|
|
|
for (size_t i = 0; i < 3; ++i) {
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([&]() {
|
|
|
|
|
frame_generator_capturer_->Stop();
|
|
|
|
|
sender_call_->DestroyVideoSendStream(video_send_stream_);
|
|
|
|
|
|
|
|
|
|
// Re-create VideoSendStream with only one stream.
|
|
|
|
|
video_send_stream_ = sender_call_->CreateVideoSendStream(
|
|
|
|
|
video_send_config_.Copy(), one_stream.Copy());
|
|
|
|
|
video_send_stream_->Start();
|
|
|
|
|
if (provoke_rtcpsr_before_rtp) {
|
|
|
|
|
// Rapid Resync Request forces sending RTCP Sender Report back.
|
|
|
|
|
// Using this request speeds up this test because then there is no need
|
|
|
|
|
// to wait for a second for periodic Sender Report.
|
|
|
|
|
rtcp::RapidResyncRequest force_send_sr_back_request;
|
|
|
|
|
rtc::Buffer packet = force_send_sr_back_request.Build();
|
|
|
|
|
static_cast<webrtc::test::DirectTransport*>(receive_transport.get())
|
|
|
|
|
->SendRtcp(packet.data(), packet.size());
|
|
|
|
|
}
|
|
|
|
|
CreateFrameGeneratorCapturer(30, 1280, 720);
|
|
|
|
|
frame_generator_capturer_->Start();
|
|
|
|
|
});
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
observer.ResetExpectedSsrcs(1);
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for single RTP packet.";
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
// Reconfigure back to use all streams.
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this]() {
|
|
|
|
|
video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());
|
|
|
|
|
});
|
2014-07-07 13:06:48 +00:00
|
|
|
observer.ResetExpectedSsrcs(kNumSsrcs);
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(observer.Wait())
|
2014-07-07 13:06:48 +00:00
|
|
|
<< "Timed out waiting for all SSRCs to send packets.";
|
|
|
|
|
|
|
|
|
|
// Reconfigure down to one stream.
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &one_stream]() {
|
|
|
|
|
video_send_stream_->ReconfigureVideoEncoder(one_stream.Copy());
|
|
|
|
|
});
|
2014-07-07 13:06:48 +00:00
|
|
|
observer.ResetExpectedSsrcs(1);
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for single RTP packet.";
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
// Reconfigure back to use all streams.
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this]() {
|
|
|
|
|
video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());
|
|
|
|
|
});
|
2014-07-07 13:06:48 +00:00
|
|
|
observer.ResetExpectedSsrcs(kNumSsrcs);
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(observer.Wait())
|
2014-07-07 13:06:48 +00:00
|
|
|
<< "Timed out waiting for all SSRCs to send packets.";
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &send_transport, &receive_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
send_transport.reset();
|
|
|
|
|
receive_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2014-07-07 13:06:48 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RestartingSendStreamPreservesRtpState) {
|
2016-07-20 15:26:59 +02:00
|
|
|
TestRtpStatePreservation(false, false);
|
2014-07-07 13:06:48 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RestartingSendStreamPreservesRtpStatesWithRtx) {
|
2016-07-20 15:26:59 +02:00
|
|
|
TestRtpStatePreservation(true, false);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RestartingSendStreamKeepsRtpAndRtcpTimestampsSynced) {
|
2016-07-20 15:26:59 +02:00
|
|
|
TestRtpStatePreservation(true, true);
|
2014-07-07 13:06:48 +00:00
|
|
|
}
|
|
|
|
|
|
2017-05-31 07:46:56 -07:00
|
|
|
// This test is flaky on linux_memcheck. Disable on all linux bots until
|
|
|
|
|
// flakyness has been fixed.
|
|
|
|
|
// https://bugs.chromium.org/p/webrtc/issues/detail?id=7737
|
|
|
|
|
#if defined(WEBRTC_LINUX)
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, DISABLED_TestFlexfecRtpStatePreservation) {
|
2017-05-31 07:46:56 -07:00
|
|
|
#else
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TestFlexfecRtpStatePreservation) {
|
2017-05-31 07:46:56 -07:00
|
|
|
#endif
|
2017-05-30 02:32:12 -07:00
|
|
|
class RtpSequenceObserver : public test::RtpRtcpObserver {
|
|
|
|
|
public:
|
|
|
|
|
RtpSequenceObserver()
|
|
|
|
|
: test::RtpRtcpObserver(kDefaultTimeoutMs),
|
|
|
|
|
num_flexfec_packets_sent_(0) {}
|
|
|
|
|
|
|
|
|
|
void ResetPacketCount() {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
num_flexfec_packets_sent_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
|
|
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
|
|
|
const uint16_t sequence_number = header.sequenceNumber;
|
|
|
|
|
const uint32_t timestamp = header.timestamp;
|
|
|
|
|
const uint32_t ssrc = header.ssrc;
|
|
|
|
|
|
|
|
|
|
if (ssrc == kVideoSendSsrcs[0] || ssrc == kSendRtxSsrcs[0]) {
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(kFlexfecSendSsrc, ssrc) << "Unknown SSRC sent.";
|
|
|
|
|
|
|
|
|
|
++num_flexfec_packets_sent_;
|
|
|
|
|
|
|
|
|
|
// If this is the first packet, we have nothing to compare to.
|
|
|
|
|
if (!last_observed_sequence_number_) {
|
|
|
|
|
last_observed_sequence_number_.emplace(sequence_number);
|
|
|
|
|
last_observed_timestamp_.emplace(timestamp);
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify continuity and monotonicity of RTP sequence numbers.
|
|
|
|
|
EXPECT_EQ(static_cast<uint16_t>(*last_observed_sequence_number_ + 1),
|
|
|
|
|
sequence_number);
|
|
|
|
|
last_observed_sequence_number_.emplace(sequence_number);
|
|
|
|
|
|
|
|
|
|
// Timestamps should be non-decreasing...
|
|
|
|
|
const bool timestamp_is_same_or_newer =
|
|
|
|
|
timestamp == *last_observed_timestamp_ ||
|
|
|
|
|
IsNewerTimestamp(timestamp, *last_observed_timestamp_);
|
|
|
|
|
EXPECT_TRUE(timestamp_is_same_or_newer);
|
|
|
|
|
// ...but reasonably close in time.
|
|
|
|
|
const int k10SecondsInRtpTimestampBase = 10 * kVideoPayloadTypeFrequency;
|
|
|
|
|
EXPECT_TRUE(IsNewerTimestamp(
|
|
|
|
|
*last_observed_timestamp_ + k10SecondsInRtpTimestampBase, timestamp));
|
|
|
|
|
last_observed_timestamp_.emplace(timestamp);
|
|
|
|
|
|
|
|
|
|
// Pass test when enough packets have been let through.
|
|
|
|
|
if (num_flexfec_packets_sent_ >= 10) {
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-09 04:17:22 -07:00
|
|
|
rtc::Optional<uint16_t> last_observed_sequence_number_
|
|
|
|
|
RTC_GUARDED_BY(crit_);
|
|
|
|
|
rtc::Optional<uint32_t> last_observed_timestamp_ RTC_GUARDED_BY(crit_);
|
|
|
|
|
size_t num_flexfec_packets_sent_ RTC_GUARDED_BY(crit_);
|
2017-05-30 02:32:12 -07:00
|
|
|
rtc::CriticalSection crit_;
|
|
|
|
|
} observer;
|
|
|
|
|
|
2017-08-24 07:40:16 -07:00
|
|
|
static constexpr int kFrameMaxWidth = 320;
|
|
|
|
|
static constexpr int kFrameMaxHeight = 180;
|
|
|
|
|
static constexpr int kFrameRate = 15;
|
2017-05-30 02:32:12 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
Call::Config config(event_log_.get());
|
2017-05-30 02:32:12 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::PacketTransport> send_transport;
|
|
|
|
|
std::unique_ptr<test::PacketTransport> receive_transport;
|
|
|
|
|
std::unique_ptr<VideoEncoder> encoder;
|
|
|
|
|
|
|
|
|
|
task_queue_.SendTask([&]() {
|
|
|
|
|
CreateCalls(config, config);
|
|
|
|
|
|
|
|
|
|
FakeNetworkPipe::Config lossy_delayed_link;
|
|
|
|
|
lossy_delayed_link.loss_percent = 2;
|
|
|
|
|
lossy_delayed_link.queue_delay_ms = 50;
|
|
|
|
|
|
|
|
|
|
send_transport = rtc::MakeUnique<test::PacketTransport>(
|
|
|
|
|
&task_queue_, sender_call_.get(), &observer,
|
|
|
|
|
test::PacketTransport::kSender, payload_type_map_, lossy_delayed_link);
|
|
|
|
|
send_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
|
|
|
|
|
FakeNetworkPipe::Config flawless_link;
|
|
|
|
|
receive_transport = rtc::MakeUnique<test::PacketTransport>(
|
|
|
|
|
&task_queue_, nullptr, &observer, test::PacketTransport::kReceiver,
|
|
|
|
|
payload_type_map_, flawless_link);
|
|
|
|
|
receive_transport->SetReceiver(sender_call_->Receiver());
|
|
|
|
|
|
|
|
|
|
// For reduced flakyness, we use a real VP8 encoder together with NACK
|
|
|
|
|
// and RTX.
|
|
|
|
|
const int kNumVideoStreams = 1;
|
|
|
|
|
const int kNumFlexfecStreams = 1;
|
|
|
|
|
CreateSendConfig(kNumVideoStreams, 0, kNumFlexfecStreams,
|
|
|
|
|
send_transport.get());
|
2017-11-13 14:10:02 +01:00
|
|
|
encoder = VP8Encoder::Create();
|
2017-08-22 04:02:52 -07:00
|
|
|
video_send_config_.encoder_settings.encoder = encoder.get();
|
|
|
|
|
video_send_config_.encoder_settings.payload_name = "VP8";
|
|
|
|
|
video_send_config_.encoder_settings.payload_type = kVideoSendPayloadType;
|
|
|
|
|
video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
video_send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
|
|
|
|
video_send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
|
2017-05-30 02:32:12 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateMatchingReceiveConfigs(receive_transport.get());
|
|
|
|
|
video_receive_configs_[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
|
|
|
|
video_receive_configs_[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
|
2017-08-25 04:44:25 -07:00
|
|
|
video_receive_configs_[0]
|
|
|
|
|
.rtp.rtx_associated_payload_types[kSendRtxPayloadType] =
|
|
|
|
|
kVideoSendPayloadType;
|
2017-08-22 04:02:52 -07:00
|
|
|
|
|
|
|
|
// The matching FlexFEC receive config is not created by
|
|
|
|
|
// CreateMatchingReceiveConfigs since this is not a test::BaseTest.
|
|
|
|
|
// Set up the receive config manually instead.
|
|
|
|
|
FlexfecReceiveStream::Config flexfec_receive_config(
|
|
|
|
|
receive_transport.get());
|
|
|
|
|
flexfec_receive_config.payload_type =
|
|
|
|
|
video_send_config_.rtp.flexfec.payload_type;
|
|
|
|
|
flexfec_receive_config.remote_ssrc = video_send_config_.rtp.flexfec.ssrc;
|
|
|
|
|
flexfec_receive_config.protected_media_ssrcs =
|
|
|
|
|
video_send_config_.rtp.flexfec.protected_media_ssrcs;
|
|
|
|
|
flexfec_receive_config.local_ssrc = kReceiverLocalVideoSsrc;
|
|
|
|
|
flexfec_receive_config.transport_cc = true;
|
|
|
|
|
flexfec_receive_config.rtp_header_extensions.emplace_back(
|
|
|
|
|
RtpExtension::kTransportSequenceNumberUri,
|
|
|
|
|
test::kTransportSequenceNumberExtensionId);
|
|
|
|
|
flexfec_receive_configs_.push_back(flexfec_receive_config);
|
|
|
|
|
|
|
|
|
|
CreateFlexfecStreams();
|
|
|
|
|
CreateVideoStreams();
|
|
|
|
|
|
|
|
|
|
// RTCP might be disabled if the network is "down".
|
|
|
|
|
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
|
|
|
|
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
|
|
|
|
|
|
|
|
|
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
|
|
|
|
|
|
|
|
|
|
Start();
|
|
|
|
|
});
|
2017-05-30 02:32:12 -07:00
|
|
|
|
|
|
|
|
// Initial test.
|
|
|
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &observer]() {
|
|
|
|
|
// Ensure monotonicity when the VideoSendStream is restarted.
|
|
|
|
|
Stop();
|
|
|
|
|
observer.ResetPacketCount();
|
|
|
|
|
Start();
|
|
|
|
|
});
|
|
|
|
|
|
2017-05-30 02:32:12 -07:00
|
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
|
|
|
|
|
2017-08-24 07:40:16 -07:00
|
|
|
task_queue_.SendTask([this, &observer]() {
|
2017-08-22 04:02:52 -07:00
|
|
|
// Ensure monotonicity when the VideoSendStream is recreated.
|
|
|
|
|
frame_generator_capturer_->Stop();
|
|
|
|
|
sender_call_->DestroyVideoSendStream(video_send_stream_);
|
|
|
|
|
observer.ResetPacketCount();
|
|
|
|
|
video_send_stream_ = sender_call_->CreateVideoSendStream(
|
|
|
|
|
video_send_config_.Copy(), video_encoder_config_.Copy());
|
|
|
|
|
video_send_stream_->Start();
|
|
|
|
|
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
|
|
|
|
|
frame_generator_capturer_->Start();
|
|
|
|
|
});
|
|
|
|
|
|
2017-05-30 02:32:12 -07:00
|
|
|
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
|
|
|
|
|
|
|
|
|
|
// Cleanup.
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &send_transport, &receive_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
send_transport.reset();
|
|
|
|
|
receive_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2017-05-30 02:32:12 -07:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, RespectsNetworkState) {
|
2014-09-03 16:17:12 +00:00
|
|
|
// TODO(pbos): Remove accepted downtime packets etc. when signaling network
|
|
|
|
|
// down blocks until no more packets will be sent.
|
|
|
|
|
|
|
|
|
|
// Pacer will send from its packet list and then send required padding before
|
|
|
|
|
// checking paused_ again. This should be enough for one round of pacing,
|
|
|
|
|
// otherwise increase.
|
|
|
|
|
static const int kNumAcceptedDowntimeRtp = 5;
|
|
|
|
|
// A single RTCP may be in the pipeline.
|
|
|
|
|
static const int kNumAcceptedDowntimeRtcp = 1;
|
|
|
|
|
class NetworkStateTest : public test::EndToEndTest, public test::FakeEncoder {
|
|
|
|
|
public:
|
2017-08-22 04:02:52 -07:00
|
|
|
explicit NetworkStateTest(
|
|
|
|
|
test::SingleThreadedTaskQueueForTesting* task_queue)
|
2014-09-03 16:17:12 +00:00
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
|
|
|
|
FakeEncoder(Clock::GetRealTimeClock()),
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_(task_queue),
|
2015-12-10 13:02:50 +01:00
|
|
|
encoded_frames_(false, false),
|
|
|
|
|
packet_event_(false, false),
|
2015-08-03 04:38:41 -07:00
|
|
|
sender_call_(nullptr),
|
|
|
|
|
receiver_call_(nullptr),
|
2015-07-16 09:30:09 +02:00
|
|
|
sender_state_(kNetworkUp),
|
2015-02-13 14:58:18 +00:00
|
|
|
sender_rtp_(0),
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
sender_padding_(0),
|
2015-02-13 14:58:18 +00:00
|
|
|
sender_rtcp_(0),
|
|
|
|
|
receiver_rtcp_(0),
|
2014-09-03 16:17:12 +00:00
|
|
|
down_frames_(0) {}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&test_crit_);
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
|
|
|
if (length == header.headerLength + header.paddingLength)
|
|
|
|
|
++sender_padding_;
|
2015-02-13 14:58:18 +00:00
|
|
|
++sender_rtp_;
|
2015-12-10 13:02:50 +01:00
|
|
|
packet_event_.Set();
|
2014-09-03 16:17:12 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnSendRtcp(const uint8_t* packet, size_t length) override {
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&test_crit_);
|
2015-02-13 14:58:18 +00:00
|
|
|
++sender_rtcp_;
|
2015-12-10 13:02:50 +01:00
|
|
|
packet_event_.Set();
|
2014-09-03 16:17:12 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtp(const uint8_t* packet, size_t length) override {
|
2014-09-03 16:17:12 +00:00
|
|
|
ADD_FAILURE() << "Unexpected receiver RTP, should not be sending.";
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
Action OnReceiveRtcp(const uint8_t* packet, size_t length) override {
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&test_crit_);
|
2015-02-13 14:58:18 +00:00
|
|
|
++receiver_rtcp_;
|
2015-12-10 13:02:50 +01:00
|
|
|
packet_event_.Set();
|
2014-09-03 16:17:12 +00:00
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void OnCallsCreated(Call* sender_call, Call* receiver_call) override {
|
2014-09-03 16:17:12 +00:00
|
|
|
sender_call_ = sender_call;
|
|
|
|
|
receiver_call_ = receiver_call;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-21 03:14:00 -08:00
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2014-09-03 16:17:12 +00:00
|
|
|
send_config->encoder_settings.encoder = this;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void PerformTest() override {
|
2015-12-10 13:02:50 +01:00
|
|
|
EXPECT_TRUE(encoded_frames_.Wait(kDefaultTimeoutMs))
|
2014-09-03 16:17:12 +00:00
|
|
|
<< "No frames received by the encoder.";
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_->SendTask([this]() {
|
|
|
|
|
// Wait for packets from both sender/receiver.
|
|
|
|
|
WaitForPacketsOrSilence(false, false);
|
2016-03-22 15:32:27 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// Sender-side network down for audio; there should be no effect on
|
|
|
|
|
// video
|
|
|
|
|
sender_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkDown);
|
|
|
|
|
WaitForPacketsOrSilence(false, false);
|
2016-03-22 15:32:27 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// Receiver-side network down for audio; no change expected
|
|
|
|
|
receiver_call_->SignalChannelNetworkState(MediaType::AUDIO,
|
|
|
|
|
kNetworkDown);
|
|
|
|
|
WaitForPacketsOrSilence(false, false);
|
|
|
|
|
|
|
|
|
|
// Sender-side network down.
|
|
|
|
|
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkDown);
|
|
|
|
|
{
|
|
|
|
|
rtc::CritScope lock(&test_crit_);
|
|
|
|
|
// After network goes down we shouldn't be encoding more frames.
|
|
|
|
|
sender_state_ = kNetworkDown;
|
|
|
|
|
}
|
|
|
|
|
// Wait for receiver-packets and no sender packets.
|
|
|
|
|
WaitForPacketsOrSilence(true, false);
|
2015-02-13 14:58:18 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// Receiver-side network down.
|
|
|
|
|
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO,
|
|
|
|
|
kNetworkDown);
|
|
|
|
|
WaitForPacketsOrSilence(true, true);
|
2016-03-22 15:32:27 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// Network up for audio for both sides; video is still not expected to
|
|
|
|
|
// start
|
|
|
|
|
sender_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp);
|
|
|
|
|
receiver_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp);
|
|
|
|
|
WaitForPacketsOrSilence(true, true);
|
2014-09-03 16:17:12 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// Network back up again for both.
|
|
|
|
|
{
|
|
|
|
|
rtc::CritScope lock(&test_crit_);
|
|
|
|
|
// It's OK to encode frames again, as we're about to bring up the
|
|
|
|
|
// network.
|
|
|
|
|
sender_state_ = kNetworkUp;
|
|
|
|
|
}
|
|
|
|
|
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
|
|
|
|
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
|
|
|
|
WaitForPacketsOrSilence(false, false);
|
2016-03-22 15:32:27 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
// TODO(skvlad): add tests to verify that the audio streams are stopped
|
|
|
|
|
// when the network goes down for audio once the workaround in
|
|
|
|
|
// paced_sender.cc is removed.
|
|
|
|
|
});
|
2014-09-03 16:17:12 +00:00
|
|
|
}
|
|
|
|
|
|
2015-05-29 17:21:40 -07:00
|
|
|
int32_t Encode(const VideoFrame& input_image,
|
2015-03-04 12:58:35 +00:00
|
|
|
const CodecSpecificInfo* codec_specific_info,
|
2015-10-19 02:39:06 -07:00
|
|
|
const std::vector<FrameType>* frame_types) override {
|
2014-09-03 16:17:12 +00:00
|
|
|
{
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&test_crit_);
|
2015-07-16 09:30:09 +02:00
|
|
|
if (sender_state_ == kNetworkDown) {
|
2014-09-03 16:17:12 +00:00
|
|
|
++down_frames_;
|
|
|
|
|
EXPECT_LE(down_frames_, 1)
|
|
|
|
|
<< "Encoding more than one frame while network is down.";
|
|
|
|
|
if (down_frames_ > 1)
|
2015-12-10 13:02:50 +01:00
|
|
|
encoded_frames_.Set();
|
2014-09-03 16:17:12 +00:00
|
|
|
} else {
|
2015-12-10 13:02:50 +01:00
|
|
|
encoded_frames_.Set();
|
2014-09-03 16:17:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return test::FakeEncoder::Encode(
|
|
|
|
|
input_image, codec_specific_info, frame_types);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2015-02-13 14:58:18 +00:00
|
|
|
void WaitForPacketsOrSilence(bool sender_down, bool receiver_down) {
|
|
|
|
|
int64_t initial_time_ms = clock_->TimeInMilliseconds();
|
|
|
|
|
int initial_sender_rtp;
|
|
|
|
|
int initial_sender_rtcp;
|
|
|
|
|
int initial_receiver_rtcp;
|
|
|
|
|
{
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&test_crit_);
|
2015-02-13 14:58:18 +00:00
|
|
|
initial_sender_rtp = sender_rtp_;
|
|
|
|
|
initial_sender_rtcp = sender_rtcp_;
|
|
|
|
|
initial_receiver_rtcp = receiver_rtcp_;
|
|
|
|
|
}
|
|
|
|
|
bool sender_done = false;
|
|
|
|
|
bool receiver_done = false;
|
2015-12-09 07:07:59 -08:00
|
|
|
while (!sender_done || !receiver_done) {
|
2015-12-10 13:02:50 +01:00
|
|
|
packet_event_.Wait(kSilenceTimeoutMs);
|
2015-02-13 14:58:18 +00:00
|
|
|
int64_t time_now_ms = clock_->TimeInMilliseconds();
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CritScope lock(&test_crit_);
|
2015-02-13 14:58:18 +00:00
|
|
|
if (sender_down) {
|
Reland of Add functionality which limits the number of bytes on the network. (patchset #1 id:1 of https://codereview.webrtc.org/3001653002/ )
Reason for revert:
Reland
Original issue's description:
> Revert of Add functionality which limits the number of bytes on the network. (patchset #26 id:500001 of https://codereview.webrtc.org/2918323002/ )
>
> Reason for revert:
> Speculative revert to see if this caused regressions in android perf tests.
>
> Original issue's description:
> > Add functionality which limits the number of bytes on the network.
> >
> > The limit is based on the bandwidth delay product, but also adds some additional slack to compensate for the sawtooth-like BWE pattern and the slowness of the encoder rate control. The delay is estimated based on the time from sending a packet until an ack is received. Since acks are received in bursts (feedback is only sent periodically), a min filter is used to estimate the rtt.
> >
> > Whenever the in flight bytes reaches the congestion window, the pacer is paused, which in turn will result in send-side queues growing. Eventually the encoders will be paused as the pacer queue grows large (currently 2 seconds).
> >
> > BUG=webrtc:7926
> >
> > Review-Url: https://codereview.webrtc.org/2918323002
> > Cr-Commit-Position: refs/heads/master@{#19289}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/8497fdde43d920ab1f0cc90362534e5493d23abe
>
> TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7926
>
> Review-Url: https://codereview.webrtc.org/3001653002
> Cr-Commit-Position: refs/heads/master@{#19339}
> Committed: https://chromium.googlesource.com/external/webrtc/+/64136af364d1fecada49e35b1bfa39ef2641d5d0
TBR=terelius@webrtc.org,philipel@webrtc.org,tschumim@webrtc.org,gnish@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7926
Review-Url: https://codereview.webrtc.org/2994343002
Cr-Commit-Position: refs/heads/master@{#19373}
2017-08-16 08:16:25 -07:00
|
|
|
ASSERT_LE(sender_rtp_ - initial_sender_rtp - sender_padding_,
|
|
|
|
|
kNumAcceptedDowntimeRtp)
|
2015-02-13 14:58:18 +00:00
|
|
|
<< "RTP sent during sender-side downtime.";
|
|
|
|
|
ASSERT_LE(sender_rtcp_ - initial_sender_rtcp,
|
|
|
|
|
kNumAcceptedDowntimeRtcp)
|
|
|
|
|
<< "RTCP sent during sender-side downtime.";
|
|
|
|
|
if (time_now_ms - initial_time_ms >=
|
|
|
|
|
static_cast<int64_t>(kSilenceTimeoutMs)) {
|
|
|
|
|
sender_done = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2016-03-22 15:32:27 -07:00
|
|
|
if (sender_rtp_ > initial_sender_rtp + kNumAcceptedDowntimeRtp)
|
2015-02-13 14:58:18 +00:00
|
|
|
sender_done = true;
|
|
|
|
|
}
|
|
|
|
|
if (receiver_down) {
|
|
|
|
|
ASSERT_LE(receiver_rtcp_ - initial_receiver_rtcp,
|
|
|
|
|
kNumAcceptedDowntimeRtcp)
|
|
|
|
|
<< "RTCP sent during receiver-side downtime.";
|
|
|
|
|
if (time_now_ms - initial_time_ms >=
|
|
|
|
|
static_cast<int64_t>(kSilenceTimeoutMs)) {
|
|
|
|
|
receiver_done = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2016-03-22 15:32:27 -07:00
|
|
|
if (receiver_rtcp_ > initial_receiver_rtcp + kNumAcceptedDowntimeRtcp)
|
2015-02-13 14:58:18 +00:00
|
|
|
receiver_done = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
test::SingleThreadedTaskQueueForTesting* const task_queue_;
|
2015-05-01 13:00:41 +02:00
|
|
|
rtc::CriticalSection test_crit_;
|
2015-12-10 13:02:50 +01:00
|
|
|
rtc::Event encoded_frames_;
|
|
|
|
|
rtc::Event packet_event_;
|
2014-09-03 16:17:12 +00:00
|
|
|
Call* sender_call_;
|
|
|
|
|
Call* receiver_call_;
|
2017-09-09 04:17:22 -07:00
|
|
|
NetworkState sender_state_ RTC_GUARDED_BY(test_crit_);
|
|
|
|
|
int sender_rtp_ RTC_GUARDED_BY(test_crit_);
|
|
|
|
|
int sender_padding_ RTC_GUARDED_BY(test_crit_);
|
|
|
|
|
int sender_rtcp_ RTC_GUARDED_BY(test_crit_);
|
|
|
|
|
int receiver_rtcp_ RTC_GUARDED_BY(test_crit_);
|
|
|
|
|
int down_frames_ RTC_GUARDED_BY(test_crit_);
|
2017-08-22 04:02:52 -07:00
|
|
|
} test(&task_queue_);
|
2014-09-03 16:17:12 +00:00
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2014-09-03 16:17:12 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, CallReportsRttForSender) {
|
2014-12-11 13:26:09 +00:00
|
|
|
static const int kSendDelayMs = 30;
|
|
|
|
|
static const int kReceiveDelayMs = 70;
|
2015-08-28 04:07:10 -07:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::DirectTransport> sender_transport;
|
|
|
|
|
std::unique_ptr<test::DirectTransport> receiver_transport;
|
2014-12-11 13:26:09 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &sender_transport, &receiver_transport]() {
|
|
|
|
|
FakeNetworkPipe::Config config;
|
|
|
|
|
config.queue_delay_ms = kSendDelayMs;
|
|
|
|
|
CreateCalls(Call::Config(event_log_.get()), Call::Config(event_log_.get()));
|
|
|
|
|
sender_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, config, sender_call_.get(), payload_type_map_);
|
|
|
|
|
config.queue_delay_ms = kReceiveDelayMs;
|
|
|
|
|
receiver_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, config, receiver_call_.get(), payload_type_map_);
|
|
|
|
|
sender_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
receiver_transport->SetReceiver(sender_call_->Receiver());
|
|
|
|
|
|
|
|
|
|
CreateSendConfig(1, 0, 0, sender_transport.get());
|
|
|
|
|
CreateMatchingReceiveConfigs(receiver_transport.get());
|
|
|
|
|
|
|
|
|
|
CreateVideoStreams();
|
|
|
|
|
CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
|
|
|
|
|
kDefaultHeight);
|
|
|
|
|
Start();
|
|
|
|
|
});
|
2014-12-11 13:26:09 +00:00
|
|
|
|
|
|
|
|
int64_t start_time_ms = clock_->TimeInMilliseconds();
|
|
|
|
|
while (true) {
|
|
|
|
|
Call::Stats stats = sender_call_->GetStats();
|
|
|
|
|
ASSERT_GE(start_time_ms + kDefaultTimeoutMs,
|
|
|
|
|
clock_->TimeInMilliseconds())
|
|
|
|
|
<< "No RTT stats before timeout!";
|
|
|
|
|
if (stats.rtt_ms != -1) {
|
2016-09-07 15:05:29 +02:00
|
|
|
// To avoid failures caused by rounding or minor ntp clock adjustments,
|
|
|
|
|
// relax expectation by 1ms.
|
|
|
|
|
constexpr int kAllowedErrorMs = 1;
|
|
|
|
|
EXPECT_GE(stats.rtt_ms, kSendDelayMs + kReceiveDelayMs - kAllowedErrorMs);
|
2014-12-11 13:26:09 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
SleepMs(10);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &sender_transport, &receiver_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
sender_transport.reset();
|
|
|
|
|
receiver_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2014-12-11 13:26:09 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-22 15:32:27 -07:00
|
|
|
void EndToEndTest::VerifyNewVideoSendStreamsRespectNetworkState(
|
2016-11-22 16:08:30 -08:00
|
|
|
MediaType network_to_bring_up,
|
2016-03-22 15:32:27 -07:00
|
|
|
VideoEncoder* encoder,
|
|
|
|
|
Transport* transport) {
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, network_to_bring_up, encoder, transport]() {
|
|
|
|
|
CreateSenderCall(Call::Config(event_log_.get()));
|
|
|
|
|
sender_call_->SignalChannelNetworkState(network_to_bring_up, kNetworkUp);
|
2014-09-03 16:17:12 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
CreateSendConfig(1, 0, 0, transport);
|
|
|
|
|
video_send_config_.encoder_settings.encoder = encoder;
|
|
|
|
|
CreateVideoStreams();
|
|
|
|
|
CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
|
|
|
|
|
kDefaultHeight);
|
|
|
|
|
|
|
|
|
|
Start();
|
|
|
|
|
});
|
2014-09-03 16:17:12 +00:00
|
|
|
|
|
|
|
|
SleepMs(kSilenceTimeoutMs);
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2014-09-03 16:17:12 +00:00
|
|
|
}
|
|
|
|
|
|
2016-03-22 15:32:27 -07:00
|
|
|
void EndToEndTest::VerifyNewVideoReceiveStreamsRespectNetworkState(
|
2016-11-22 16:08:30 -08:00
|
|
|
MediaType network_to_bring_up,
|
2016-03-22 15:32:27 -07:00
|
|
|
Transport* transport) {
|
2017-08-22 04:02:52 -07:00
|
|
|
std::unique_ptr<test::DirectTransport> sender_transport;
|
2014-09-03 16:17:12 +00:00
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &sender_transport, network_to_bring_up,
|
|
|
|
|
transport]() {
|
|
|
|
|
Call::Config config(event_log_.get());
|
|
|
|
|
CreateCalls(config, config);
|
|
|
|
|
receiver_call_->SignalChannelNetworkState(network_to_bring_up, kNetworkUp);
|
|
|
|
|
sender_transport = rtc::MakeUnique<test::DirectTransport>(
|
|
|
|
|
&task_queue_, sender_call_.get(), payload_type_map_);
|
|
|
|
|
sender_transport->SetReceiver(receiver_call_->Receiver());
|
|
|
|
|
CreateSendConfig(1, 0, 0, sender_transport.get());
|
|
|
|
|
CreateMatchingReceiveConfigs(transport);
|
|
|
|
|
CreateVideoStreams();
|
|
|
|
|
CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
|
|
|
|
|
kDefaultHeight);
|
|
|
|
|
Start();
|
|
|
|
|
});
|
2014-09-03 16:17:12 +00:00
|
|
|
|
|
|
|
|
SleepMs(kSilenceTimeoutMs);
|
|
|
|
|
|
2017-08-22 04:02:52 -07:00
|
|
|
task_queue_.SendTask([this, &sender_transport]() {
|
|
|
|
|
Stop();
|
|
|
|
|
DestroyStreams();
|
|
|
|
|
sender_transport.reset();
|
|
|
|
|
DestroyCalls();
|
|
|
|
|
});
|
2014-09-03 16:17:12 +00:00
|
|
|
}
|
2014-11-04 13:48:15 +00:00
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, NewVideoSendStreamsRespectVideoNetworkDown) {
|
2016-03-22 15:32:27 -07:00
|
|
|
class UnusedEncoder : public test::FakeEncoder {
|
|
|
|
|
public:
|
|
|
|
|
UnusedEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
|
2016-05-14 00:58:48 -07:00
|
|
|
|
|
|
|
|
int32_t InitEncode(const VideoCodec* config,
|
|
|
|
|
int32_t number_of_cores,
|
|
|
|
|
size_t max_payload_size) override {
|
|
|
|
|
EXPECT_GT(config->startBitrate, 0u);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-03-22 15:32:27 -07:00
|
|
|
int32_t Encode(const VideoFrame& input_image,
|
|
|
|
|
const CodecSpecificInfo* codec_specific_info,
|
|
|
|
|
const std::vector<FrameType>* frame_types) override {
|
|
|
|
|
ADD_FAILURE() << "Unexpected frame encode.";
|
|
|
|
|
return test::FakeEncoder::Encode(input_image, codec_specific_info,
|
|
|
|
|
frame_types);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
UnusedEncoder unused_encoder;
|
|
|
|
|
UnusedTransport unused_transport;
|
|
|
|
|
VerifyNewVideoSendStreamsRespectNetworkState(
|
2016-11-22 16:08:30 -08:00
|
|
|
MediaType::AUDIO, &unused_encoder, &unused_transport);
|
2016-03-22 15:32:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, NewVideoSendStreamsIgnoreAudioNetworkDown) {
|
2016-03-22 15:32:27 -07:00
|
|
|
class RequiredEncoder : public test::FakeEncoder {
|
|
|
|
|
public:
|
|
|
|
|
RequiredEncoder()
|
|
|
|
|
: FakeEncoder(Clock::GetRealTimeClock()), encoded_frame_(false) {}
|
|
|
|
|
~RequiredEncoder() {
|
|
|
|
|
if (!encoded_frame_) {
|
|
|
|
|
ADD_FAILURE() << "Didn't encode an expected frame";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
int32_t Encode(const VideoFrame& input_image,
|
|
|
|
|
const CodecSpecificInfo* codec_specific_info,
|
|
|
|
|
const std::vector<FrameType>* frame_types) override {
|
|
|
|
|
encoded_frame_ = true;
|
|
|
|
|
return test::FakeEncoder::Encode(input_image, codec_specific_info,
|
|
|
|
|
frame_types);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
bool encoded_frame_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RequiredTransport required_transport(true /*rtp*/, false /*rtcp*/);
|
|
|
|
|
RequiredEncoder required_encoder;
|
|
|
|
|
VerifyNewVideoSendStreamsRespectNetworkState(
|
2016-11-22 16:08:30 -08:00
|
|
|
MediaType::VIDEO, &required_encoder, &required_transport);
|
2016-03-22 15:32:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, NewVideoReceiveStreamsRespectVideoNetworkDown) {
|
2016-03-22 15:32:27 -07:00
|
|
|
UnusedTransport transport;
|
2016-11-22 16:08:30 -08:00
|
|
|
VerifyNewVideoReceiveStreamsRespectNetworkState(MediaType::AUDIO, &transport);
|
2016-03-22 15:32:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, NewVideoReceiveStreamsIgnoreAudioNetworkDown) {
|
2016-03-22 15:32:27 -07:00
|
|
|
RequiredTransport transport(false /*rtp*/, true /*rtcp*/);
|
2016-11-22 16:08:30 -08:00
|
|
|
VerifyNewVideoReceiveStreamsRespectNetworkState(MediaType::VIDEO, &transport);
|
2016-03-22 15:32:27 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-05 14:09:38 +02:00
|
|
|
void VerifyEmptyNackConfig(const NackConfig& config) {
|
|
|
|
|
EXPECT_EQ(0, config.rtp_history_ms)
|
|
|
|
|
<< "Enabling NACK requires rtcp-fb: nack negotiation.";
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-04 23:28:39 -07:00
|
|
|
void VerifyEmptyUlpfecConfig(const UlpfecConfig& config) {
|
2015-06-05 14:09:38 +02:00
|
|
|
EXPECT_EQ(-1, config.ulpfec_payload_type)
|
2016-10-31 03:45:58 -07:00
|
|
|
<< "Enabling ULPFEC requires rtpmap: ulpfec negotiation.";
|
2015-06-05 14:09:38 +02:00
|
|
|
EXPECT_EQ(-1, config.red_payload_type)
|
2016-10-31 03:45:58 -07:00
|
|
|
<< "Enabling ULPFEC requires rtpmap: red negotiation.";
|
2015-06-05 14:09:38 +02:00
|
|
|
EXPECT_EQ(-1, config.red_rtx_payload_type)
|
2016-10-31 03:45:58 -07:00
|
|
|
<< "Enabling RTX in ULPFEC requires rtpmap: rtx negotiation.";
|
2015-06-05 14:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-16 06:59:19 -08:00
|
|
|
void VerifyEmptyFlexfecConfig(
|
|
|
|
|
const VideoSendStream::Config::Rtp::Flexfec& config) {
|
|
|
|
|
EXPECT_EQ(-1, config.payload_type)
|
2016-11-16 22:45:19 -08:00
|
|
|
<< "Enabling FlexFEC requires rtpmap: flexfec negotiation.";
|
2017-01-16 06:59:19 -08:00
|
|
|
EXPECT_EQ(0U, config.ssrc)
|
2016-12-08 04:17:53 -08:00
|
|
|
<< "Enabling FlexFEC requires ssrc-group: FEC-FR negotiation.";
|
2016-11-16 22:45:19 -08:00
|
|
|
EXPECT_TRUE(config.protected_media_ssrcs.empty())
|
|
|
|
|
<< "Enabling FlexFEC requires ssrc-group: FEC-FR negotiation.";
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyDefaultSendConfigParameters) {
|
2015-08-28 04:07:10 -07:00
|
|
|
VideoSendStream::Config default_send_config(nullptr);
|
2015-06-05 14:09:38 +02:00
|
|
|
EXPECT_EQ(0, default_send_config.rtp.nack.rtp_history_ms)
|
|
|
|
|
<< "Enabling NACK require rtcp-fb: nack negotiation.";
|
|
|
|
|
EXPECT_TRUE(default_send_config.rtp.rtx.ssrcs.empty())
|
|
|
|
|
<< "Enabling RTX requires rtpmap: rtx negotiation.";
|
|
|
|
|
EXPECT_TRUE(default_send_config.rtp.extensions.empty())
|
|
|
|
|
<< "Enabling RTP extensions require negotiation.";
|
|
|
|
|
|
|
|
|
|
VerifyEmptyNackConfig(default_send_config.rtp.nack);
|
2016-10-04 23:28:39 -07:00
|
|
|
VerifyEmptyUlpfecConfig(default_send_config.rtp.ulpfec);
|
2016-11-16 22:45:19 -08:00
|
|
|
VerifyEmptyFlexfecConfig(default_send_config.rtp.flexfec);
|
2015-06-05 14:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyDefaultVideoReceiveConfigParameters) {
|
2015-08-28 04:07:10 -07:00
|
|
|
VideoReceiveStream::Config default_receive_config(nullptr);
|
2015-10-02 02:36:56 -07:00
|
|
|
EXPECT_EQ(RtcpMode::kCompound, default_receive_config.rtp.rtcp_mode)
|
2015-06-05 14:09:38 +02:00
|
|
|
<< "Reduced-size RTCP require rtcp-rsize to be negotiated.";
|
|
|
|
|
EXPECT_FALSE(default_receive_config.rtp.remb)
|
|
|
|
|
<< "REMB require rtcp-fb: goog-remb to be negotiated.";
|
|
|
|
|
EXPECT_FALSE(
|
|
|
|
|
default_receive_config.rtp.rtcp_xr.receiver_reference_time_report)
|
|
|
|
|
<< "RTCP XR settings require rtcp-xr to be negotiated.";
|
Reland of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #1 id:1 of https://codereview.webrtc.org/2649323010/ )
Reason for revert:
Downstream project relied on changed struct.
Transition made possible by https://codereview.webrtc.org/2655243006/.
Original issue's description:
> Revert of Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters. (patchset #7 id:160001 of https://codereview.webrtc.org/2646073004/ )
>
> Reason for revert:
> Breaks internal downstream project.
>
> Original issue's description:
> > Make RTX pt/apt reconfigurable by calling WebRtcVideoChannel2::SetRecvParameters.
> >
> > Prior to this CL, received RTX (associated) payload types were only configured
> > when WebRtcVideoChannel2::AddRecvStream was called. In the same method, the RTX
> > SSRC was set up.
> >
> > After this CL, the RTX (associated) payload types are set in
> > WebRtcVideoChannel2::SetRecvParameters, which is the appropriate place to set
> > them. The RTX SSRC is still set in WebRtcVideoChannel2::AddRecvStream, since
> > that is the code path that sets other SSRCs.
> >
> > As part of this fix, the VideoReceiveStream::Config::Rtp struct is changed.
> > We remove the possibility for each video payload type to have an associated
> > specific RTX SSRC. Although the config previously allowed for this, all payload
> > types always had the same RTX SSRC set, and the underlying RtpPayloadRegistry
> > did not support multiple SSRCs. This change to the config struct should thus not
> > have any functional impact. The change does however affect the RtcEventLog, since
> > that is used for storing the VideoReceiveStream::Configs. For simplicity,
> > this CL does not change the event log proto definitions, instead duplicating
> > the serialized RTX SSRCs such that they fit in the existing proto definition.
> >
> > BUG=webrtc:7011
> >
> > Review-Url: https://codereview.webrtc.org/2646073004
> > Cr-Commit-Position: refs/heads/master@{#16302}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/fe2bef39cd2a5c891a49f7320514fb04324dc66c
>
> TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,brandtr@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:7011
>
> Review-Url: https://codereview.webrtc.org/2649323010
> Cr-Commit-Position: refs/heads/master@{#16307}
> Committed: https://chromium.googlesource.com/external/webrtc/+/e4974953ce0d03a60fae7659b199a6a62a79fa30
TBR=stefan@webrtc.org,magjed@webrtc.org,terelius@webrtc.org,kjellander@webrtc.org,kjellander@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
# NOTREECHECKS=true
# NOTRY=true
BUG=webrtc:7011
Review-Url: https://codereview.webrtc.org/2654163006
Cr-Commit-Position: refs/heads/master@{#16322}
2017-01-27 04:53:07 -08:00
|
|
|
EXPECT_EQ(0U, default_receive_config.rtp.rtx_ssrc)
|
|
|
|
|
<< "Enabling RTX requires ssrc-group: FID negotiation";
|
2017-08-25 04:44:25 -07:00
|
|
|
EXPECT_TRUE(default_receive_config.rtp.rtx_associated_payload_types.empty())
|
2015-06-05 14:09:38 +02:00
|
|
|
<< "Enabling RTX requires rtpmap: rtx negotiation.";
|
|
|
|
|
EXPECT_TRUE(default_receive_config.rtp.extensions.empty())
|
|
|
|
|
<< "Enabling RTP extensions require negotiation.";
|
|
|
|
|
|
|
|
|
|
VerifyEmptyNackConfig(default_receive_config.rtp.nack);
|
2017-09-26 02:49:21 -07:00
|
|
|
EXPECT_EQ(-1, default_receive_config.rtp.ulpfec_payload_type)
|
|
|
|
|
<< "Enabling ULPFEC requires rtpmap: ulpfec negotiation.";
|
|
|
|
|
EXPECT_EQ(-1, default_receive_config.rtp.red_payload_type)
|
|
|
|
|
<< "Enabling ULPFEC requires rtpmap: red negotiation.";
|
2015-06-05 14:09:38 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, VerifyDefaultFlexfecReceiveConfigParameters) {
|
2017-01-13 07:41:19 -08:00
|
|
|
test::NullTransport rtcp_send_transport;
|
|
|
|
|
FlexfecReceiveStream::Config default_receive_config(&rtcp_send_transport);
|
2016-12-08 04:17:53 -08:00
|
|
|
EXPECT_EQ(-1, default_receive_config.payload_type)
|
|
|
|
|
<< "Enabling FlexFEC requires rtpmap: flexfec negotiation.";
|
|
|
|
|
EXPECT_EQ(0U, default_receive_config.remote_ssrc)
|
|
|
|
|
<< "Enabling FlexFEC requires ssrc-group: FEC-FR negotiation.";
|
|
|
|
|
EXPECT_TRUE(default_receive_config.protected_media_ssrcs.empty())
|
|
|
|
|
<< "Enabling FlexFEC requires ssrc-group: FEC-FR negotiation.";
|
2016-11-16 22:45:19 -08:00
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndTest, TransportSeqNumOnAudioAndVideo) {
|
2017-03-03 06:21:54 -08:00
|
|
|
static constexpr int kExtensionId = 8;
|
|
|
|
|
static constexpr size_t kMinPacketsToWaitFor = 50;
|
2016-01-07 17:43:18 +01:00
|
|
|
class TransportSequenceNumberTest : public test::EndToEndTest {
|
|
|
|
|
public:
|
|
|
|
|
TransportSequenceNumberTest()
|
|
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
|
|
|
|
video_observed_(false),
|
|
|
|
|
audio_observed_(false) {
|
|
|
|
|
parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
|
|
|
|
|
kExtensionId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t GetNumVideoStreams() const override { return 1; }
|
|
|
|
|
size_t GetNumAudioStreams() const override { return 1; }
|
|
|
|
|
|
|
|
|
|
void ModifyAudioConfigs(
|
|
|
|
|
AudioSendStream::Config* send_config,
|
|
|
|
|
std::vector<AudioReceiveStream::Config>* receive_configs) override {
|
|
|
|
|
send_config->rtp.extensions.clear();
|
2016-05-26 11:24:55 -07:00
|
|
|
send_config->rtp.extensions.push_back(RtpExtension(
|
|
|
|
|
RtpExtension::kTransportSequenceNumberUri, kExtensionId));
|
2016-01-07 17:43:18 +01:00
|
|
|
(*receive_configs)[0].rtp.extensions.clear();
|
|
|
|
|
(*receive_configs)[0].rtp.extensions = send_config->rtp.extensions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Action OnSendRtp(const uint8_t* packet, size_t length) override {
|
|
|
|
|
RTPHeader header;
|
|
|
|
|
EXPECT_TRUE(parser_->Parse(packet, length, &header));
|
|
|
|
|
EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
|
|
|
|
|
// Unwrap packet id and verify uniqueness.
|
|
|
|
|
int64_t packet_id =
|
|
|
|
|
unwrapper_.Unwrap(header.extension.transportSequenceNumber);
|
|
|
|
|
EXPECT_TRUE(received_packet_ids_.insert(packet_id).second);
|
|
|
|
|
|
|
|
|
|
if (header.ssrc == kVideoSendSsrcs[0])
|
|
|
|
|
video_observed_ = true;
|
|
|
|
|
if (header.ssrc == kAudioSendSsrc)
|
|
|
|
|
audio_observed_ = true;
|
|
|
|
|
if (audio_observed_ && video_observed_ &&
|
2017-03-03 06:21:54 -08:00
|
|
|
received_packet_ids_.size() >= kMinPacketsToWaitFor) {
|
2016-01-07 17:43:18 +01:00
|
|
|
size_t packet_id_range =
|
|
|
|
|
*received_packet_ids_.rbegin() - *received_packet_ids_.begin() + 1;
|
|
|
|
|
EXPECT_EQ(received_packet_ids_.size(), packet_id_range);
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
|
|
|
|
return SEND_PACKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
EXPECT_TRUE(Wait()) << "Timed out while waiting for audio and video "
|
|
|
|
|
"packets with transport sequence number.";
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-03 06:21:54 -08:00
|
|
|
void ExpectSuccessful() {
|
|
|
|
|
EXPECT_TRUE(video_observed_);
|
|
|
|
|
EXPECT_TRUE(audio_observed_);
|
|
|
|
|
EXPECT_GE(received_packet_ids_.size(), kMinPacketsToWaitFor);
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-07 17:43:18 +01:00
|
|
|
private:
|
|
|
|
|
bool video_observed_;
|
|
|
|
|
bool audio_observed_;
|
|
|
|
|
SequenceNumberUnwrapper unwrapper_;
|
|
|
|
|
std::set<int64_t> received_packet_ids_;
|
|
|
|
|
} test;
|
|
|
|
|
|
2016-01-08 06:47:13 -08:00
|
|
|
RunBaseTest(&test);
|
2017-03-03 06:21:54 -08:00
|
|
|
// Double check conditions for successful test to produce better error
|
|
|
|
|
// message when the test fail.
|
|
|
|
|
test.ExpectSuccessful();
|
2016-01-07 17:43:18 +01:00
|
|
|
}
|
2016-09-28 06:19:48 -07:00
|
|
|
|
|
|
|
|
class EndToEndLogTest : public EndToEndTest {
|
|
|
|
|
void SetUp() { paths_.clear(); }
|
|
|
|
|
void TearDown() {
|
|
|
|
|
for (const auto& path : paths_) {
|
|
|
|
|
rtc::RemoveFile(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
int AddFile() {
|
|
|
|
|
paths_.push_back(test::TempFilename(test::OutputPath(), "test_file"));
|
|
|
|
|
return static_cast<int>(paths_.size()) - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtc::PlatformFile OpenFile(int idx) {
|
|
|
|
|
return rtc::OpenPlatformFile(paths_[idx]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LogSend(bool open) {
|
|
|
|
|
if (open) {
|
|
|
|
|
video_send_stream_->EnableEncodedFrameRecording(
|
|
|
|
|
std::vector<rtc::PlatformFile>(1, OpenFile(AddFile())), 0);
|
|
|
|
|
} else {
|
|
|
|
|
video_send_stream_->DisableEncodedFrameRecording();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void LogReceive(bool open) {
|
|
|
|
|
if (open) {
|
|
|
|
|
video_receive_streams_[0]->EnableEncodedFrameRecording(
|
|
|
|
|
OpenFile(AddFile()), 0);
|
|
|
|
|
} else {
|
|
|
|
|
video_receive_streams_[0]->DisableEncodedFrameRecording();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> paths_;
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
TEST_P(EndToEndLogTest, LogsEncodedFramesWhenRequested) {
|
2016-09-28 06:19:48 -07:00
|
|
|
static const int kNumFramesToRecord = 10;
|
|
|
|
|
class LogEncodingObserver : public test::EndToEndTest,
|
|
|
|
|
public EncodedFrameObserver {
|
|
|
|
|
public:
|
|
|
|
|
explicit LogEncodingObserver(EndToEndLogTest* fixture)
|
|
|
|
|
: EndToEndTest(kDefaultTimeoutMs),
|
|
|
|
|
fixture_(fixture),
|
|
|
|
|
recorded_frames_(0) {}
|
|
|
|
|
|
|
|
|
|
void PerformTest() override {
|
|
|
|
|
fixture_->LogSend(true);
|
|
|
|
|
fixture_->LogReceive(true);
|
|
|
|
|
ASSERT_TRUE(Wait()) << "Timed out while waiting for frame logging.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ModifyVideoConfigs(
|
|
|
|
|
VideoSendStream::Config* send_config,
|
|
|
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
|
|
|
VideoEncoderConfig* encoder_config) override {
|
2017-11-13 14:10:02 +01:00
|
|
|
encoder_ = VP8Encoder::Create();
|
|
|
|
|
decoder_ = VP8Decoder::Create();
|
2016-09-28 06:19:48 -07:00
|
|
|
|
|
|
|
|
send_config->post_encode_callback = this;
|
|
|
|
|
send_config->encoder_settings.payload_name = "VP8";
|
|
|
|
|
send_config->encoder_settings.encoder = encoder_.get();
|
|
|
|
|
|
|
|
|
|
(*receive_configs)[0].decoders.resize(1);
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_type =
|
|
|
|
|
send_config->encoder_settings.payload_type;
|
|
|
|
|
(*receive_configs)[0].decoders[0].payload_name =
|
|
|
|
|
send_config->encoder_settings.payload_name;
|
|
|
|
|
(*receive_configs)[0].decoders[0].decoder = decoder_.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EncodedFrameCallback(const EncodedFrame& encoded_frame) override {
|
|
|
|
|
rtc::CritScope lock(&crit_);
|
|
|
|
|
if (recorded_frames_++ > kNumFramesToRecord) {
|
|
|
|
|
fixture_->LogSend(false);
|
|
|
|
|
fixture_->LogReceive(false);
|
|
|
|
|
rtc::File send_file(fixture_->OpenFile(0));
|
|
|
|
|
rtc::File receive_file(fixture_->OpenFile(1));
|
|
|
|
|
uint8_t out[100];
|
|
|
|
|
// If logging has worked correctly neither file should be empty, i.e.
|
|
|
|
|
// we should be able to read something from them.
|
|
|
|
|
EXPECT_LT(0u, send_file.Read(out, 100));
|
|
|
|
|
EXPECT_LT(0u, receive_file.Read(out, 100));
|
|
|
|
|
observation_complete_.Set();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
EndToEndLogTest* const fixture_;
|
|
|
|
|
std::unique_ptr<VideoEncoder> encoder_;
|
|
|
|
|
std::unique_ptr<VideoDecoder> decoder_;
|
|
|
|
|
rtc::CriticalSection crit_;
|
2017-09-09 04:17:22 -07:00
|
|
|
int recorded_frames_ RTC_GUARDED_BY(crit_);
|
2016-09-28 06:19:48 -07:00
|
|
|
} test(this);
|
|
|
|
|
|
|
|
|
|
RunBaseTest(&test);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-23 12:42:17 +02:00
|
|
|
INSTANTIATE_TEST_CASE_P(RoundRobin,
|
|
|
|
|
EndToEndTest,
|
|
|
|
|
::testing::Values("WebRTC-RoundRobinPacing/Disabled/",
|
|
|
|
|
"WebRTC-RoundRobinPacing/Enabled/"));
|
|
|
|
|
|
2013-08-05 12:01:36 +00:00
|
|
|
} // namespace webrtc
|