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}
This commit is contained in:
parent
4703741e49
commit
fe2bef39cd
@ -649,11 +649,8 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
|
|||||||
RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) ==
|
RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) ==
|
||||||
video_receive_ssrcs_.end());
|
video_receive_ssrcs_.end());
|
||||||
video_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
video_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
||||||
// TODO(pbos): Configure different RTX payloads per receive payload.
|
if (config.rtp.rtx_ssrc)
|
||||||
VideoReceiveStream::Config::Rtp::RtxMap::const_iterator it =
|
video_receive_ssrcs_[config.rtp.rtx_ssrc] = receive_stream;
|
||||||
config.rtp.rtx.begin();
|
|
||||||
if (it != config.rtp.rtx.end())
|
|
||||||
video_receive_ssrcs_[it->second.ssrc] = receive_stream;
|
|
||||||
video_receive_streams_.insert(receive_stream);
|
video_receive_streams_.insert(receive_stream);
|
||||||
ConfigureSync(config.sync_group);
|
ConfigureSync(config.sync_group);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -199,10 +199,10 @@ void RampUpTester::ModifyVideoConfigs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rtx_) {
|
if (rtx_) {
|
||||||
recv_config.rtp.rtx[send_config->encoder_settings.payload_type].ssrc =
|
recv_config.rtp.rtx_ssrc = video_rtx_ssrcs_[i];
|
||||||
video_rtx_ssrcs_[i];
|
recv_config.rtp
|
||||||
recv_config.rtp.rtx[send_config->encoder_settings.payload_type]
|
.rtx_payload_types[send_config->encoder_settings.payload_type] =
|
||||||
.payload_type = send_config->rtp.rtx.payload_type;
|
send_config->rtp.rtx.payload_type;
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -242,11 +242,11 @@ void RtcEventLogImpl::LogVideoReceiveStreamConfig(
|
|||||||
receiver_config->set_rtcp_mode(ConvertRtcpMode(config.rtp.rtcp_mode));
|
receiver_config->set_rtcp_mode(ConvertRtcpMode(config.rtp.rtcp_mode));
|
||||||
receiver_config->set_remb(config.rtp.remb);
|
receiver_config->set_remb(config.rtp.remb);
|
||||||
|
|
||||||
for (const auto& kv : config.rtp.rtx) {
|
for (const auto& kv : config.rtp.rtx_payload_types) {
|
||||||
rtclog::RtxMap* rtx = receiver_config->add_rtx_map();
|
rtclog::RtxMap* rtx = receiver_config->add_rtx_map();
|
||||||
rtx->set_payload_type(kv.first);
|
rtx->set_payload_type(kv.first);
|
||||||
rtx->mutable_config()->set_rtx_ssrc(kv.second.ssrc);
|
rtx->mutable_config()->set_rtx_ssrc(config.rtp.rtx_ssrc);
|
||||||
rtx->mutable_config()->set_rtx_payload_type(kv.second.payload_type);
|
rtx->mutable_config()->set_rtx_payload_type(kv.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& e : config.rtp.extensions) {
|
for (const auto& e : config.rtp.extensions) {
|
||||||
|
|||||||
@ -10,8 +10,10 @@
|
|||||||
|
|
||||||
#include "webrtc/logging/rtc_event_log/rtc_event_log_parser.h"
|
#include "webrtc/logging/rtc_event_log/rtc_event_log_parser.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -314,17 +316,30 @@ void ParsedRtcEventLog::GetVideoReceiveConfig(
|
|||||||
RTC_CHECK(receiver_config.has_remb());
|
RTC_CHECK(receiver_config.has_remb());
|
||||||
config->rtp.remb = receiver_config.remb();
|
config->rtp.remb = receiver_config.remb();
|
||||||
// Get RTX map.
|
// Get RTX map.
|
||||||
config->rtp.rtx.clear();
|
std::vector<uint32_t> rtx_ssrcs(receiver_config.rtx_map_size());
|
||||||
|
config->rtp.rtx_payload_types.clear();
|
||||||
for (int i = 0; i < receiver_config.rtx_map_size(); i++) {
|
for (int i = 0; i < receiver_config.rtx_map_size(); i++) {
|
||||||
const rtclog::RtxMap& map = receiver_config.rtx_map(i);
|
const rtclog::RtxMap& map = receiver_config.rtx_map(i);
|
||||||
RTC_CHECK(map.has_payload_type());
|
RTC_CHECK(map.has_payload_type());
|
||||||
RTC_CHECK(map.has_config());
|
RTC_CHECK(map.has_config());
|
||||||
RTC_CHECK(map.config().has_rtx_ssrc());
|
RTC_CHECK(map.config().has_rtx_ssrc());
|
||||||
|
rtx_ssrcs[i] = map.config().rtx_ssrc();
|
||||||
RTC_CHECK(map.config().has_rtx_payload_type());
|
RTC_CHECK(map.config().has_rtx_payload_type());
|
||||||
webrtc::VideoReceiveStream::Config::Rtp::Rtx rtx_pair;
|
config->rtp.rtx_payload_types.insert(
|
||||||
rtx_pair.ssrc = map.config().rtx_ssrc();
|
std::make_pair(map.payload_type(), map.config().rtx_payload_type()));
|
||||||
rtx_pair.payload_type = map.config().rtx_payload_type();
|
}
|
||||||
config->rtp.rtx.insert(std::make_pair(map.payload_type(), rtx_pair));
|
if (!rtx_ssrcs.empty()) {
|
||||||
|
config->rtp.rtx_ssrc = rtx_ssrcs[0];
|
||||||
|
|
||||||
|
auto pred = [&config](uint32_t ssrc) {
|
||||||
|
return ssrc == config->rtp.rtx_ssrc;
|
||||||
|
};
|
||||||
|
if (!std::all_of(rtx_ssrcs.cbegin(), rtx_ssrcs.cend(), pred)) {
|
||||||
|
LOG(LS_WARNING) << "RtcEventLog protobuf contained different SSRCs for "
|
||||||
|
"different received RTX payload types. Will only use "
|
||||||
|
"rtx_ssrc = "
|
||||||
|
<< config->rtp.rtx_ssrc << ".";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Get header extensions.
|
// Get header extensions.
|
||||||
GetHeaderExtensions(&config->rtp.extensions,
|
GetHeaderExtensions(&config->rtp.extensions,
|
||||||
|
|||||||
@ -165,11 +165,10 @@ void GenerateVideoReceiveConfig(uint32_t extensions_bitvector,
|
|||||||
config->rtp.rtcp_mode =
|
config->rtp.rtcp_mode =
|
||||||
prng->Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize;
|
prng->Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize;
|
||||||
config->rtp.remb = prng->Rand<bool>();
|
config->rtp.remb = prng->Rand<bool>();
|
||||||
// Add a map from a payload type to a new ssrc and a new payload type for RTX.
|
config->rtp.rtx_ssrc = prng->Rand<uint32_t>();
|
||||||
VideoReceiveStream::Config::Rtp::Rtx rtx_pair;
|
// Add a map from a payload type to a new payload type for RTX.
|
||||||
rtx_pair.ssrc = prng->Rand<uint32_t>();
|
config->rtp.rtx_payload_types.insert(
|
||||||
rtx_pair.payload_type = prng->Rand(0, 127);
|
std::make_pair(prng->Rand(0, 127), prng->Rand(0, 127)));
|
||||||
config->rtp.rtx.insert(std::make_pair(prng->Rand(0, 127), rtx_pair));
|
|
||||||
// Add header extensions.
|
// Add header extensions.
|
||||||
for (unsigned i = 0; i < kNumExtensions; i++) {
|
for (unsigned i = 0; i < kNumExtensions; i++) {
|
||||||
if (extensions_bitvector & (1u << i)) {
|
if (extensions_bitvector & (1u << i)) {
|
||||||
|
|||||||
@ -127,19 +127,18 @@ void RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig(
|
|||||||
ASSERT_TRUE(receiver_config.has_remb());
|
ASSERT_TRUE(receiver_config.has_remb());
|
||||||
EXPECT_EQ(config.rtp.remb, receiver_config.remb());
|
EXPECT_EQ(config.rtp.remb, receiver_config.remb());
|
||||||
// Check RTX map.
|
// Check RTX map.
|
||||||
ASSERT_EQ(static_cast<int>(config.rtp.rtx.size()),
|
ASSERT_EQ(static_cast<int>(config.rtp.rtx_payload_types.size()),
|
||||||
receiver_config.rtx_map_size());
|
receiver_config.rtx_map_size());
|
||||||
for (const rtclog::RtxMap& rtx_map : receiver_config.rtx_map()) {
|
for (const rtclog::RtxMap& rtx_map : receiver_config.rtx_map()) {
|
||||||
ASSERT_TRUE(rtx_map.has_payload_type());
|
ASSERT_TRUE(rtx_map.has_payload_type());
|
||||||
ASSERT_TRUE(rtx_map.has_config());
|
ASSERT_TRUE(rtx_map.has_config());
|
||||||
EXPECT_EQ(1u, config.rtp.rtx.count(rtx_map.payload_type()));
|
EXPECT_EQ(1u, config.rtp.rtx_payload_types.count(rtx_map.payload_type()));
|
||||||
const rtclog::RtxConfig& rtx_config = rtx_map.config();
|
const rtclog::RtxConfig& rtx_config = rtx_map.config();
|
||||||
const VideoReceiveStream::Config::Rtp::Rtx& rtx =
|
|
||||||
config.rtp.rtx.at(rtx_map.payload_type());
|
|
||||||
ASSERT_TRUE(rtx_config.has_rtx_ssrc());
|
ASSERT_TRUE(rtx_config.has_rtx_ssrc());
|
||||||
ASSERT_TRUE(rtx_config.has_rtx_payload_type());
|
ASSERT_TRUE(rtx_config.has_rtx_payload_type());
|
||||||
EXPECT_EQ(rtx.ssrc, rtx_config.rtx_ssrc());
|
EXPECT_EQ(config.rtp.rtx_ssrc, rtx_config.rtx_ssrc());
|
||||||
EXPECT_EQ(rtx.payload_type, rtx_config.rtx_payload_type());
|
EXPECT_EQ(config.rtp.rtx_payload_types.at(rtx_map.payload_type()),
|
||||||
|
rtx_config.rtx_payload_type());
|
||||||
}
|
}
|
||||||
// Check header extensions.
|
// Check header extensions.
|
||||||
ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
|
ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
|
||||||
@ -173,12 +172,13 @@ void RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig(
|
|||||||
EXPECT_EQ(config.rtp.rtcp_mode, parsed_config.rtp.rtcp_mode);
|
EXPECT_EQ(config.rtp.rtcp_mode, parsed_config.rtp.rtcp_mode);
|
||||||
EXPECT_EQ(config.rtp.remb, parsed_config.rtp.remb);
|
EXPECT_EQ(config.rtp.remb, parsed_config.rtp.remb);
|
||||||
// Check RTX map.
|
// Check RTX map.
|
||||||
EXPECT_EQ(config.rtp.rtx.size(), parsed_config.rtp.rtx.size());
|
EXPECT_EQ(config.rtp.rtx_ssrc, parsed_config.rtp.rtx_ssrc);
|
||||||
for (const auto& kv : config.rtp.rtx) {
|
EXPECT_EQ(config.rtp.rtx_payload_types.size(),
|
||||||
auto parsed_kv = parsed_config.rtp.rtx.find(kv.first);
|
parsed_config.rtp.rtx_payload_types.size());
|
||||||
|
for (const auto& kv : config.rtp.rtx_payload_types) {
|
||||||
|
auto parsed_kv = parsed_config.rtp.rtx_payload_types.find(kv.first);
|
||||||
EXPECT_EQ(kv.first, parsed_kv->first);
|
EXPECT_EQ(kv.first, parsed_kv->first);
|
||||||
EXPECT_EQ(kv.second.ssrc, parsed_kv->second.ssrc);
|
EXPECT_EQ(kv.second, parsed_kv->second);
|
||||||
EXPECT_EQ(kv.second.payload_type, parsed_kv->second.payload_type);
|
|
||||||
}
|
}
|
||||||
// Check header extensions.
|
// Check header extensions.
|
||||||
EXPECT_EQ(config.rtp.extensions.size(), parsed_config.rtp.extensions.size());
|
EXPECT_EQ(config.rtp.extensions.size(), parsed_config.rtp.extensions.size());
|
||||||
|
|||||||
@ -1233,16 +1233,7 @@ void WebRtcVideoChannel2::ConfigureReceiverRtp(
|
|||||||
flexfec_config->rtp_header_extensions = config->rtp.extensions;
|
flexfec_config->rtp_header_extensions = config->rtp.extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < recv_codecs_.size(); ++i) {
|
sp.GetFidSsrc(ssrc, &config->rtp.rtx_ssrc);
|
||||||
uint32_t rtx_ssrc;
|
|
||||||
if (recv_codecs_[i].rtx_payload_type != -1 &&
|
|
||||||
sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
|
|
||||||
webrtc::VideoReceiveStream::Config::Rtp::Rtx& rtx =
|
|
||||||
config->rtp.rtx[recv_codecs_[i].codec.id];
|
|
||||||
rtx.ssrc = rtx_ssrc;
|
|
||||||
rtx.payload_type = recv_codecs_[i].rtx_payload_type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config->rtp.extensions = recv_rtp_extensions_;
|
config->rtp.extensions = recv_rtp_extensions_;
|
||||||
}
|
}
|
||||||
@ -2205,7 +2196,12 @@ void WebRtcVideoChannel2::WebRtcVideoReceiveStream::ConfigureCodecs(
|
|||||||
config_.decoders.push_back(decoder);
|
config_.decoders.push_back(decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pbos): Reconfigure RTX based on incoming recv_codecs.
|
config_.rtp.rtx_payload_types.clear();
|
||||||
|
for (const VideoCodecSettings& recv_codec : recv_codecs) {
|
||||||
|
config_.rtp.rtx_payload_types[recv_codec.codec.id] =
|
||||||
|
recv_codec.rtx_payload_type;
|
||||||
|
}
|
||||||
|
|
||||||
config_.rtp.ulpfec = recv_codecs.front().ulpfec;
|
config_.rtp.ulpfec = recv_codecs.front().ulpfec;
|
||||||
flexfec_config_.payload_type = recv_codecs.front().flexfec_payload_type;
|
flexfec_config_.payload_type = recv_codecs.front().flexfec_payload_type;
|
||||||
|
|
||||||
|
|||||||
@ -1228,13 +1228,11 @@ TEST_F(WebRtcVideoChannel2Test, RecvStreamWithSimAndRtx) {
|
|||||||
// Receiver side.
|
// Receiver side.
|
||||||
FakeVideoReceiveStream* recv_stream = AddRecvStream(
|
FakeVideoReceiveStream* recv_stream = AddRecvStream(
|
||||||
cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs));
|
cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs));
|
||||||
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx.empty());
|
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx_payload_types.empty());
|
||||||
EXPECT_EQ(recv_stream->GetConfig().decoders.size(),
|
EXPECT_EQ(recv_stream->GetConfig().decoders.size(),
|
||||||
recv_stream->GetConfig().rtp.rtx.size())
|
recv_stream->GetConfig().rtp.rtx_payload_types.size())
|
||||||
<< "RTX should be mapped for all decoders/payload types.";
|
<< "RTX should be mapped for all decoders/payload types.";
|
||||||
for (const auto& kv : recv_stream->GetConfig().rtp.rtx) {
|
EXPECT_EQ(rtx_ssrcs[0], recv_stream->GetConfig().rtp.rtx_ssrc);
|
||||||
EXPECT_EQ(rtx_ssrcs[0], kv.second.ssrc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
|
TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
|
||||||
@ -1243,8 +1241,7 @@ TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
|
|||||||
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
|
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
|
||||||
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
|
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
|
||||||
FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
|
FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
|
||||||
EXPECT_EQ(kRtxSsrcs1[0],
|
EXPECT_EQ(kRtxSsrcs1[0], recv_stream->GetConfig().rtp.rtx_ssrc);
|
||||||
recv_stream->GetConfig().rtp.rtx.begin()->second.ssrc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannel2Test, RecvStreamNoRtx) {
|
TEST_F(WebRtcVideoChannel2Test, RecvStreamNoRtx) {
|
||||||
@ -1252,7 +1249,7 @@ TEST_F(WebRtcVideoChannel2Test, RecvStreamNoRtx) {
|
|||||||
cricket::StreamParams params =
|
cricket::StreamParams params =
|
||||||
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
|
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
|
||||||
FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
|
FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
|
||||||
ASSERT_TRUE(recv_stream->GetConfig().rtp.rtx.empty());
|
ASSERT_EQ(0U, recv_stream->GetConfig().rtp.rtx_ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannel2Test, NoHeaderExtesionsByDefault) {
|
TEST_F(WebRtcVideoChannel2Test, NoHeaderExtesionsByDefault) {
|
||||||
@ -2482,6 +2479,43 @@ TEST_F(WebRtcVideoChannel2Test,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithChangedRtxPayloadType) {
|
||||||
|
const int kUnusedPayloadType1 = 126;
|
||||||
|
const int kUnusedPayloadType2 = 127;
|
||||||
|
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType1));
|
||||||
|
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType2));
|
||||||
|
|
||||||
|
// SSRCs for RTX.
|
||||||
|
cricket::StreamParams params =
|
||||||
|
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
|
||||||
|
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
|
||||||
|
AddSendStream(params);
|
||||||
|
|
||||||
|
// Original payload type for RTX.
|
||||||
|
cricket::VideoSendParameters parameters;
|
||||||
|
parameters.codecs.push_back(GetEngineCodec("VP8"));
|
||||||
|
cricket::VideoCodec rtx_codec(kUnusedPayloadType1, "rtx");
|
||||||
|
rtx_codec.SetParam("apt", GetEngineCodec("VP8").id);
|
||||||
|
parameters.codecs.push_back(rtx_codec);
|
||||||
|
EXPECT_TRUE(channel_->SetSendParameters(parameters));
|
||||||
|
ASSERT_EQ(1U, fake_call_->GetVideoSendStreams().size());
|
||||||
|
const webrtc::VideoSendStream::Config& config_before =
|
||||||
|
fake_call_->GetVideoSendStreams()[0]->GetConfig();
|
||||||
|
EXPECT_EQ(kUnusedPayloadType1, config_before.rtp.rtx.payload_type);
|
||||||
|
ASSERT_EQ(1U, config_before.rtp.rtx.ssrcs.size());
|
||||||
|
EXPECT_EQ(kRtxSsrcs1[0], config_before.rtp.rtx.ssrcs[0]);
|
||||||
|
|
||||||
|
// Change payload type for RTX.
|
||||||
|
parameters.codecs[1].id = kUnusedPayloadType2;
|
||||||
|
EXPECT_TRUE(channel_->SetSendParameters(parameters));
|
||||||
|
ASSERT_EQ(1U, fake_call_->GetVideoSendStreams().size());
|
||||||
|
const webrtc::VideoSendStream::Config& config_after =
|
||||||
|
fake_call_->GetVideoSendStreams()[0]->GetConfig();
|
||||||
|
EXPECT_EQ(kUnusedPayloadType2, config_after.rtp.rtx.payload_type);
|
||||||
|
ASSERT_EQ(1U, config_after.rtp.rtx.ssrcs.size());
|
||||||
|
EXPECT_EQ(kRtxSsrcs1[0], config_after.rtp.rtx.ssrcs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithoutFecDisablesFec) {
|
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithoutFecDisablesFec) {
|
||||||
cricket::VideoSendParameters parameters;
|
cricket::VideoSendParameters parameters;
|
||||||
parameters.codecs.push_back(GetEngineCodec("VP8"));
|
parameters.codecs.push_back(GetEngineCodec("VP8"));
|
||||||
@ -2812,6 +2846,49 @@ TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithRtx) {
|
|||||||
"rejected.";
|
"rejected.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithChangedRtxPayloadType) {
|
||||||
|
const int kUnusedPayloadType1 = 126;
|
||||||
|
const int kUnusedPayloadType2 = 127;
|
||||||
|
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType1));
|
||||||
|
EXPECT_FALSE(FindCodecById(engine_.codecs(), kUnusedPayloadType2));
|
||||||
|
|
||||||
|
// SSRCs for RTX.
|
||||||
|
cricket::StreamParams params =
|
||||||
|
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
|
||||||
|
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
|
||||||
|
AddRecvStream(params);
|
||||||
|
|
||||||
|
// Original payload type for RTX.
|
||||||
|
cricket::VideoRecvParameters parameters;
|
||||||
|
parameters.codecs.push_back(GetEngineCodec("VP8"));
|
||||||
|
cricket::VideoCodec rtx_codec(kUnusedPayloadType1, "rtx");
|
||||||
|
rtx_codec.SetParam("apt", GetEngineCodec("VP8").id);
|
||||||
|
parameters.codecs.push_back(rtx_codec);
|
||||||
|
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
|
||||||
|
ASSERT_EQ(1U, fake_call_->GetVideoReceiveStreams().size());
|
||||||
|
const webrtc::VideoReceiveStream::Config& config_before =
|
||||||
|
fake_call_->GetVideoReceiveStreams()[0]->GetConfig();
|
||||||
|
EXPECT_EQ(1U, config_before.rtp.rtx_payload_types.size());
|
||||||
|
auto it_before =
|
||||||
|
config_before.rtp.rtx_payload_types.find(GetEngineCodec("VP8").id);
|
||||||
|
ASSERT_NE(it_before, config_before.rtp.rtx_payload_types.end());
|
||||||
|
EXPECT_EQ(kUnusedPayloadType1, it_before->second);
|
||||||
|
EXPECT_EQ(kRtxSsrcs1[0], config_before.rtp.rtx_ssrc);
|
||||||
|
|
||||||
|
// Change payload type for RTX.
|
||||||
|
parameters.codecs[1].id = kUnusedPayloadType2;
|
||||||
|
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
|
||||||
|
ASSERT_EQ(1U, fake_call_->GetVideoReceiveStreams().size());
|
||||||
|
const webrtc::VideoReceiveStream::Config& config_after =
|
||||||
|
fake_call_->GetVideoReceiveStreams()[0]->GetConfig();
|
||||||
|
EXPECT_EQ(1U, config_after.rtp.rtx_payload_types.size());
|
||||||
|
auto it_after =
|
||||||
|
config_after.rtp.rtx_payload_types.find(GetEngineCodec("VP8").id);
|
||||||
|
ASSERT_NE(it_after, config_after.rtp.rtx_payload_types.end());
|
||||||
|
EXPECT_EQ(kUnusedPayloadType2, it_after->second);
|
||||||
|
EXPECT_EQ(kRtxSsrcs1[0], config_after.rtp.rtx_ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsDifferentPayloadType) {
|
TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsDifferentPayloadType) {
|
||||||
cricket::VideoRecvParameters parameters;
|
cricket::VideoRecvParameters parameters;
|
||||||
parameters.codecs.push_back(GetEngineCodec("VP8"));
|
parameters.codecs.push_back(GetEngineCodec("VP8"));
|
||||||
@ -3441,21 +3518,19 @@ TEST_F(WebRtcVideoChannel2Test, DefaultReceiveStreamReconfiguresToUseRtx) {
|
|||||||
ASSERT_EQ(1u, fake_call_->GetVideoReceiveStreams().size())
|
ASSERT_EQ(1u, fake_call_->GetVideoReceiveStreams().size())
|
||||||
<< "No default receive stream created.";
|
<< "No default receive stream created.";
|
||||||
FakeVideoReceiveStream* recv_stream = fake_call_->GetVideoReceiveStreams()[0];
|
FakeVideoReceiveStream* recv_stream = fake_call_->GetVideoReceiveStreams()[0];
|
||||||
EXPECT_TRUE(recv_stream->GetConfig().rtp.rtx.empty())
|
EXPECT_EQ(0u, recv_stream->GetConfig().rtp.rtx_ssrc)
|
||||||
<< "Default receive stream should not have configured RTX";
|
<< "Default receive stream should not have configured RTX";
|
||||||
|
|
||||||
EXPECT_TRUE(channel_->AddRecvStream(
|
EXPECT_TRUE(channel_->AddRecvStream(
|
||||||
cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs)));
|
cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs)));
|
||||||
ASSERT_EQ(1u, fake_call_->GetVideoReceiveStreams().size())
|
ASSERT_EQ(1u, fake_call_->GetVideoReceiveStreams().size())
|
||||||
<< "AddRecvStream should've reconfigured, not added a new receiver.";
|
<< "AddRecvStream should have reconfigured, not added a new receiver.";
|
||||||
recv_stream = fake_call_->GetVideoReceiveStreams()[0];
|
recv_stream = fake_call_->GetVideoReceiveStreams()[0];
|
||||||
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx.empty());
|
EXPECT_FALSE(recv_stream->GetConfig().rtp.rtx_payload_types.empty());
|
||||||
EXPECT_EQ(recv_stream->GetConfig().decoders.size(),
|
EXPECT_EQ(recv_stream->GetConfig().decoders.size(),
|
||||||
recv_stream->GetConfig().rtp.rtx.size())
|
recv_stream->GetConfig().rtp.rtx_payload_types.size())
|
||||||
<< "RTX should be mapped for all decoders/payload types.";
|
<< "RTX should be mapped for all decoders/payload types.";
|
||||||
for (const auto& kv : recv_stream->GetConfig().rtp.rtx) {
|
EXPECT_EQ(rtx_ssrcs[0], recv_stream->GetConfig().rtp.rtx_ssrc);
|
||||||
EXPECT_EQ(rtx_ssrcs[0], kv.second.ssrc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannel2Test, RejectsAddingStreamsWithMissingSsrcsForRtx) {
|
TEST_F(WebRtcVideoChannel2Test, RejectsAddingStreamsWithMissingSsrcsForRtx) {
|
||||||
|
|||||||
@ -311,13 +311,11 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
|
|||||||
StreamId stream(config.rtp.remote_ssrc, kIncomingPacket);
|
StreamId stream(config.rtp.remote_ssrc, kIncomingPacket);
|
||||||
extension_maps[stream] = RtpHeaderExtensionMap(config.rtp.extensions);
|
extension_maps[stream] = RtpHeaderExtensionMap(config.rtp.extensions);
|
||||||
video_ssrcs_.insert(stream);
|
video_ssrcs_.insert(stream);
|
||||||
for (auto kv : config.rtp.rtx) {
|
StreamId rtx_stream(config.rtp.rtx_ssrc, kIncomingPacket);
|
||||||
StreamId rtx_stream(kv.second.ssrc, kIncomingPacket);
|
|
||||||
extension_maps[rtx_stream] =
|
extension_maps[rtx_stream] =
|
||||||
RtpHeaderExtensionMap(config.rtp.extensions);
|
RtpHeaderExtensionMap(config.rtp.extensions);
|
||||||
video_ssrcs_.insert(rtx_stream);
|
video_ssrcs_.insert(rtx_stream);
|
||||||
rtx_ssrcs_.insert(rtx_stream);
|
rtx_ssrcs_.insert(rtx_stream);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT: {
|
case ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT: {
|
||||||
|
|||||||
@ -1091,8 +1091,8 @@ void EndToEndTest::DecodesRetransmittedFrame(bool enable_rtx, bool enable_red) {
|
|||||||
if (retransmission_ssrc_ == kSendRtxSsrcs[0]) {
|
if (retransmission_ssrc_ == kSendRtxSsrcs[0]) {
|
||||||
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
||||||
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
||||||
(*receive_configs)[0].rtp.rtx[payload_type_].ssrc = kSendRtxSsrcs[0];
|
(*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
|
||||||
(*receive_configs)[0].rtp.rtx[payload_type_].payload_type =
|
(*receive_configs)[0].rtp.rtx_payload_types[payload_type_] =
|
||||||
kSendRtxPayloadType;
|
kSendRtxPayloadType;
|
||||||
}
|
}
|
||||||
// Configure encoding and decoding with VP8, since generic packetization
|
// Configure encoding and decoding with VP8, since generic packetization
|
||||||
@ -2331,9 +2331,8 @@ void EndToEndTest::VerifyHistogramStats(bool use_rtx,
|
|||||||
if (use_rtx_) {
|
if (use_rtx_) {
|
||||||
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
|
||||||
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
|
||||||
(*receive_configs)[0].rtp.rtx[kFakeVideoSendPayloadType].ssrc =
|
(*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
|
||||||
kSendRtxSsrcs[0];
|
(*receive_configs)[0].rtp.rtx_payload_types[kFakeVideoSendPayloadType] =
|
||||||
(*receive_configs)[0].rtp.rtx[kFakeVideoSendPayloadType].payload_type =
|
|
||||||
kSendRtxPayloadType;
|
kSendRtxPayloadType;
|
||||||
}
|
}
|
||||||
// RTT needed for RemoteNtpTimeEstimator for the receive stream.
|
// RTT needed for RemoteNtpTimeEstimator for the receive stream.
|
||||||
@ -2953,9 +2952,8 @@ TEST_P(EndToEndTest, GetStats) {
|
|||||||
(*receive_configs)[i].renderer = &receive_stream_renderer_;
|
(*receive_configs)[i].renderer = &receive_stream_renderer_;
|
||||||
(*receive_configs)[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
(*receive_configs)[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
||||||
|
|
||||||
(*receive_configs)[i].rtp.rtx[kFakeVideoSendPayloadType].ssrc =
|
(*receive_configs)[i].rtp.rtx_ssrc = kSendRtxSsrcs[i];
|
||||||
kSendRtxSsrcs[i];
|
(*receive_configs)[i].rtp.rtx_payload_types[kFakeVideoSendPayloadType] =
|
||||||
(*receive_configs)[i].rtp.rtx[kFakeVideoSendPayloadType].payload_type =
|
|
||||||
kSendRtxPayloadType;
|
kSendRtxPayloadType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3939,7 +3937,9 @@ TEST_P(EndToEndTest, VerifyDefaultVideoReceiveConfigParameters) {
|
|||||||
EXPECT_FALSE(
|
EXPECT_FALSE(
|
||||||
default_receive_config.rtp.rtcp_xr.receiver_reference_time_report)
|
default_receive_config.rtp.rtcp_xr.receiver_reference_time_report)
|
||||||
<< "RTCP XR settings require rtcp-xr to be negotiated.";
|
<< "RTCP XR settings require rtcp-xr to be negotiated.";
|
||||||
EXPECT_TRUE(default_receive_config.rtp.rtx.empty())
|
EXPECT_EQ(0U, default_receive_config.rtp.rtx_ssrc)
|
||||||
|
<< "Enabling RTX requires ssrc-group: FID negotiation";
|
||||||
|
EXPECT_TRUE(default_receive_config.rtp.rtx_payload_types.empty())
|
||||||
<< "Enabling RTX requires rtpmap: rtx negotiation.";
|
<< "Enabling RTX requires rtpmap: rtx negotiation.";
|
||||||
EXPECT_TRUE(default_receive_config.rtp.extensions.empty())
|
EXPECT_TRUE(default_receive_config.rtp.extensions.empty())
|
||||||
<< "Enabling RTP extensions require negotiation.";
|
<< "Enabling RTP extensions require negotiation.";
|
||||||
|
|||||||
@ -78,8 +78,11 @@ ReceiveStatisticsProxy::ReceiveStatisticsProxy(
|
|||||||
avg_rtt_ms_(0),
|
avg_rtt_ms_(0),
|
||||||
frame_window_accumulated_bytes_(0) {
|
frame_window_accumulated_bytes_(0) {
|
||||||
stats_.ssrc = config_.rtp.remote_ssrc;
|
stats_.ssrc = config_.rtp.remote_ssrc;
|
||||||
for (auto it : config_.rtp.rtx)
|
// TODO(brandtr): Replace |rtx_stats_| with a single instance of
|
||||||
rtx_stats_[it.second.ssrc] = StreamDataCounters();
|
// StreamDataCounters.
|
||||||
|
if (config_.rtp.rtx_ssrc) {
|
||||||
|
rtx_stats_[config_.rtp.rtx_ssrc] = StreamDataCounters();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReceiveStatisticsProxy::~ReceiveStatisticsProxy() {
|
ReceiveStatisticsProxy::~ReceiveStatisticsProxy() {
|
||||||
|
|||||||
@ -150,14 +150,13 @@ RtpStreamReceiver::RtpStreamReceiver(
|
|||||||
: kDefaultMaxReorderingThreshold;
|
: kDefaultMaxReorderingThreshold;
|
||||||
rtp_receive_statistics_->SetMaxReorderingThreshold(max_reordering_threshold);
|
rtp_receive_statistics_->SetMaxReorderingThreshold(max_reordering_threshold);
|
||||||
|
|
||||||
// TODO(pbos): Support multiple RTX, per video payload.
|
if (config_.rtp.rtx_ssrc) {
|
||||||
for (const auto& kv : config_.rtp.rtx) {
|
rtp_payload_registry_.SetRtxSsrc(config_.rtp.rtx_ssrc);
|
||||||
RTC_DCHECK(kv.second.ssrc != 0);
|
|
||||||
RTC_DCHECK(kv.second.payload_type != 0);
|
|
||||||
|
|
||||||
rtp_payload_registry_.SetRtxSsrc(kv.second.ssrc);
|
for (const auto& kv : config_.rtp.rtx_payload_types) {
|
||||||
rtp_payload_registry_.SetRtxPayloadType(kv.second.payload_type,
|
RTC_DCHECK(kv.second != 0);
|
||||||
kv.first);
|
rtp_payload_registry_.SetRtxPayloadType(kv.second, kv.first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsUlpfecEnabled()) {
|
if (IsUlpfecEnabled()) {
|
||||||
|
|||||||
@ -1124,8 +1124,8 @@ void VideoQualityTest::SetupVideo(Transport* send_transport,
|
|||||||
|
|
||||||
for (size_t i = 0; i < num_video_streams; ++i) {
|
for (size_t i = 0; i < num_video_streams; ++i) {
|
||||||
video_receive_configs_[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
video_receive_configs_[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
|
||||||
video_receive_configs_[i].rtp.rtx[payload_type].ssrc = kSendRtxSsrcs[i];
|
video_receive_configs_[i].rtp.rtx_ssrc = kSendRtxSsrcs[i];
|
||||||
video_receive_configs_[i].rtp.rtx[payload_type].payload_type =
|
video_receive_configs_[i].rtp.rtx_payload_types[payload_type] =
|
||||||
kSendRtxPayloadType;
|
kSendRtxPayloadType;
|
||||||
video_receive_configs_[i].rtp.transport_cc = params_.call.send_side_bwe;
|
video_receive_configs_[i].rtp.transport_cc = params_.call.send_side_bwe;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,12 +100,10 @@ std::string VideoReceiveStream::Config::Rtp::ToString() const {
|
|||||||
ss << ", transport_cc: " << (transport_cc ? "on" : "off");
|
ss << ", transport_cc: " << (transport_cc ? "on" : "off");
|
||||||
ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
|
ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
|
||||||
ss << ", ulpfec: " << ulpfec.ToString();
|
ss << ", ulpfec: " << ulpfec.ToString();
|
||||||
ss << ", rtx: {";
|
ss << ", rtx_ssrc: " << rtx_ssrc;
|
||||||
for (auto& kv : rtx) {
|
ss << ", rtx_payload_types: {";
|
||||||
ss << kv.first << " -> ";
|
for (auto& kv : rtx_payload_types) {
|
||||||
ss << "{ssrc: " << kv.second.ssrc;
|
ss << kv.first << " (apt) -> " << kv.second << " (pt), ";
|
||||||
ss << ", payload_type: " << kv.second.payload_type;
|
|
||||||
ss << '}';
|
|
||||||
}
|
}
|
||||||
ss << '}';
|
ss << '}';
|
||||||
ss << ", extensions: [";
|
ss << ", extensions: [";
|
||||||
|
|||||||
@ -117,6 +117,7 @@ class VideoReceiveStream {
|
|||||||
|
|
||||||
// Synchronization source (stream identifier) to be received.
|
// Synchronization source (stream identifier) to be received.
|
||||||
uint32_t remote_ssrc = 0;
|
uint32_t remote_ssrc = 0;
|
||||||
|
|
||||||
// Sender SSRC used for sending RTCP (such as receiver reports).
|
// Sender SSRC used for sending RTCP (such as receiver reports).
|
||||||
uint32_t local_ssrc = 0;
|
uint32_t local_ssrc = 0;
|
||||||
|
|
||||||
@ -142,19 +143,12 @@ class VideoReceiveStream {
|
|||||||
// See UlpfecConfig for description.
|
// See UlpfecConfig for description.
|
||||||
UlpfecConfig ulpfec;
|
UlpfecConfig ulpfec;
|
||||||
|
|
||||||
// RTX settings for incoming video payloads that may be received. RTX is
|
// SSRC for retransmissions.
|
||||||
// disabled if there's no config present.
|
uint32_t rtx_ssrc = 0;
|
||||||
struct Rtx {
|
|
||||||
// SSRCs to use for the RTX streams.
|
|
||||||
uint32_t ssrc = 0;
|
|
||||||
|
|
||||||
// Payload type to use for the RTX stream.
|
// Map from video payload type (apt) -> RTX payload type (pt).
|
||||||
int payload_type = 0;
|
// For RTX to be enabled, both an SSRC and this mapping are needed.
|
||||||
};
|
std::map<int, int> rtx_payload_types;
|
||||||
|
|
||||||
// Map from video RTP payload type -> RTX config.
|
|
||||||
typedef std::map<int, Rtx> RtxMap;
|
|
||||||
RtxMap rtx;
|
|
||||||
|
|
||||||
// RTP header extensions used for the received stream.
|
// RTP header extensions used for the received stream.
|
||||||
std::vector<RtpExtension> extensions;
|
std::vector<RtpExtension> extensions;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user