Set up SSRCs correctly after switching codec.
Before SSRCs were not set up correctly, as the old VideoEngine API doesn't support setting additional SSRCs before a codec with as many streams are set. No test was in place to catch this, so two tests are added to make sure that we send the SSRCs that are set, and also that we can switch from using one to using all SSRCs, even though initially not all of them are set up. BUG= R=mflodman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/4539004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5188 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
d1a1c353ac
commit
13d38a13e3
@ -215,8 +215,7 @@ VideoSendStream::Config Call::GetDefaultSendConfig() {
|
|||||||
VideoSendStream* Call::CreateVideoSendStream(
|
VideoSendStream* Call::CreateVideoSendStream(
|
||||||
const VideoSendStream::Config& config) {
|
const VideoSendStream::Config& config) {
|
||||||
assert(config.rtp.ssrcs.size() > 0);
|
assert(config.rtp.ssrcs.size() > 0);
|
||||||
assert(config.codec.numberOfSimulcastStreams == 0 ||
|
assert(config.rtp.ssrcs.size() >= config.codec.numberOfSimulcastStreams);
|
||||||
config.codec.numberOfSimulcastStreams == config.rtp.ssrcs.size());
|
|
||||||
|
|
||||||
VideoSendStream* send_stream = new VideoSendStream(
|
VideoSendStream* send_stream = new VideoSendStream(
|
||||||
config_.send_transport, config_.overuse_detection, video_engine_, config);
|
config_.send_transport, config_.overuse_detection, video_engine_, config);
|
||||||
|
@ -43,7 +43,9 @@ class RtpRtcpObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual EventTypeWrapper Wait() {
|
virtual EventTypeWrapper Wait() {
|
||||||
return observation_complete_->Wait(timeout_ms_);
|
EventTypeWrapper result = observation_complete_->Wait(timeout_ms_);
|
||||||
|
observation_complete_->Reset();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -95,33 +95,9 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
|
|||||||
assert(rtp_rtcp_ != NULL);
|
assert(rtp_rtcp_ != NULL);
|
||||||
|
|
||||||
assert(config_.rtp.ssrcs.size() > 0);
|
assert(config_.rtp.ssrcs.size() > 0);
|
||||||
if (config_.rtp.ssrcs.size() == 1) {
|
|
||||||
rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.ssrcs[0]);
|
|
||||||
} else {
|
|
||||||
for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
|
|
||||||
rtp_rtcp_->SetLocalSSRC(channel_,
|
|
||||||
config_.rtp.ssrcs[i],
|
|
||||||
kViEStreamTypeNormal,
|
|
||||||
static_cast<unsigned char>(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config_.suspend_below_min_bitrate)
|
if (config_.suspend_below_min_bitrate)
|
||||||
config_.pacing = true;
|
config_.pacing = true;
|
||||||
rtp_rtcp_->SetTransmissionSmoothingStatus(channel_, config_.pacing);
|
rtp_rtcp_->SetTransmissionSmoothingStatus(channel_, config_.pacing);
|
||||||
if (!config_.rtp.rtx.ssrcs.empty()) {
|
|
||||||
assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size());
|
|
||||||
for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
|
|
||||||
rtp_rtcp_->SetLocalSSRC(channel_,
|
|
||||||
config_.rtp.rtx.ssrcs[i],
|
|
||||||
kViEStreamTypeRtx,
|
|
||||||
static_cast<unsigned char>(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_.rtp.rtx.rtx_payload_type != 0) {
|
|
||||||
rtp_rtcp_->SetRtxSendPayloadType(channel_,
|
|
||||||
config_.rtp.rtx.rtx_payload_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
|
for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
|
||||||
const std::string& extension = config_.rtp.extensions[i].name;
|
const std::string& extension = config_.rtp.extensions[i].name;
|
||||||
@ -279,14 +255,37 @@ void VideoSendStream::StopSending() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VideoSendStream::SetCodec(const VideoCodec& codec) {
|
bool VideoSendStream::SetCodec(const VideoCodec& codec) {
|
||||||
if (codec.numberOfSimulcastStreams > 0)
|
assert(config_.rtp.ssrcs.size() >= codec.numberOfSimulcastStreams);
|
||||||
assert(config_.rtp.ssrcs.size() >= codec.numberOfSimulcastStreams);
|
|
||||||
|
|
||||||
CriticalSectionScoped crit(codec_lock_.get());
|
CriticalSectionScoped crit(codec_lock_.get());
|
||||||
if (codec_->SetSendCodec(channel_, codec) != 0)
|
if (codec_->SetSendCodec(channel_, codec) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
|
||||||
|
rtp_rtcp_->SetLocalSSRC(channel_,
|
||||||
|
config_.rtp.ssrcs[i],
|
||||||
|
kViEStreamTypeNormal,
|
||||||
|
static_cast<unsigned char>(i));
|
||||||
|
}
|
||||||
|
|
||||||
config_.codec = codec;
|
config_.codec = codec;
|
||||||
|
if (config_.rtp.rtx.ssrcs.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Set up RTX.
|
||||||
|
assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size());
|
||||||
|
for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
|
||||||
|
rtp_rtcp_->SetLocalSSRC(channel_,
|
||||||
|
config_.rtp.rtx.ssrcs[i],
|
||||||
|
kViEStreamTypeRtx,
|
||||||
|
static_cast<unsigned char>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_.rtp.rtx.rtx_payload_type != 0) {
|
||||||
|
rtp_rtcp_->SetRtxSendPayloadType(channel_,
|
||||||
|
config_.rtp.rtx.rtx_payload_type);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,8 @@ class VideoSendStreamTest : public ::testing::Test {
|
|||||||
uint8_t retransmit_payload_type,
|
uint8_t retransmit_payload_type,
|
||||||
bool enable_pacing);
|
bool enable_pacing);
|
||||||
|
|
||||||
|
void SendsSetSsrcs(size_t num_ssrcs, bool send_single_ssrc_first);
|
||||||
|
|
||||||
enum { kNumSendSsrcs = 3 };
|
enum { kNumSendSsrcs = 3 };
|
||||||
static const uint8_t kSendPayloadType;
|
static const uint8_t kSendPayloadType;
|
||||||
static const uint8_t kSendRtxPayloadType;
|
static const uint8_t kSendRtxPayloadType;
|
||||||
@ -95,30 +97,104 @@ const uint32_t VideoSendStreamTest::kSendSsrcs[kNumSendSsrcs] = { 0xC0FFED,
|
|||||||
const uint32_t VideoSendStreamTest::kSendSsrc =
|
const uint32_t VideoSendStreamTest::kSendSsrc =
|
||||||
VideoSendStreamTest::kSendSsrcs[0];
|
VideoSendStreamTest::kSendSsrcs[0];
|
||||||
|
|
||||||
TEST_F(VideoSendStreamTest, SendsSetSsrc) {
|
void VideoSendStreamTest::SendsSetSsrcs(size_t num_ssrcs,
|
||||||
|
bool send_single_ssrc_first) {
|
||||||
class SendSsrcObserver : public test::RtpRtcpObserver {
|
class SendSsrcObserver : public test::RtpRtcpObserver {
|
||||||
public:
|
public:
|
||||||
SendSsrcObserver() : RtpRtcpObserver(30 * 1000) {}
|
SendSsrcObserver(const uint32_t* ssrcs,
|
||||||
|
size_t num_ssrcs,
|
||||||
|
bool send_single_ssrc_first)
|
||||||
|
: RtpRtcpObserver(30 * 1000),
|
||||||
|
ssrcs_to_observe_(num_ssrcs),
|
||||||
|
expect_single_ssrc_(send_single_ssrc_first) {
|
||||||
|
for (size_t i = 0; i < num_ssrcs; ++i)
|
||||||
|
valid_ssrcs_[ssrcs[i]] = true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
|
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
|
||||||
RTPHeader header;
|
RTPHeader header;
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
|
||||||
parser_->Parse(packet, static_cast<int>(length), &header));
|
|
||||||
|
|
||||||
if (header.ssrc == kSendSsrc)
|
EXPECT_TRUE(valid_ssrcs_[header.ssrc])
|
||||||
|
<< "Received unknown SSRC: " << header.ssrc;
|
||||||
|
|
||||||
|
if (!valid_ssrcs_[header.ssrc])
|
||||||
|
observation_complete_->Set();
|
||||||
|
|
||||||
|
if (!is_observed_[header.ssrc]) {
|
||||||
|
is_observed_[header.ssrc] = true;
|
||||||
|
--ssrcs_to_observe_;
|
||||||
|
if (expect_single_ssrc_) {
|
||||||
|
expect_single_ssrc_ = false;
|
||||||
|
observation_complete_->Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssrcs_to_observe_ == 0)
|
||||||
observation_complete_->Set();
|
observation_complete_->Set();
|
||||||
|
|
||||||
return SEND_PACKET;
|
return SEND_PACKET;
|
||||||
}
|
}
|
||||||
} observer;
|
|
||||||
|
private:
|
||||||
|
std::map<uint32_t, bool> valid_ssrcs_;
|
||||||
|
std::map<uint32_t, bool> is_observed_;
|
||||||
|
size_t ssrcs_to_observe_;
|
||||||
|
bool expect_single_ssrc_;
|
||||||
|
} observer(kSendSsrcs, num_ssrcs, send_single_ssrc_first);
|
||||||
|
|
||||||
Call::Config call_config(observer.SendTransport());
|
Call::Config call_config(observer.SendTransport());
|
||||||
scoped_ptr<Call> call(Call::Create(call_config));
|
scoped_ptr<Call> call(Call::Create(call_config));
|
||||||
|
|
||||||
VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1);
|
VideoSendStream::Config send_config =
|
||||||
send_config.rtp.max_packet_size = 128;
|
GetSendTestConfig(call.get(), num_ssrcs);
|
||||||
|
|
||||||
RunSendTest(call.get(), send_config, &observer);
|
if (num_ssrcs > 1) {
|
||||||
|
// Set low simulcast bitrates to not have to wait for bandwidth ramp-up.
|
||||||
|
for (size_t i = 0; i < num_ssrcs; ++i) {
|
||||||
|
send_config.codec.simulcastStream[i].minBitrate = 10;
|
||||||
|
send_config.codec.simulcastStream[i].targetBitrate = 10;
|
||||||
|
send_config.codec.simulcastStream[i].maxBitrate = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_single_ssrc_first)
|
||||||
|
send_config.codec.numberOfSimulcastStreams = 1;
|
||||||
|
|
||||||
|
send_stream_ = call->CreateVideoSendStream(send_config);
|
||||||
|
scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
|
||||||
|
test::FrameGeneratorCapturer::Create(
|
||||||
|
send_stream_->Input(), 320, 240, 30, Clock::GetRealTimeClock()));
|
||||||
|
send_stream_->StartSending();
|
||||||
|
frame_generator_capturer->Start();
|
||||||
|
|
||||||
|
EXPECT_EQ(kEventSignaled, observer.Wait())
|
||||||
|
<< "Timed out while waiting for "
|
||||||
|
<< (send_single_ssrc_first ? "first SSRC." : "SSRCs.");
|
||||||
|
|
||||||
|
if (send_single_ssrc_first) {
|
||||||
|
// Set full simulcast and continue with the rest of the SSRCs.
|
||||||
|
send_config.codec.numberOfSimulcastStreams =
|
||||||
|
static_cast<unsigned char>(num_ssrcs);
|
||||||
|
send_stream_->SetCodec(send_config.codec);
|
||||||
|
EXPECT_EQ(kEventSignaled, observer.Wait())
|
||||||
|
<< "Timed out while waiting on additional SSRCs.";
|
||||||
|
}
|
||||||
|
|
||||||
|
observer.StopSending();
|
||||||
|
frame_generator_capturer->Stop();
|
||||||
|
send_stream_->StopSending();
|
||||||
|
call->DestroyVideoSendStream(send_stream_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VideoSendStreamTest, SendsSetSsrc) { SendsSetSsrcs(1, false); }
|
||||||
|
|
||||||
|
TEST_F(VideoSendStreamTest, SendsSetSimulcastSsrcs) {
|
||||||
|
SendsSetSsrcs(kNumSendSsrcs, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VideoSendStreamTest, CanSwitchToUseAllSsrcs) {
|
||||||
|
SendsSetSsrcs(kNumSendSsrcs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(VideoSendStreamTest, SupportsCName) {
|
TEST_F(VideoSendStreamTest, SupportsCName) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user