Allow multiple REMB groups and introduce receive channels.

BUG=312
TEST=ViE standard autotest and API test.

Review URL: https://webrtc-codereview.appspot.com/432005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1836 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mflodman@webrtc.org 2012-03-05 17:12:41 +00:00
parent 855ced7336
commit 9ec883e8bd
20 changed files with 591 additions and 334 deletions

View File

@ -1662,7 +1662,7 @@ WebRtc_Word32 ModuleRtpRtcpImpl::SetREMBData(const WebRtc_UWord32 bitrate,
}
WebRtc_Word32 ModuleRtpRtcpImpl::SetMaximumBitrateEstimate(
const WebRtc_UWord32 bitrate) {
const WebRtc_UWord32 bitrate) {
if (_defaultModule) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"SetMaximumBitrateEstimate - Should be called on default "

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 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
@ -85,10 +85,22 @@ class WEBRTC_DLLEXPORT ViEBase {
// synchronization.
virtual int SetVoiceEngine(VoiceEngine* voice_engine) = 0;
// Creates a new channel, either with a new encoder instance or by sharing
// encoder instance with an already created channel.
// Creates a new channel.
virtual int CreateChannel(int& video_channel) = 0;
virtual int CreateChannel(int& video_channel, int original_channel) = 0;
// Creates a new channel grouped together with |original_channel|. The channel
// can both send and receive video. It is assumed the channel is sending
// and/or receiving video to the same end-point.
// Note: |CreateReceiveChannel| will give better performance and network
// properties for receive only channels.
virtual int CreateChannel(int& video_channel,
int original_channel) = 0;
// Creates a new channel grouped together with |original_channel|. The channel
// can only receive video and it is assumed the remote end-point is the same
// as for |original_channel|.
virtual int CreateReceiveChannel(int& video_channel,
int original_channel) = 0;
// Deletes an existing channel and releases the utilized resources.
virtual int DeleteChannel(const int video_channel) = 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 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
@ -21,6 +21,7 @@ enum ViEErrors {
kViEBaseInvalidArgument,
kViEBaseAlreadySending, // StartSend called on channel that is already sending.
kViEBaseNotSending, // StopSend called on channel that is not sending.
kViEBaseReceiveOnlyChannel, // Can't send on a receive only channel.
kViEBaseAlreadyReceiving, // StartReceive called on channel that is already receiving.
kViEBaseObserverAlreadyRegistered, // RegisterObserver- an observer has already been set.
kViEBaseObserverNotRegistered, // DeregisterObserver - no observer has been registered.
@ -33,6 +34,7 @@ enum ViEErrors {
kViECodecInvalidCodec, // SetSendCodec,SetReceiveCodec- The codec structure is invalid.
kViECodecInvalidChannelId, // The channel does not exist.
kViECodecInUse, // SetSendCodec- Can't change codec size or type when multiple channels use the same encoder.
kViECodecReceiveOnlyChannel, // SetSendCodec, can't change receive only channel.
kViECodecUnknownError, // An unknown error has occurred. Check the log file.
// ViERender.

View File

@ -133,6 +133,9 @@ void ViEAutoTest::ViEBaseAPITest() {
ptrViEBase = webrtc::ViEBase::GetInterface(ptrViE);
EXPECT_TRUE(NULL != ptrViEBase);
webrtc::ViENetwork* ptrVieNetwork = webrtc::ViENetwork::GetInterface(ptrViE);
EXPECT_TRUE(ptrVieNetwork != NULL);
// ***************************************************************
// Engine ready. Begin testing class
// ***************************************************************
@ -148,16 +151,35 @@ void ViEAutoTest::ViEBaseAPITest() {
EXPECT_EQ(0, ptrViEBase->CreateChannel(videoChannel));
int videoChannel2 = -1;
int videoChannel3 = -1;
EXPECT_EQ(0, ptrViEBase->CreateChannel(videoChannel2));
EXPECT_NE(videoChannel, videoChannel2) <<
"Should allocate new number for independent channel";
EXPECT_EQ(0, ptrViEBase->DeleteChannel(videoChannel2));
EXPECT_EQ(-1, ptrViEBase->CreateChannel(videoChannel2, videoChannel + 1)) <<
"Should fail since neither channel exists (the second must)";
EXPECT_EQ(-1, ptrViEBase->CreateChannel(videoChannel2, videoChannel + 1))
<< "Should fail since neither channel exists (the second must)";
EXPECT_EQ(0, ptrViEBase->CreateChannel(videoChannel2, videoChannel));
// Create a receive only channel and a send channel. Verify we can't send on
// the receive only channel.
EXPECT_EQ(0, ptrViEBase->CreateReceiveChannel(videoChannel2, videoChannel));
EXPECT_EQ(0, ptrViEBase->CreateChannel(videoChannel3, videoChannel));
const char* ipAddress = "127.0.0.1\0";
const int sendPort = 1234;
EXPECT_EQ(0, ptrVieNetwork->SetSendDestination(videoChannel, ipAddress,
sendPort));
EXPECT_EQ(0, ptrVieNetwork->SetSendDestination(videoChannel2,ipAddress,
sendPort + 2));
EXPECT_EQ(0, ptrVieNetwork->SetSendDestination(videoChannel3,ipAddress,
sendPort + 4));
EXPECT_EQ(0, ptrViEBase->StartSend(videoChannel));
EXPECT_EQ(-1, ptrViEBase->StartSend(videoChannel2));
EXPECT_EQ(0, ptrViEBase->StartSend(videoChannel3));
EXPECT_EQ(0, ptrViEBase->StopSend(videoChannel));
EXPECT_EQ(0, ptrViEBase->StopSend(videoChannel3));
// Test Voice Engine integration with Video Engine.
webrtc::VoiceEngine* ptrVoE = NULL;
@ -191,6 +213,7 @@ void ViEAutoTest::ViEBaseAPITest() {
EXPECT_EQ(0, ptrViEBase->DisconnectAudioChannel(videoChannel));
// Clean up voice engine
EXPECT_EQ(0, ptrVieNetwork->Release());
EXPECT_EQ(0, ptrViEBase->SetVoiceEngine(NULL));
EXPECT_EQ(0, ptrVoEBase->Release());
EXPECT_TRUE(webrtc::VoiceEngine::Delete(ptrVoE));

View File

@ -139,99 +139,116 @@ void ViEAutoTest::ViECodecExtendedTest()
}
//
// Default channel
// Multiple send channels.
//
{
// Create VIE
// Create two channels, where the second channel is created from the
// first channel. Send different resolutions on the channels and verify
// the received streams.
TbInterfaces ViE("ViECodecExtendedTest2");
// Create a capture device
TbCaptureDevice tbCapture(ViE);
// Create channel 1
// Create channel 1.
int videoChannel1 = -1;
EXPECT_EQ(0, ViE.base->CreateChannel(videoChannel1));
// Create channel 2 based on the first channel.
int videoChannel2 = -1;
EXPECT_EQ(0, ViE.base->CreateChannel(videoChannel2, videoChannel1));
EXPECT_NE(videoChannel1, videoChannel2) <<
"Channel 2 should be unique.";
unsigned short rtpPort1 = 12000;
unsigned short rtpPort2 = 13000;
EXPECT_EQ(0, ViE.network->SetLocalReceiver(
videoChannel1, rtpPort1));
EXPECT_EQ(0, ViE.network->SetSendDestination(
videoChannel1, "127.0.0.1", rtpPort1));
EXPECT_EQ(0, ViE.network->SetLocalReceiver(
videoChannel2, rtpPort2));
EXPECT_EQ(0, ViE.network->SetSendDestination(
videoChannel2, "127.0.0.1", rtpPort2));
tbCapture.ConnectTo(videoChannel1);
tbCapture.ConnectTo(videoChannel2);
EXPECT_EQ(0, ViE.rtp_rtcp->SetKeyFrameRequestMethod(
videoChannel1, webrtc::kViEKeyFrameRequestPliRtcp));
EXPECT_EQ(0, ViE.rtp_rtcp->SetKeyFrameRequestMethod(
videoChannel2, webrtc::kViEKeyFrameRequestPliRtcp));
EXPECT_EQ(0, ViE.render->AddRenderer(
videoChannel1, _window1, 0, 0.0, 0.0, 1.0, 1.0));
EXPECT_EQ(0, ViE.render->StartRender(videoChannel1));
ViEAutotestCodecObserver codecObserver1;
EXPECT_EQ(0, ViE.codec->RegisterEncoderObserver(
videoChannel1, codecObserver1));
EXPECT_EQ(0, ViE.codec->RegisterDecoderObserver(
videoChannel1, codecObserver1));
EXPECT_EQ(0, ViE.render->AddRenderer(
videoChannel2, _window2, 0, 0.0, 0.0, 1.0, 1.0));
EXPECT_EQ(0, ViE.render->StartRender(videoChannel2));
// Set Send codec
unsigned short codecWidth = 176;
unsigned short codecHeight = 144;
unsigned short codecWidth = 320;
unsigned short codecHeight = 240;
bool codecSet = false;
webrtc::VideoCodec videoCodec;
webrtc::VideoCodec sendCodec1;
webrtc::VideoCodec sendCodec2;
for (int idx = 0; idx < ViE.codec->NumberOfCodecs(); idx++)
{
EXPECT_EQ(0, ViE.codec->GetCodec(idx, videoCodec));
EXPECT_EQ(0, ViE.codec->SetReceiveCodec(videoChannel1, videoCodec));
if (videoCodec.codecType == webrtc::kVideoCodecVP8)
{
videoCodec.width = codecWidth;
videoCodec.height = codecHeight;
videoCodec.startBitrate = 200;
videoCodec.maxBitrate = 300;
EXPECT_EQ(0, ViE.codec->SetSendCodec(
videoChannel1, videoCodec));
memcpy(&sendCodec1, &videoCodec, sizeof(videoCodec));
sendCodec1.width = codecWidth;
sendCodec1.height = codecHeight;
EXPECT_EQ(0, ViE.codec->SetSendCodec(videoChannel1,
sendCodec1));
memcpy(&sendCodec2, &videoCodec, sizeof(videoCodec));
sendCodec2.width = 2 * codecWidth;
sendCodec2.height = 2 * codecHeight;
EXPECT_EQ(0, ViE.codec->SetSendCodec(videoChannel2,
sendCodec2));
codecSet = true;
break;
}
}
EXPECT_TRUE(codecSet);
webrtc::VideoCodec send_codec;
memcpy(&send_codec, &videoCodec, sizeof(videoCodec));
EXPECT_EQ(0, ViE.base->StartSend(videoChannel1));
// We need to verify using render effect filter since we won't trigger
// a decode reset in loopback (due to using the same SSRC).
RenderFilter filter1;
RenderFilter filter2;
EXPECT_EQ(0,
ViE.image_process->RegisterRenderEffectFilter(videoChannel1,
filter1));
EXPECT_EQ(0,
ViE.image_process->RegisterRenderEffectFilter(videoChannel2,
filter2));
EXPECT_EQ(0, ViE.base->StartReceive(videoChannel1));
// Create channel 2, based on channel 1
int videoChannel2 = -1;
EXPECT_EQ(0, ViE.base->CreateChannel(videoChannel2, videoChannel1));
EXPECT_NE(videoChannel1, videoChannel2) <<
"Channel 2 should be seop";
EXPECT_EQ(0, ViE.rtp_rtcp->SetKeyFrameRequestMethod(
videoChannel2, webrtc::kViEKeyFrameRequestPliRtcp));
// Prepare receive codecs
for (int idx = 0; idx < ViE.codec->NumberOfCodecs(); idx++)
{
EXPECT_EQ(0, ViE.codec->GetCodec(idx, videoCodec));
EXPECT_EQ(0, ViE.codec->SetReceiveCodec(videoChannel2, videoCodec));
}
ViEAutotestCodecObserver codecObserver2;
EXPECT_EQ(0, ViE.codec->RegisterDecoderObserver(
videoChannel2, codecObserver2));
EXPECT_EQ(0, ViE.render->AddRenderer(
videoChannel2, _window2, 0, 0.0, 0.0, 1.0, 1.0));
EXPECT_EQ(0, ViE.render->StartRender(videoChannel2));
unsigned short rtpPort2 = 13000;
EXPECT_EQ(0, ViE.network->SetLocalReceiver(videoChannel2, rtpPort2));
EXPECT_EQ(0, ViE.network->SetSendDestination(
videoChannel2, "127.0.0.1", rtpPort2));
EXPECT_EQ(0, ViE.base->StartSend(videoChannel1));
EXPECT_EQ(0, ViE.base->StartReceive(videoChannel2));
EXPECT_EQ(-1, ViE.base->StartSend(videoChannel2));
EXPECT_EQ(0, ViE.base->StartSend(videoChannel2));
AutoTestSleep(KAutoTestSleepTimeMs);
EXPECT_EQ(0, ViE.base->StopReceive(videoChannel1));
EXPECT_EQ(0, ViE.base->StopSend(videoChannel1));
EXPECT_EQ(0, ViE.base->StopReceive(videoChannel2));
EXPECT_EQ(0, ViE.base->StopSend(videoChannel2));
EXPECT_EQ(0, ViE.image_process->DeregisterRenderEffectFilter(
videoChannel1));
EXPECT_EQ(0, ViE.image_process->DeregisterRenderEffectFilter(
videoChannel2));
EXPECT_EQ(sendCodec1.width, filter1.last_render_width_);
EXPECT_EQ(sendCodec1.height, filter1.last_render_height_);
EXPECT_EQ(sendCodec2.width, filter2.last_render_width_);
EXPECT_EQ(sendCodec2.height, filter2.last_render_height_);
EXPECT_EQ(0, ViE.base->DeleteChannel(videoChannel1));
EXPECT_EQ(0, ViE.base->DeleteChannel(videoChannel2));
}
}

View File

@ -112,7 +112,6 @@ void ViEAutoTest::ViERtpRtcpStandardTest()
// ***************************************************************
// Engine ready. Begin testing class
// ***************************************************************
unsigned short startSequenceNumber = 12345;
ViETest::Log("Set start sequence number: %u", startSequenceNumber);
EXPECT_EQ(0, ViE.rtp_rtcp->SetStartSequenceNumber(
@ -279,13 +278,14 @@ void ViEAutoTest::ViERtpRtcpStandardTest()
// __FUNCTION__, __LINE__);
EXPECT_EQ(0, ViE.base->StopReceive(tbChannel.videoChannel));
EXPECT_EQ(0, ViE.base->StopSend(tbChannel.videoChannel));
EXPECT_EQ(0, ViE.rtp_rtcp->SetNACKStatus(tbChannel.videoChannel, false));
//
// Keepalive
//
ViETest::Log("Testing RTP keep alive...\n");
EXPECT_EQ(0, ViE.base->StopSend(tbChannel.videoChannel));
EXPECT_EQ(0, ViE.base->StartReceive(tbChannel.videoChannel));
myTransport.SetPacketLoss(0);
@ -375,6 +375,94 @@ void ViEAutoTest::ViERtpRtcpStandardTest()
// Deregister external transport
EXPECT_EQ(0, ViE.network->DeregisterSendTransport(tbChannel.videoChannel));
{
// Create three channels. 1 and 2 are grouped together and will get a
// common REMB packet. 3 is in its own group and will get a separate REMB
// packet. To verify we receive a REMB, set a higher start bitrate for 2
// than 1 and verify the estimated send bitrate for 2 is lowered. Also,
// verify that the bitrate estimate for 3 is kept high and not lowered
// due to 1 and 2.
const unsigned int start_rate_1_bps = 100000;
const unsigned int start_rate_2_bps = 300000;
const unsigned int start_rate_3_bps = 1000000;
int channel_1 = -1;
int channel_2 = -1;
int channel_3 = -1;
EXPECT_EQ(0, ViE.base->CreateChannel(channel_1));
EXPECT_EQ(0, ViE.base->CreateChannel(channel_2, channel_1));
EXPECT_EQ(0, ViE.base->CreateChannel(channel_3));
//TbCaptureDevice tbCapture(ViE);
tbCapture.ConnectTo(channel_1);
tbCapture.ConnectTo(channel_2);
tbCapture.ConnectTo(channel_3);
TbExternalTransport transport_1(*(ViE.network));
TbExternalTransport transport_2(*(ViE.network));
TbExternalTransport transport_3(*(ViE.network));
EXPECT_EQ(0, ViE.network->RegisterSendTransport(channel_1, transport_1));
EXPECT_EQ(0, ViE.network->RegisterSendTransport(channel_2, transport_2));
EXPECT_EQ(0, ViE.network->RegisterSendTransport(channel_3, transport_3));
webrtc::VideoCodec video_codec;
for (int idx = 0; idx < ViE.codec->NumberOfCodecs(); ++idx) {
ViE.codec->GetCodec(idx, video_codec);
if (video_codec.codecType == webrtc::kVideoCodecVP8) {
break;
}
}
EXPECT_EQ(0, ViE.codec->SetReceiveCodec(channel_1, video_codec));
EXPECT_EQ(0, ViE.codec->SetReceiveCodec(channel_2, video_codec));
EXPECT_EQ(0, ViE.codec->SetReceiveCodec(channel_3, video_codec));
video_codec.startBitrate = start_rate_1_bps / 1000;
EXPECT_EQ(0, ViE.codec->SetSendCodec(channel_1, video_codec));
video_codec.startBitrate = start_rate_2_bps / 1000;
EXPECT_EQ(0, ViE.codec->SetSendCodec(channel_2, video_codec));
video_codec.startBitrate = start_rate_3_bps / 1000;
EXPECT_EQ(0, ViE.codec->SetSendCodec(channel_3, video_codec));
EXPECT_EQ(0, ViE.rtp_rtcp->SetRembStatus(channel_1, true, true));
EXPECT_EQ(0, ViE.rtp_rtcp->SetRembStatus(channel_2, true, true));
EXPECT_EQ(0, ViE.rtp_rtcp->SetRembStatus(channel_3, true, true));
EXPECT_EQ(0, ViE.base->StartReceive(channel_1));
EXPECT_EQ(0, ViE.base->StartReceive(channel_2));
EXPECT_EQ(0, ViE.base->StartReceive(channel_3));
EXPECT_EQ(0, ViE.base->StartSend(channel_1));
EXPECT_EQ(0, ViE.base->StartSend(channel_2));
EXPECT_EQ(0, ViE.base->StartSend(channel_3));
AutoTestSleep(KAutoTestSleepTimeMs);
EXPECT_EQ(0, ViE.base->StopReceive(channel_1));
EXPECT_EQ(0, ViE.base->StopReceive(channel_2));
EXPECT_EQ(0, ViE.base->StopReceive(channel_3));
EXPECT_EQ(0, ViE.base->StopSend(channel_1));
EXPECT_EQ(0, ViE.base->StopSend(channel_2));
EXPECT_EQ(0, ViE.base->StopSend(channel_3));
unsigned int bw_estimate_1 = 0;
unsigned int bw_estimate_2 = 0;
unsigned int bw_estimate_3 = 0;
ViE.rtp_rtcp->GetEstimatedSendBandwidth(channel_1, &bw_estimate_1);
ViE.rtp_rtcp->GetEstimatedSendBandwidth(channel_2, &bw_estimate_2);
ViE.rtp_rtcp->GetEstimatedSendBandwidth(channel_3, &bw_estimate_3);
EXPECT_LT(bw_estimate_1, start_rate_2_bps);
EXPECT_LT(bw_estimate_2, start_rate_2_bps);
EXPECT_NE(bw_estimate_1, start_rate_1_bps);
// Add some margin to avoid flaky test runs.
EXPECT_GT(bw_estimate_3, 0.75 * start_rate_3_bps);
EXPECT_EQ(0, ViE.base->DeleteChannel(channel_1));
EXPECT_EQ(0, ViE.base->DeleteChannel(channel_2));
EXPECT_EQ(0, ViE.base->DeleteChannel(channel_3));
}
//***************************************************************
// Testing finished. Tear down Video Engine
//***************************************************************

View File

@ -78,6 +78,7 @@
'vie_shared_data.h',
'vie_capturer.h',
'vie_channel.h',
'vie_channel_group.h',
'vie_channel_manager.h',
'vie_encoder.h',
'vie_file_image.h',
@ -109,6 +110,7 @@
'vie_shared_data.cc',
'vie_capturer.cc',
'vie_channel.cc',
'vie_channel_group.cc',
'vie_channel_manager.cc',
'vie_encoder.cc',
'vie_file_image.cc',

View File

@ -124,34 +124,12 @@ int ViEBaseImpl::CreateChannel(int& video_channel) {
}
int ViEBaseImpl::CreateChannel(int& video_channel, int original_channel) {
if (!(shared_data_.Initialized())) {
shared_data_.SetLastError(kViENotInitialized);
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s - ViE instance %d not initialized", __FUNCTION__,
shared_data_.instance_id());
return -1;
}
return CreateChannel(video_channel, original_channel, true);
}
ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
if (!cs.Channel(original_channel)) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s - original_channel does not exist.", __FUNCTION__,
shared_data_.instance_id());
shared_data_.SetLastError(kViEBaseInvalidChannelId);
return -1;
}
if (shared_data_.channel_manager()->CreateChannel(video_channel,
original_channel) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s: Could not create channel", __FUNCTION__);
video_channel = -1;
shared_data_.SetLastError(kViEBaseChannelCreationFailed);
return -1;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s: channel created: %d", __FUNCTION__, video_channel);
return 0;
int ViEBaseImpl::CreateReceiveChannel(int& video_channel,
int original_channel) {
return CreateChannel(video_channel, original_channel, false);
}
int ViEBaseImpl::DeleteChannel(const int video_channel) {
@ -270,27 +248,13 @@ int ViEBaseImpl::StartSend(const int video_channel) {
return -1;
}
// Verify no other channel using the same encoder is sending.
ChannelList channels;
cs.ChannelsUsingViEEncoder(video_channel, &channels);
for (ChannelList::iterator it = channels.begin(); it != channels.end();
++it) {
if ((*it)->Sending()) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_.instance_id(), video_channel),
"A channel using this encoder is already synding");
shared_data_.SetLastError(kViEBaseAlreadySending);
return -1;
}
}
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
assert(false);
assert(vie_encoder != NULL);
if (vie_encoder->Owner() != video_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_.instance_id(), video_channel),
"%s: Could not find encoder for channel %d", __FUNCTION__,
video_channel);
"Can't start ssend on a receive only channel.");
shared_data_.SetLastError(kViEBaseReceiveOnlyChannel);
return -1;
}
@ -491,4 +455,37 @@ WebRtc_Word32 ViEBaseImpl::AddExternalTransportBuild(char* str) const {
#endif
}
int ViEBaseImpl::CreateChannel(int& video_channel, int original_channel,
bool sender) {
if (!(shared_data_.Initialized())) {
shared_data_.SetLastError(kViENotInitialized);
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s - ViE instance %d not initialized", __FUNCTION__,
shared_data_.instance_id());
return -1;
}
ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
if (!cs.Channel(original_channel)) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s - original_channel does not exist.", __FUNCTION__,
shared_data_.instance_id());
shared_data_.SetLastError(kViEBaseInvalidChannelId);
return -1;
}
if (shared_data_.channel_manager()->CreateChannel(video_channel,
original_channel,
sender) == -1) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s: Could not create channel", __FUNCTION__);
video_channel = -1;
shared_data_.SetLastError(kViEBaseChannelCreationFailed);
return -1;
}
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(shared_data_.instance_id()),
"%s: channel created: %d", __FUNCTION__, video_channel);
return 0;
}
} // namespace webrtc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2012 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
@ -27,52 +27,23 @@ class ViEBaseImpl
public:
virtual int Release();
// Initializes VideoEngine and must be called before any other API is called.
// Implements ViEBase.
virtual int Init();
// Connects ViE to a VoE instance. Pass in NULL to forget about a previously
// set voice engine and release all resources we allocated from it.
virtual int SetVoiceEngine(VoiceEngine* voice_engine);
// Creates a new ViE channel.
virtual int CreateChannel(int& video_channel);
// Creates a new ViE channel that will use the same capture device and encoder
// as |original_channel|.
virtual int CreateChannel(int& video_channel, int original_channel);
// Deletes a ViE channel.
virtual int CreateReceiveChannel(int& video_channel, int original_channel);
virtual int DeleteChannel(const int video_channel);
// Connects a ViE channel with a VoE channel.
virtual int ConnectAudioChannel(const int video_channel,
const int audio_channel);
// Disconnects a video/voice channel pair.
virtual int DisconnectAudioChannel(const int video_channel);
// Starts sending on video_channel and also starts the encoder.
virtual int StartSend(const int video_channel);
// Stops sending on the specified channel.
virtual int StopSend(const int video_channel);
// Starts receiving on the channel and also start decoding.
virtual int StartReceive(const int video_channel);
// Stops receiving on the specified channel.
virtual int StopReceive(const int video_channel);
// Registers a customer implemented observer.
virtual int RegisterObserver(ViEBaseObserver& observer);
// Deregisters the observer.
virtual int DeregisterObserver();
// Prints version information into |version|.
virtual int GetVersion(char version[1024]);
// Returns the error code for the last registered error.
virtual int LastError();
protected:
@ -87,6 +58,8 @@ class ViEBaseImpl
WebRtc_Word32 AddBuildInfo(char* str) const;
WebRtc_Word32 AddExternalTransportBuild(char* str) const;
int CreateChannel(int& video_channel, int original_channel, bool sender);
// ViEBaseImpl owns ViESharedData used by all interface implementations.
ViESharedData shared_data_;
};

View File

@ -219,6 +219,13 @@ int ViECaptureImpl::ConnectCaptureDevice(const int capture_id,
shared_data_->SetLastError(kViECaptureDeviceInvalidChannelId);
return -1;
}
if (vie_encoder->Owner() != video_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"Can't connect capture device to a receive only channel.");
shared_data_->SetLastError(kViECaptureDeviceInvalidChannelId);
return -1;
}
// Check if the encoder already has a connected frame provider
if (is.FrameProvider(vie_encoder) != NULL) {
WEBRTC_TRACE(kTraceError, kTraceVideo,

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2012 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.
*/
#include "video_engine/vie_channel_group.h"
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "video_engine/vie_channel.h"
#include "video_engine/vie_encoder.h"
#include "video_engine/vie_remb.h"
namespace webrtc {
ChannelGroup::ChannelGroup(ProcessThread* process_thread)
: remb_(new VieRemb(process_thread)) {}
ChannelGroup::~ChannelGroup() {
assert(channels_.empty());
assert(!remb_->InUse());
}
void ChannelGroup::AddChannel(int channel_id) {
channels_.insert(channel_id);
}
void ChannelGroup::RemoveChannel(int channel_id) {
channels_.erase(channel_id);
}
bool ChannelGroup::HasChannel(int channel_id) {
return channels_.find(channel_id) != channels_.end();
}
bool ChannelGroup::Empty() {
return channels_.empty();
}
bool ChannelGroup::SetChannelRembStatus(int channel_id,
bool sender,
bool receiver,
ViEChannel* channel,
ViEEncoder* encoder) {
// Update the channel state.
if (sender || receiver) {
if (!channel->EnableRemb(true)) {
return false;
}
} else if (channel) {
channel->EnableRemb(false);
}
// Update the remb instance with necesary RTp modules.
RtpRtcp* rtp_module = channel->rtp_rtcp();
if (sender) {
remb_->AddRembSender(rtp_module);
remb_->AddSendChannel(encoder->SendRtpRtcpModule());
} else {
remb_->RemoveRembSender(rtp_module);
remb_->RemoveSendChannel(encoder->SendRtpRtcpModule());
}
if (receiver) {
remb_->AddReceiveChannel(rtp_module);
} else {
remb_->RemoveReceiveChannel(rtp_module);
}
if (sender || receiver) {
rtp_module->SetRemoteBitrateObserver(remb_.get());
} else {
rtp_module->SetRemoteBitrateObserver(NULL);
}
return true;
}
} // namespace webrtc

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2012 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_VIE_CHANNEL_GROUP_H_
#define WEBRTC_VIDEO_ENGINE_VIE_CHANNEL_GROUP_H_
#include <set>
#include "system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
class ProcessThread;
class ViEChannel;
class ViEEncoder;
class VieRemb;
// Channel group contains data common for several channels. All channels in the
// group are assumed to send/receive data to the same end-point.
class ChannelGroup {
public:
explicit ChannelGroup(ProcessThread* process_thread);
~ChannelGroup();
void AddChannel(int channel_id);
void RemoveChannel(int channel_id);
bool HasChannel(int channel_id);
bool Empty();
bool SetChannelRembStatus(int channel_id,
bool sender,
bool receiver,
ViEChannel* channel,
ViEEncoder* encoder);
private:
typedef std::set<int> ChannelSet;
scoped_ptr<VieRemb> remb_;
ChannelSet channels_;
};
} // namespace webrtc
#endif // WEBRTC_VIDEO_ENGINE_VIE_CHANNEL_GROUP_H_

View File

@ -35,7 +35,6 @@ ViEChannelManager::ViEChannelManager(
free_channel_ids_(new bool[kViEMaxNumberOfChannels]),
free_channel_ids_size_(kViEMaxNumberOfChannels),
voice_sync_interface_(NULL),
remb_(new VieRemb(engine_id)),
voice_engine_(NULL),
module_process_thread_(NULL) {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id),
@ -50,7 +49,6 @@ ViEChannelManager::~ViEChannelManager() {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id_),
"ViEChannelManager Destructor, engine_id: %d", engine_id_);
module_process_thread_->DeRegisterModule(remb_.get());
while (channel_map_.size() > 0) {
ChannelMap::iterator it = channel_map_.begin();
// DeleteChannel will erase this channel from the map and invalidate |it|.
@ -69,131 +67,83 @@ ViEChannelManager::~ViEChannelManager() {
free_channel_ids_ = NULL;
free_channel_ids_size_ = 0;
}
assert(channel_groups_.empty());
assert(channel_map_.empty());
assert(vie_encoder_map_.empty());
}
void ViEChannelManager::SetModuleProcessThread(
ProcessThread& module_process_thread) {
assert(!module_process_thread_);
module_process_thread_ = &module_process_thread;
module_process_thread_->RegisterModule(remb_.get());
}
int ViEChannelManager::CreateChannel(int& channel_id) {
CriticalSectionScoped cs(*channel_id_critsect_);
// Get a free id for the new channel.
if (!GetFreeChannelId(channel_id)) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"Max number of channels reached: %d", channel_map_.size());
// Get a new channel id.
int new_channel_id = FreeChannelId();
if (new_channel_id == -1) {
return -1;
}
ViEChannel* vie_channel = new ViEChannel(channel_id, engine_id_,
// Create a new channel group and add this channel.
ChannelGroup* group = new ChannelGroup(module_process_thread_);
ViEEncoder* vie_encoder = new ViEEncoder(engine_id_, new_channel_id,
number_of_cores_,
*module_process_thread_);
if (!vie_channel) {
ReturnChannelId(channel_id);
return -1;
}
if (vie_channel->Init() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"%s could not init channel", __FUNCTION__, channel_id);
ReturnChannelId(channel_id);
delete vie_channel;
vie_channel = NULL;
return -1;
if (!CreateChannelObject(new_channel_id, vie_encoder)) {
delete vie_encoder;
vie_encoder = NULL;
ReturnChannelId(new_channel_id);
delete group;
}
// There is no ViEEncoder for this channel, create one with default settings.
ViEEncoder* vie_encoder = new ViEEncoder(engine_id_, channel_id,
number_of_cores_,
*module_process_thread_);
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"%s(video_channel_id: %d) - Could not create a new encoder",
__FUNCTION__, channel_id);
delete vie_channel;
return -1;
}
vie_encoder_map_[channel_id] = vie_encoder;
channel_map_[channel_id] = vie_channel;
// Register the channel at the encoder.
RtpRtcp* send_rtp_rtcp_module = vie_encoder->SendRtpRtcpModule();
if (vie_channel->RegisterSendRtpRtcpModule(*send_rtp_rtcp_module) != 0) {
assert(false);
vie_encoder_map_.erase(channel_id);
channel_map_.erase(channel_id);
ReturnChannelId(channel_id);
delete vie_channel;
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id),
"%s: Could not register rtp module %d", __FUNCTION__,
channel_id);
return -1;
}
channel_id = new_channel_id;
group->AddChannel(channel_id);
channel_groups_.push_back(group);
return 0;
}
int ViEChannelManager::CreateChannel(int& channel_id, int original_channel) {
int ViEChannelManager::CreateChannel(int& channel_id,
int original_channel,
bool sender) {
CriticalSectionScoped cs(*channel_id_critsect_);
// Check that original_channel already exists.
ViEEncoder* vie_encoder = ViEEncoderPtr(original_channel);
ChannelGroup* channel_group = FindGroup(original_channel);
if (!channel_group) {
return -1;
}
int new_channel_id = FreeChannelId();
if (new_channel_id == -1) {
return -1;
}
ViEEncoder* vie_encoder = NULL;
if (sender) {
// We need to create a new ViEEncoder.
vie_encoder = new ViEEncoder(engine_id_, new_channel_id, number_of_cores_,
*module_process_thread_);
if (!CreateChannelObject(new_channel_id, vie_encoder)) {
delete vie_encoder;
vie_encoder = NULL;
}
} else {
vie_encoder = ViEEncoderPtr(original_channel);
assert(vie_encoder);
if (!CreateChannelObject(new_channel_id, vie_encoder)) {
vie_encoder = NULL;
}
}
if (!vie_encoder) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"%s: Original channel doesn't exist", __FUNCTION__,
original_channel);
ReturnChannelId(new_channel_id);
return -1;
}
VideoCodec video_codec;
vie_encoder->GetEncoder(video_codec);
// Get a free id for the new channel.
if (GetFreeChannelId(channel_id) == false) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"Max number of channels reached: %d", channel_map_.size());
return -1;
}
ViEChannel* vie_channel = new ViEChannel(channel_id, engine_id_,
number_of_cores_,
*module_process_thread_);
if (!vie_channel) {
ReturnChannelId(channel_id);
return -1;
}
if (vie_channel->Init() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"%s could not init channel", __FUNCTION__, channel_id);
ReturnChannelId(channel_id);
delete vie_channel;
vie_channel = NULL;
return -1;
}
vie_encoder_map_[channel_id] = vie_encoder;
// Set the same encoder settings for the channel as used by the master
// channel. Do this before attaching rtp module to ensure all rtp children has
// the same codec type.
VideoCodec encoder;
if (vie_encoder->GetEncoder(encoder) == 0) {
vie_channel->SetSendCodec(encoder);
}
channel_map_[channel_id] = vie_channel;
// Register the channel at the encoder.
RtpRtcp* send_rtp_rtcp_module = vie_encoder->SendRtpRtcpModule();
if (vie_channel->RegisterSendRtpRtcpModule(*send_rtp_rtcp_module) != 0) {
assert(false);
vie_encoder_map_.erase(channel_id);
channel_map_.erase(channel_id);
ReturnChannelId(channel_id);
delete vie_channel;
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id),
"%s: Could not register rtp module %d", __FUNCTION__,
channel_id);
return -1;
}
channel_id = new_channel_id;
channel_group->AddChannel(channel_id);
return 0;
}
@ -204,8 +154,9 @@ int ViEChannelManager::DeleteChannel(int channel_id) {
// Write lock to make sure no one is using the channel.
ViEManagerWriteScoped wl(*this);
// Protect the map.
// Protect the maps.
CriticalSectionScoped cs(*channel_id_critsect_);
ChannelMap::iterator c_it = channel_map_.find(channel_id);
if (c_it == channel_map_.end()) {
// No such channel.
@ -216,11 +167,6 @@ int ViEChannelManager::DeleteChannel(int channel_id) {
vie_channel = c_it->second;
channel_map_.erase(c_it);
// Deregister possible remb modules.
RtpRtcp* rtp_module = vie_channel->rtp_rtcp();
remb_->RemoveRembSender(rtp_module);
remb_->RemoveReceiveChannel(rtp_module);
// Deregister the channel from the ViEEncoder to stop the media flow.
vie_channel->DeregisterSendRtpRtcpModule();
ReturnChannelId(channel_id);
@ -230,7 +176,14 @@ int ViEChannelManager::DeleteChannel(int channel_id) {
assert(e_it != vie_encoder_map_.end());
vie_encoder = e_it->second;
remb_->RemoveSendChannel(vie_encoder->SendRtpRtcpModule());
ChannelGroup* group = FindGroup(channel_id);
group->SetChannelRembStatus(channel_id, false, false, vie_channel,
vie_encoder);
group->RemoveChannel(channel_id);
if (group->Empty()) {
channel_groups_.remove(group);
delete group;
}
// Check if other channels are using the same encoder.
if (ChannelUsingViEEncoder(channel_id)) {
@ -327,38 +280,49 @@ VoiceEngine* ViEChannelManager::GetVoiceEngine() {
bool ViEChannelManager::SetRembStatus(int channel_id, bool sender,
bool receiver) {
CriticalSectionScoped cs(*channel_id_critsect_);
ChannelGroup* group = FindGroup(channel_id);
if (!group) {
return -1;
}
ViEChannel* channel = ViEChannelPtr(channel_id);
if (!channel) {
assert(channel);
ViEEncoder* encoder = ViEEncoderPtr(channel_id);
assert(encoder);
return group->SetChannelRembStatus(channel_id, sender, receiver, channel,
encoder);
}
bool ViEChannelManager::CreateChannelObject(int channel_id,
ViEEncoder* vie_encoder) {
ViEChannel* vie_channel = new ViEChannel(channel_id, engine_id_,
number_of_cores_,
*module_process_thread_);
if (vie_channel->Init() != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"%s could not init channel", __FUNCTION__, channel_id);
delete vie_channel;
return false;
}
ViEEncoder* encoder = ViEEncoderPtr(channel_id);
VideoCodec encoder;
vie_encoder->GetEncoder(encoder);
if (vie_channel->SetSendCodec(encoder) != 0) {
vie_encoder = NULL;
}
if (sender || receiver) {
if (!channel->EnableRemb(true)) {
return false;
}
} else {
channel->EnableRemb(false);
}
RtpRtcp* rtp_module = channel->rtp_rtcp();
if (sender) {
remb_->AddRembSender(rtp_module);
remb_->AddSendChannel(encoder->SendRtpRtcpModule());
} else {
remb_->RemoveRembSender(rtp_module);
remb_->RemoveSendChannel(encoder->SendRtpRtcpModule());
}
if (receiver) {
remb_->AddReceiveChannel(rtp_module);
} else {
remb_->RemoveReceiveChannel(rtp_module);
}
if (sender || receiver) {
rtp_module->SetRemoteBitrateObserver(remb_.get());
} else {
rtp_module->SetRemoteBitrateObserver(NULL);
// Register the channel at the encoder.
RtpRtcp* send_rtp_rtcp_module = vie_encoder->SendRtpRtcpModule();
if (vie_channel->RegisterSendRtpRtcpModule(*send_rtp_rtcp_module) != 0) {
delete vie_channel;
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id),
"%s: Could not register RTP module", __FUNCTION__);
return false;
}
// Store the channel, add it to the channel group and save the vie_encoder.
channel_map_[channel_id] = vie_channel;
vie_encoder_map_[channel_id] = vie_encoder;
return true;
}
@ -395,21 +359,19 @@ ViEEncoder* ViEChannelManager::ViEEncoderPtr(int video_channel_id) const {
return it->second;
}
bool ViEChannelManager::GetFreeChannelId(int& free_channel_id) {
CriticalSectionScoped cs(*channel_id_critsect_);
int ViEChannelManager::FreeChannelId() {
int idx = 0;
while (idx < free_channel_ids_size_) {
if (free_channel_ids_[idx] == true) {
// We've found a free id, allocate it and return.
free_channel_ids_[idx] = false;
free_channel_id = idx + kViEChannelIdBase;
return true;
return idx + kViEChannelIdBase;
}
idx++;
}
// No free channel id.
free_channel_id = -1;
return false;
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_),
"Max number of channels reached: %d", channel_map_.size());
return -1;
}
void ViEChannelManager::ReturnChannelId(int channel_id) {
@ -419,10 +381,20 @@ void ViEChannelManager::ReturnChannelId(int channel_id) {
free_channel_ids_[channel_id - kViEChannelIdBase] = true;
}
ChannelGroup* ViEChannelManager::FindGroup(int channel_id) {
for (ChannelGroups::iterator it = channel_groups_.begin();
it != channel_groups_.end(); ++it) {
if ((*it)->HasChannel(channel_id)) {
return *it;
}
}
return NULL;
}
bool ViEChannelManager::ChannelUsingViEEncoder(int channel_id) const {
CriticalSectionScoped cs(*channel_id_critsect_);
EncoderMap::const_iterator orig_it = vie_encoder_map_.find(channel_id);
if(orig_it == vie_encoder_map_.end()) {
if (orig_it == vie_encoder_map_.end()) {
// No ViEEncoder for this channel.
return false;
}

View File

@ -17,8 +17,10 @@
#include "engine_configurations.h"
#include "system_wrappers/interface/scoped_ptr.h"
#include "typedefs.h"
#include "video_engine/vie_channel_group.h"
#include "video_engine/vie_defines.h"
#include "video_engine/vie_manager_base.h"
#include "video_engine/vie_remb.h"
namespace webrtc {
@ -28,10 +30,10 @@ class ProcessThread;
class ViEChannel;
class ViEEncoder;
class ViEPerformanceMonitor;
class VieRemb;
class VoEVideoSync;
class VoiceEngine;
typedef std::list<ChannelGroup*> ChannelGroups;
typedef std::list<ViEChannel*> ChannelList;
typedef std::map<int, ViEChannel*> ChannelMap;
typedef std::map<int, ViEEncoder*> EncoderMap;
@ -49,8 +51,10 @@ class ViEChannelManager: private ViEManagerBase {
// Creates a new channel. 'channelId' will be the id of the created channel.
int CreateChannel(int& channel_id);
// Creates a channel and attaches to an already existing ViEEncoder.
int CreateChannel(int& channel_id, int original_channel);
// Creates a new channel grouped with |original_channel|. The new channel
// will get its own |ViEEncoder| if |sender| is set to true. It will be a
// receive only channel, without an own |ViEEncoder| if |sender| is false.
int CreateChannel(int& channel_id, int original_channel, bool sender);
// Deletes a channel.
int DeleteChannel(int channel_id);
@ -70,6 +74,10 @@ class ViEChannelManager: private ViEManagerBase {
bool SetRembStatus(int channel_id, bool sender, bool receiver);
private:
// Creates a channel object connected to |vie_encoder|. Assumed to be called
// protected.
bool CreateChannelObject(int channel_id, ViEEncoder* vie_encoder);
// Used by ViEChannelScoped, forcing a manager user to use scoped.
// Returns a pointer to the channel with id 'channelId'.
ViEChannel* ViEChannelPtr(int channel_id) const;
@ -81,13 +89,15 @@ class ViEChannelManager: private ViEManagerBase {
// Gets the ViEEncoder used as input for video_channel_id
ViEEncoder* ViEEncoderPtr(int video_channel_id) const;
// Returns true if we found a new channel id, free_channel_id, false
// otherwise.
bool GetFreeChannelId(int& free_channel_id);
// Returns a free channel id, -1 if failing.
int FreeChannelId();
// Returns a previously allocated channel id.
void ReturnChannelId(int channel_id);
// Returns the iterator to the ChannelGroup containing |channel_id|.
ChannelGroup* FindGroup(int channel_id);
// Returns true if at least one other channels uses the same ViEEncoder as
// channel_id.
bool ChannelUsingViEEncoder(int channel_id) const;
@ -98,14 +108,20 @@ class ViEChannelManager: private ViEManagerBase {
int engine_id_;
int number_of_cores_;
ViEPerformanceMonitor& vie_performance_monitor_;
// TODO(mflodman) Make part of channel group.
ChannelMap channel_map_;
bool* free_channel_ids_;
int free_channel_ids_size_;
// List with all channel groups.
std::list<ChannelGroup*> channel_groups_;
// TODO(mflodman) Make part of channel group.
// Maps Channel id -> ViEEncoder.
EncoderMap vie_encoder_map_;
VoEVideoSync* voice_sync_interface_;
scoped_ptr<VieRemb> remb_;
VoiceEngine* voice_engine_;
ProcessThread* module_process_thread_;
};

View File

@ -144,6 +144,16 @@ int ViECodecImpl::SetSendCodec(const int video_channel,
return -1;
}
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
assert(vie_encoder);
if (vie_encoder->Owner() != video_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Receive only channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecReceiveOnlyChannel);
return -1;
}
// Set a max_bitrate if the user hasn't set one.
VideoCodec video_codec_internal;
memcpy(&video_codec_internal, &video_codec, sizeof(VideoCodec));
@ -163,28 +173,9 @@ int ViECodecImpl::SetSendCodec(const int video_channel,
video_codec_internal.maxBitrate);
}
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
if (!vie_encoder) {
assert(false);
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No encoder found for channel %d", __FUNCTION__);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return -1;
}
VideoCodec encoder;
vie_encoder->GetEncoder(encoder);
if (encoder.codecType != video_codec_internal.codecType &&
cs.ChannelUsingViEEncoder(video_channel)) {
// We don't allow changing codec type when several channels share encoder.
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Settings differs from other channels using encoder",
__FUNCTION__);
shared_data_->SetLastError(kViECodecInUse);
return -1;
}
// Make sure to generate a new SSRC if the codec type and/or resolution has
// changed. This won't have any effect if the user has set an SSRC.
bool new_rtp_stream = false;
@ -193,17 +184,6 @@ int ViECodecImpl::SetSendCodec(const int video_channel,
encoder.height != video_codec_internal.height) {
new_rtp_stream = true;
}
if (video_codec_internal.numberOfSimulcastStreams > 1) {
if (cs.ChannelUsingViEEncoder(video_channel)) {
// We don't allow simulcast channels to share encoder.
WEBRTC_TRACE(kTraceInfo, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Can't share simulcast encoder",
__FUNCTION__);
shared_data_->SetLastError(kViECodecInUse);
return -1;
}
}
ViEInputManagerScoped is(*(shared_data_->input_manager()));
ViEFrameProviderBase* frame_provider = NULL;

View File

@ -172,6 +172,10 @@ ViEEncoder::~ViEEncoder() {
delete qm_callback_;
}
int ViEEncoder::Owner() const {
return channel_id_;
}
void ViEEncoder::Pause() {
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
ViEId(engine_id_, channel_id_),

View File

@ -45,6 +45,9 @@ class ViEEncoder
ProcessThread& module_process_thread);
~ViEEncoder();
// Returns the id of the owning channel.
int Owner() const;
// Drops incoming packets before they get to the encoder.
void Pause();
void Restart();
@ -144,7 +147,7 @@ class ViEEncoder
private:
WebRtc_Word32 engine_id_;
WebRtc_Word32 channel_id_;
const int channel_id_;
const WebRtc_UWord32 number_of_cores_;
VideoCodingModule& vcm_;

View File

@ -14,6 +14,7 @@
#include <cassert>
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "modules/utility/interface/process_thread.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/tick_util.h"
#include "system_wrappers/interface/trace.h"
@ -25,19 +26,21 @@ const int kRembSendIntervallMs = 1000;
// % threshold for if we should send a new REMB asap.
const int kSendThresholdPercent = 97;
VieRemb::VieRemb(int engine_id)
: engine_id_(engine_id),
VieRemb::VieRemb(ProcessThread* process_thread)
: process_thread_(process_thread),
list_crit_(CriticalSectionWrapper::CreateCriticalSection()),
last_remb_time_(TickTime::MillisecondTimestamp()),
last_send_bitrate_(0) {
process_thread->RegisterModule(this);
}
VieRemb::~VieRemb() {
process_thread_->DeRegisterModule(this);
}
void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, -1,
"VieRemb::AddReceiveChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
@ -45,7 +48,7 @@ void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
receive_modules_.end())
return;
WEBRTC_TRACE(kTraceInfo, kTraceVideo, engine_id_, "AddRembChannel");
WEBRTC_TRACE(kTraceInfo, kTraceVideo, -1, "AddRembChannel");
// The module probably doesn't have a remote SSRC yet, so don't add it to the
// map.
receive_modules_.push_back(rtp_rtcp);
@ -53,7 +56,7 @@ void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
void VieRemb::RemoveReceiveChannel(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, -1,
"VieRemb::RemoveReceiveChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
@ -70,7 +73,7 @@ void VieRemb::RemoveReceiveChannel(RtpRtcp* rtp_rtcp) {
void VieRemb::AddRembSender(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, -1,
"VieRemb::AddRembSender(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
@ -84,7 +87,7 @@ void VieRemb::AddRembSender(RtpRtcp* rtp_rtcp) {
void VieRemb::RemoveRembSender(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, -1,
"VieRemb::RemoveRembSender(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
@ -99,7 +102,7 @@ void VieRemb::RemoveRembSender(RtpRtcp* rtp_rtcp) {
void VieRemb::AddSendChannel(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, -1,
"VieRemb::AddSendChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
@ -113,7 +116,7 @@ void VieRemb::AddSendChannel(RtpRtcp* rtp_rtcp) {
void VieRemb::RemoveSendChannel(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, -1,
"VieRemb::RemoveSendChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
@ -126,8 +129,16 @@ void VieRemb::RemoveSendChannel(RtpRtcp* rtp_rtcp) {
}
}
bool VieRemb::InUse() const {
CriticalSectionScoped cs(list_crit_.get());
if(receive_modules_.empty() && send_modules_.empty() && rtcp_sender_.empty())
return false;
else
return true;
}
void VieRemb::OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) {
WEBRTC_TRACE(kTraceStream, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStream, kTraceVideo, -1,
"VieRemb::UpdateBitrateEstimate(ssrc: %u, bitrate: %u)",
ssrc, bitrate);
CriticalSectionScoped cs(list_crit_.get());
@ -147,7 +158,7 @@ void VieRemb::OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) {
}
void VieRemb::OnReceivedRemb(unsigned int bitrate) {
WEBRTC_TRACE(kTraceStream, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStream, kTraceVideo, -1,
"VieRemb::OnReceivedRemb(bitrate: %u)", bitrate);
// TODO(mflodman) Should be extended to allow different split of bitrate.
// TODO(mflodman) Do we want to call |SetMaximumBitrateEstimate| from

View File

@ -28,11 +28,12 @@
namespace webrtc {
class CriticalSectionWrapper;
class ProcessThread;
class RtpRtcp;
class VieRemb : public RtpRemoteBitrateObserver, public Module {
public:
explicit VieRemb(int engine_id);
VieRemb(ProcessThread* process_thread);
~VieRemb();
// Called to add a receive channel to include in the REMB packet.
@ -54,6 +55,9 @@ class VieRemb : public RtpRemoteBitrateObserver, public Module {
// Removes the specified channel from receiving REMB packet estimates.
void RemoveSendChannel(RtpRtcp* rtp_rtcp);
// Returns true if the instance is in use, false otherwise.
bool InUse() const;
// Called every time there is a new bitrate estimate for the received stream
// with given SSRC. This call will trigger a new RTCP REMB packet if the
// bitrate estimate has decreased or if no RTCP REMB packet has been sent for
@ -74,7 +78,7 @@ class VieRemb : public RtpRemoteBitrateObserver, public Module {
typedef std::list<RtpRtcp*> RtpModules;
typedef std::map<unsigned int, unsigned int> SsrcBitrate;
int engine_id_;
ProcessThread* process_thread_;
scoped_ptr<CriticalSectionWrapper> list_crit_;
// The last time a REMB was sent.

View File

@ -19,6 +19,7 @@
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "modules/utility/interface/process_thread.h"
#include "system_wrappers/interface/scoped_ptr.h"
#include "video_engine/vie_remb.h"
@ -28,11 +29,25 @@ using ::testing::Return;
namespace webrtc {
// TODO(mflodman) Make a trigger function for this class to fake a clock and
// remove sleeps in the test.
class TestProcessThread : public ProcessThread {
public:
explicit TestProcessThread() {}
~TestProcessThread() {}
virtual WebRtc_Word32 Start() { return 0; }
virtual WebRtc_Word32 Stop() { return 0; }
virtual WebRtc_Word32 RegisterModule(const Module* module) { return 0; }
virtual WebRtc_Word32 DeRegisterModule(const Module* module) { return 0; }
};
class ViERembTest : public ::testing::Test {
protected:
virtual void SetUp() {
vie_remb_.reset(new VieRemb(1234));
process_thread_.reset(new TestProcessThread);
vie_remb_.reset(new VieRemb(process_thread_.get()));
}
scoped_ptr<TestProcessThread> process_thread_;
scoped_ptr<VieRemb> vie_remb_;
void TestSleep(unsigned int time_ms) {