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(); << " voice channel. Options: " << options.ToString();
WebRtcVideoChannel2* channel = WebRtcVideoChannel2* channel =
new WebRtcVideoChannel2(call_factory_, new WebRtcVideoChannel2(call_factory_,
voice_engine_,
voice_channel, voice_channel,
options, options,
external_encoder_factory_, external_encoder_factory_,
@ -745,20 +746,24 @@ class WebRtcVideoRenderFrame : public VideoFrame {
WebRtcVideoChannel2::WebRtcVideoChannel2( WebRtcVideoChannel2::WebRtcVideoChannel2(
WebRtcCallFactory* call_factory, WebRtcCallFactory* call_factory,
WebRtcVoiceEngine* voice_engine,
VoiceMediaChannel* voice_channel, VoiceMediaChannel* voice_channel,
const VideoOptions& options, const VideoOptions& options,
WebRtcVideoEncoderFactory* external_encoder_factory, WebRtcVideoEncoderFactory* external_encoder_factory,
WebRtcVideoDecoderFactory* external_decoder_factory, WebRtcVideoDecoderFactory* external_decoder_factory,
WebRtcVideoEncoderFactory2* encoder_factory) WebRtcVideoEncoderFactory2* encoder_factory)
: unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_), : unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_),
voice_channel_(voice_channel),
external_encoder_factory_(external_encoder_factory), external_encoder_factory_(external_encoder_factory),
external_decoder_factory_(external_decoder_factory), external_decoder_factory_(external_decoder_factory),
encoder_factory_(encoder_factory) { encoder_factory_(encoder_factory) {
// TODO(pbos): Connect the video and audio with |voice_channel|.
SetDefaultOptions(); SetDefaultOptions();
options_.SetAll(options); options_.SetAll(options);
webrtc::Call::Config config(this); webrtc::Call::Config config(this);
config.overuse_callback = 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. // Set start bitrate for the call. A default is provided by SetDefaultOptions.
int start_bitrate_kbps; int start_bitrate_kbps;
@ -1009,6 +1014,18 @@ bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) {
webrtc::VideoReceiveStream::Config config; webrtc::VideoReceiveStream::Config config;
ConfigureReceiverRtp(&config, sp); 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( receive_streams_[ssrc] = new WebRtcVideoReceiveStream(
call_.get(), external_decoder_factory_, config, recv_codecs_); call_.get(), external_decoder_factory_, config, recv_codecs_);

View File

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

View File

@ -34,6 +34,7 @@
#include "talk/media/webrtc/webrtcvideochannelfactory.h" #include "talk/media/webrtc/webrtcvideochannelfactory.h"
#include "talk/media/webrtc/webrtcvideoengine2.h" #include "talk/media/webrtc/webrtcvideoengine2.h"
#include "talk/media/webrtc/webrtcvideoengine2_unittest.h" #include "talk/media/webrtc/webrtcvideoengine2_unittest.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
#include "webrtc/base/gunit.h" #include "webrtc/base/gunit.h"
#include "webrtc/base/stringutils.h" #include "webrtc/base/stringutils.h"
#include "webrtc/video_encoder.h" #include "webrtc/video_encoder.h"
@ -328,6 +329,22 @@ class WebRtcVideoEngine2Test : public ::testing::Test {
} }
protected: 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( VideoMediaChannel* SetUpForExternalEncoderFactory(
cricket::WebRtcVideoEncoderFactory* encoder_factory, cricket::WebRtcVideoEncoderFactory* encoder_factory,
const std::vector<VideoCodec>& codecs); const std::vector<VideoCodec>& codecs);
@ -341,9 +358,42 @@ class WebRtcVideoEngine2Test : public ::testing::Test {
VideoCodec default_rtx_codec_; VideoCodec default_rtx_codec_;
}; };
// TODO(pbos): Add test that verifies that sync is configured properly. TEST_F(WebRtcVideoEngine2Test, ConfiguresAvSyncForFirstReceiveChannel) {
TEST_F(WebRtcVideoEngine2Test, DISABLED_CreateChannelWithVoiceEngine) { FakeCallFactory call_factory;
FAIL() << "Not implemented."; // TODO(pbos): Implement. 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) { TEST_F(WebRtcVideoEngine2Test, FindCodec) {
@ -431,25 +481,6 @@ TEST_F(WebRtcVideoEngine2Test, SupportsAbsoluteSenderTimeHeaderExtension) {
void WebRtcVideoEngine2Test::TestStartBitrate(bool override_start_bitrate, void WebRtcVideoEngine2Test::TestStartBitrate(bool override_start_bitrate,
int start_bitrate_bps) { 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; FakeCallFactory call_factory;
engine_.SetCallFactory(&call_factory); engine_.SetCallFactory(&call_factory);

View File

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

View File

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