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:
pbos@webrtc.org 2013-11-28 11:59:31 +00:00
parent d1a1c353ac
commit 13d38a13e3
4 changed files with 114 additions and 38 deletions

View File

@ -215,8 +215,7 @@ VideoSendStream::Config Call::GetDefaultSendConfig() {
VideoSendStream* Call::CreateVideoSendStream(
const VideoSendStream::Config& config) {
assert(config.rtp.ssrcs.size() > 0);
assert(config.codec.numberOfSimulcastStreams == 0 ||
config.codec.numberOfSimulcastStreams == config.rtp.ssrcs.size());
assert(config.rtp.ssrcs.size() >= config.codec.numberOfSimulcastStreams);
VideoSendStream* send_stream = new VideoSendStream(
config_.send_transport, config_.overuse_detection, video_engine_, config);

View File

@ -43,7 +43,9 @@ class RtpRtcpObserver {
}
virtual EventTypeWrapper Wait() {
return observation_complete_->Wait(timeout_ms_);
EventTypeWrapper result = observation_complete_->Wait(timeout_ms_);
observation_complete_->Reset();
return result;
}
protected:

View File

@ -95,33 +95,9 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
assert(rtp_rtcp_ != NULL);
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)
config_.pacing = true;
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) {
const std::string& extension = config_.rtp.extensions[i].name;
@ -279,14 +255,37 @@ void VideoSendStream::StopSending() {
}
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());
if (codec_->SetSendCodec(channel_, codec) != 0)
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;
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;
}

View File

@ -74,6 +74,8 @@ class VideoSendStreamTest : public ::testing::Test {
uint8_t retransmit_payload_type,
bool enable_pacing);
void SendsSetSsrcs(size_t num_ssrcs, bool send_single_ssrc_first);
enum { kNumSendSsrcs = 3 };
static const uint8_t kSendPayloadType;
static const uint8_t kSendRtxPayloadType;
@ -95,30 +97,104 @@ const uint32_t VideoSendStreamTest::kSendSsrcs[kNumSendSsrcs] = { 0xC0FFED,
const uint32_t VideoSendStreamTest::kSendSsrc =
VideoSendStreamTest::kSendSsrcs[0];
TEST_F(VideoSendStreamTest, SendsSetSsrc) {
void VideoSendStreamTest::SendsSetSsrcs(size_t num_ssrcs,
bool send_single_ssrc_first) {
class SendSsrcObserver : public test::RtpRtcpObserver {
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 {
RTPHeader header;
EXPECT_TRUE(
parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(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();
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());
scoped_ptr<Call> call(Call::Create(call_config));
VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1);
send_config.rtp.max_packet_size = 128;
VideoSendStream::Config send_config =
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) {