Configure A/V sync in WebRtcVideoEngine2.

Sets up A/V sync for the first video receive channel with the default
voice channel. This is only done when conference mode is disabled to
preserve existing behavior. Ideally we'd know which voice channel to
sync with here.

R=mflodman@webrtc.org, stefan@webrtc.org
BUG=1788

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7577 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org 2014-10-31 12:59:34 +00:00
parent 4abadab708
commit 3bf3d238c8
5 changed files with 75 additions and 25 deletions

View File

@ -423,6 +423,7 @@ WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel(
<< " voice channel. Options: " << options.ToString();
WebRtcVideoChannel2* channel =
new WebRtcVideoChannel2(call_factory_,
voice_engine_,
voice_channel,
options,
external_encoder_factory_,
@ -745,20 +746,24 @@ class WebRtcVideoRenderFrame : public VideoFrame {
WebRtcVideoChannel2::WebRtcVideoChannel2(
WebRtcCallFactory* call_factory,
WebRtcVoiceEngine* voice_engine,
VoiceMediaChannel* voice_channel,
const VideoOptions& options,
WebRtcVideoEncoderFactory* external_encoder_factory,
WebRtcVideoDecoderFactory* external_decoder_factory,
WebRtcVideoEncoderFactory2* encoder_factory)
: unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_),
voice_channel_(voice_channel),
external_encoder_factory_(external_encoder_factory),
external_decoder_factory_(external_decoder_factory),
encoder_factory_(encoder_factory) {
// TODO(pbos): Connect the video and audio with |voice_channel|.
SetDefaultOptions();
options_.SetAll(options);
webrtc::Call::Config config(this);
config.overuse_callback = this;
if (voice_engine != NULL) {
config.voice_engine = voice_engine->voe()->engine();
}
// Set start bitrate for the call. A default is provided by SetDefaultOptions.
int start_bitrate_kbps;
@ -1009,6 +1014,18 @@ bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) {
webrtc::VideoReceiveStream::Config config;
ConfigureReceiverRtp(&config, sp);
// Set up A/V sync if there is a VoiceChannel.
// TODO(pbos): The A/V is synched by the receiving channel. So we need to know
// the SSRC of the remote audio channel in order to sync the correct webrtc
// VoiceEngine channel. For now sync the first channel in non-conference to
// match existing behavior in WebRtcVideoEngine.
if (voice_channel_ != NULL && receive_streams_.empty() &&
!options_.conference_mode.GetWithDefaultIfUnset(false)) {
config.audio_channel_id =
static_cast<WebRtcVoiceMediaChannel*>(voice_channel_)->voe_channel();
}
receive_streams_[ssrc] = new WebRtcVideoReceiveStream(
call_.get(), external_decoder_factory_, config, recv_codecs_);

View File

@ -211,6 +211,7 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler,
public webrtc::LoadObserver {
public:
WebRtcVideoChannel2(WebRtcCallFactory* call_factory,
WebRtcVoiceEngine* voice_engine,
VoiceMediaChannel* voice_channel,
const VideoOptions& options,
WebRtcVideoEncoderFactory* external_encoder_factory,
@ -470,6 +471,7 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler,
Settable<VideoCodecSettings> send_codec_;
std::vector<webrtc::RtpExtension> send_rtp_extensions_;
VoiceMediaChannel* const voice_channel_;
WebRtcVideoEncoderFactory* const external_encoder_factory_;
WebRtcVideoDecoderFactory* const external_decoder_factory_;
WebRtcVideoEncoderFactory2* const encoder_factory_;

View File

@ -34,6 +34,7 @@
#include "talk/media/webrtc/webrtcvideochannelfactory.h"
#include "talk/media/webrtc/webrtcvideoengine2.h"
#include "talk/media/webrtc/webrtcvideoengine2_unittest.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/stringutils.h"
#include "webrtc/video_encoder.h"
@ -328,6 +329,22 @@ class WebRtcVideoEngine2Test : public ::testing::Test {
}
protected:
class FakeCallFactory : public WebRtcCallFactory {
public:
FakeCallFactory() : fake_call_(NULL) {}
FakeCall* GetCall() { return fake_call_; }
private:
virtual webrtc::Call* CreateCall(
const webrtc::Call::Config& config) OVERRIDE {
assert(fake_call_ == NULL);
fake_call_ = new FakeCall(config);
return fake_call_;
}
FakeCall* fake_call_;
};
VideoMediaChannel* SetUpForExternalEncoderFactory(
cricket::WebRtcVideoEncoderFactory* encoder_factory,
const std::vector<VideoCodec>& codecs);
@ -341,9 +358,42 @@ class WebRtcVideoEngine2Test : public ::testing::Test {
VideoCodec default_rtx_codec_;
};
// TODO(pbos): Add test that verifies that sync is configured properly.
TEST_F(WebRtcVideoEngine2Test, DISABLED_CreateChannelWithVoiceEngine) {
FAIL() << "Not implemented."; // TODO(pbos): Implement.
TEST_F(WebRtcVideoEngine2Test, ConfiguresAvSyncForFirstReceiveChannel) {
FakeCallFactory call_factory;
engine_.SetCallFactory(&call_factory);
WebRtcVoiceEngine voice_engine;
engine_.SetVoiceEngine(&voice_engine);
voice_engine.Init(rtc::Thread::Current());
engine_.Init(rtc::Thread::Current());
rtc::scoped_ptr<VoiceMediaChannel> voice_channel(
voice_engine.CreateChannel());
ASSERT_TRUE(voice_channel.get() != NULL);
WebRtcVoiceMediaChannel* webrtc_voice_channel =
static_cast<WebRtcVoiceMediaChannel*>(voice_channel.get());
ASSERT_NE(webrtc_voice_channel->voe_channel(), -1);
rtc::scoped_ptr<VideoMediaChannel> channel(
engine_.CreateChannel(cricket::VideoOptions(), voice_channel.get()));
FakeCall* fake_call = call_factory.GetCall();
ASSERT_TRUE(fake_call != NULL);
webrtc::Call::Config call_config = fake_call->GetConfig();
ASSERT_TRUE(voice_engine.voe()->engine() != NULL);
ASSERT_EQ(voice_engine.voe()->engine(), call_config.voice_engine);
EXPECT_TRUE(channel->AddRecvStream(StreamParams::CreateLegacy(kSsrc)));
EXPECT_TRUE(channel->AddRecvStream(StreamParams::CreateLegacy(kSsrc + 1)));
std::vector<FakeVideoReceiveStream*> receive_streams =
fake_call->GetVideoReceiveStreams();
ASSERT_EQ(2u, receive_streams.size());
EXPECT_EQ(webrtc_voice_channel->voe_channel(),
receive_streams[0]->GetConfig().audio_channel_id);
EXPECT_EQ(-1, receive_streams[1]->GetConfig().audio_channel_id)
<< "AV sync should only be set up for the first receive channel.";
}
TEST_F(WebRtcVideoEngine2Test, FindCodec) {
@ -431,25 +481,6 @@ TEST_F(WebRtcVideoEngine2Test, SupportsAbsoluteSenderTimeHeaderExtension) {
void WebRtcVideoEngine2Test::TestStartBitrate(bool override_start_bitrate,
int start_bitrate_bps) {
class FakeCallFactory : public WebRtcCallFactory {
public:
FakeCallFactory() : fake_call_(NULL) {}
FakeCall* GetCall() {
return fake_call_;
}
private:
virtual webrtc::Call* CreateCall(
const webrtc::Call::Config& config) OVERRIDE {
assert(fake_call_ == NULL);
fake_call_ = new FakeCall(config);
return fake_call_;
}
FakeCall* fake_call_;
};
FakeCallFactory call_factory;
engine_.SetCallFactory(&call_factory);

View File

@ -190,7 +190,7 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
render_->AddRenderCallback(channel_, this);
if (voice_engine) {
if (voice_engine && config_.audio_channel_id != -1) {
video_engine_base_->SetVoiceEngine(voice_engine);
video_engine_base_->ConnectAudioChannel(channel_, config_.audio_channel_id);
}

View File

@ -85,7 +85,7 @@ class VideoReceiveStream {
Config()
: renderer(NULL),
render_delay_ms(0),
audio_channel_id(0),
audio_channel_id(-1),
pre_decode_callback(NULL),
pre_render_callback(NULL),
target_delay_ms(0) {}