2015-10-16 14:35:07 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2015 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 <list>
|
2017-03-27 07:15:49 -07:00
|
|
|
#include <map>
|
2016-03-12 06:10:44 -08:00
|
|
|
#include <memory>
|
2017-05-08 11:52:38 -07:00
|
|
|
#include <utility>
|
2015-10-16 14:35:07 -07:00
|
|
|
|
2017-05-08 11:52:38 -07:00
|
|
|
#include "webrtc/base/ptr_util.h"
|
2016-12-07 04:52:58 -08:00
|
|
|
#include "webrtc/call/audio_state.h"
|
|
|
|
|
#include "webrtc/call/call.h"
|
2017-05-08 11:52:38 -07:00
|
|
|
#include "webrtc/call/fake_rtp_transport_controller_send.h"
|
2016-10-07 11:53:05 -07:00
|
|
|
#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
|
2016-12-07 04:52:58 -08:00
|
|
|
#include "webrtc/modules/audio_mixer/audio_mixer_impl.h"
|
2017-05-08 11:52:38 -07:00
|
|
|
#include "webrtc/modules/congestion_controller/include/mock/mock_send_side_congestion_controller.h"
|
2016-09-30 22:29:43 -07:00
|
|
|
#include "webrtc/test/gtest.h"
|
2017-04-10 05:15:48 -07:00
|
|
|
#include "webrtc/test/mock_audio_decoder_factory.h"
|
2017-01-13 07:41:19 -08:00
|
|
|
#include "webrtc/test/mock_transport.h"
|
2015-11-03 10:15:49 +01:00
|
|
|
#include "webrtc/test/mock_voice_engine.h"
|
2015-10-16 14:35:07 -07:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
struct CallHelper {
|
2016-06-13 07:34:51 -07:00
|
|
|
explicit CallHelper(
|
|
|
|
|
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory = nullptr)
|
|
|
|
|
: voice_engine_(decoder_factory) {
|
2015-11-06 15:34:49 -08:00
|
|
|
webrtc::AudioState::Config audio_state_config;
|
|
|
|
|
audio_state_config.voice_engine = &voice_engine_;
|
2016-11-17 06:48:48 -08:00
|
|
|
audio_state_config.audio_mixer = webrtc::AudioMixerImpl::Create();
|
2016-11-17 06:28:59 -08:00
|
|
|
EXPECT_CALL(voice_engine_, audio_device_module());
|
|
|
|
|
EXPECT_CALL(voice_engine_, audio_processing());
|
|
|
|
|
EXPECT_CALL(voice_engine_, audio_transport());
|
2016-10-07 11:53:05 -07:00
|
|
|
webrtc::Call::Config config(&event_log_);
|
2015-11-06 15:34:49 -08:00
|
|
|
config.audio_state = webrtc::AudioState::Create(audio_state_config);
|
2015-10-16 14:35:07 -07:00
|
|
|
call_.reset(webrtc::Call::Create(config));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
webrtc::Call* operator->() { return call_.get(); }
|
2016-11-14 11:30:07 -08:00
|
|
|
webrtc::test::MockVoiceEngine* voice_engine() { return &voice_engine_; }
|
2015-10-16 14:35:07 -07:00
|
|
|
|
|
|
|
|
private:
|
2015-11-16 07:34:50 -08:00
|
|
|
testing::NiceMock<webrtc::test::MockVoiceEngine> voice_engine_;
|
2016-10-07 11:53:05 -07:00
|
|
|
webrtc::RtcEventLogNullImpl event_log_;
|
2016-03-12 06:10:44 -08:00
|
|
|
std::unique_ptr<webrtc::Call> call_;
|
2015-10-16 14:35:07 -07:00
|
|
|
};
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, ConstructDestruct) {
|
|
|
|
|
CallHelper call;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, CreateDestroy_AudioSendStream) {
|
|
|
|
|
CallHelper call;
|
|
|
|
|
AudioSendStream::Config config(nullptr);
|
|
|
|
|
config.rtp.ssrc = 42;
|
|
|
|
|
config.voe_channel_id = 123;
|
|
|
|
|
AudioSendStream* stream = call->CreateAudioSendStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
call->DestroyAudioSendStream(stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, CreateDestroy_AudioReceiveStream) {
|
2016-06-13 07:34:51 -07:00
|
|
|
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory(
|
|
|
|
|
new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>);
|
|
|
|
|
CallHelper call(decoder_factory);
|
2015-10-16 14:35:07 -07:00
|
|
|
AudioReceiveStream::Config config;
|
|
|
|
|
config.rtp.remote_ssrc = 42;
|
|
|
|
|
config.voe_channel_id = 123;
|
2016-06-13 07:34:51 -07:00
|
|
|
config.decoder_factory = decoder_factory;
|
2015-10-16 14:35:07 -07:00
|
|
|
AudioReceiveStream* stream = call->CreateAudioReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
call->DestroyAudioReceiveStream(stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, CreateDestroy_AudioSendStreams) {
|
|
|
|
|
CallHelper call;
|
|
|
|
|
AudioSendStream::Config config(nullptr);
|
|
|
|
|
config.voe_channel_id = 123;
|
|
|
|
|
std::list<AudioSendStream*> streams;
|
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
|
for (uint32_t ssrc = 0; ssrc < 1234567; ssrc += 34567) {
|
|
|
|
|
config.rtp.ssrc = ssrc;
|
|
|
|
|
AudioSendStream* stream = call->CreateAudioSendStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
if (ssrc & 1) {
|
|
|
|
|
streams.push_back(stream);
|
|
|
|
|
} else {
|
|
|
|
|
streams.push_front(stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (auto s : streams) {
|
|
|
|
|
call->DestroyAudioSendStream(s);
|
|
|
|
|
}
|
|
|
|
|
streams.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, CreateDestroy_AudioReceiveStreams) {
|
2016-06-13 07:34:51 -07:00
|
|
|
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory(
|
|
|
|
|
new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>);
|
|
|
|
|
CallHelper call(decoder_factory);
|
2015-10-16 14:35:07 -07:00
|
|
|
AudioReceiveStream::Config config;
|
|
|
|
|
config.voe_channel_id = 123;
|
2016-06-13 07:34:51 -07:00
|
|
|
config.decoder_factory = decoder_factory;
|
2015-10-16 14:35:07 -07:00
|
|
|
std::list<AudioReceiveStream*> streams;
|
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
|
for (uint32_t ssrc = 0; ssrc < 1234567; ssrc += 34567) {
|
|
|
|
|
config.rtp.remote_ssrc = ssrc;
|
|
|
|
|
AudioReceiveStream* stream = call->CreateAudioReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
if (ssrc & 1) {
|
|
|
|
|
streams.push_back(stream);
|
|
|
|
|
} else {
|
|
|
|
|
streams.push_front(stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (auto s : streams) {
|
|
|
|
|
call->DestroyAudioReceiveStream(s);
|
|
|
|
|
}
|
|
|
|
|
streams.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-23 23:37:14 -07:00
|
|
|
|
2016-11-14 11:30:07 -08:00
|
|
|
TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_RecvFirst) {
|
|
|
|
|
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory(
|
|
|
|
|
new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>);
|
|
|
|
|
CallHelper call(decoder_factory);
|
|
|
|
|
|
|
|
|
|
constexpr int kRecvChannelId = 101;
|
|
|
|
|
|
|
|
|
|
// Set up the mock to create a channel proxy which we know of, so that we can
|
|
|
|
|
// add our expectations to it.
|
|
|
|
|
test::MockVoEChannelProxy* recv_channel_proxy = nullptr;
|
|
|
|
|
EXPECT_CALL(*call.voice_engine(), ChannelProxyFactory(testing::_))
|
|
|
|
|
.WillRepeatedly(testing::Invoke([&](int channel_id) {
|
|
|
|
|
test::MockVoEChannelProxy* channel_proxy =
|
|
|
|
|
new testing::NiceMock<test::MockVoEChannelProxy>();
|
|
|
|
|
EXPECT_CALL(*channel_proxy, GetAudioDecoderFactory())
|
|
|
|
|
.WillRepeatedly(testing::ReturnRef(decoder_factory));
|
2017-03-27 07:15:49 -07:00
|
|
|
EXPECT_CALL(*channel_proxy, SetReceiveCodecs(testing::_))
|
|
|
|
|
.WillRepeatedly(testing::Invoke(
|
|
|
|
|
[](const std::map<int, SdpAudioFormat>& codecs) {
|
|
|
|
|
EXPECT_THAT(codecs, testing::IsEmpty());
|
|
|
|
|
}));
|
2016-11-14 11:30:07 -08:00
|
|
|
// If being called for the send channel, save a pointer to the channel
|
|
|
|
|
// proxy for later.
|
|
|
|
|
if (channel_id == kRecvChannelId) {
|
|
|
|
|
EXPECT_FALSE(recv_channel_proxy);
|
|
|
|
|
recv_channel_proxy = channel_proxy;
|
|
|
|
|
}
|
|
|
|
|
return channel_proxy;
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
AudioReceiveStream::Config recv_config;
|
|
|
|
|
recv_config.rtp.remote_ssrc = 42;
|
|
|
|
|
recv_config.rtp.local_ssrc = 777;
|
|
|
|
|
recv_config.voe_channel_id = kRecvChannelId;
|
|
|
|
|
recv_config.decoder_factory = decoder_factory;
|
|
|
|
|
AudioReceiveStream* recv_stream = call->CreateAudioReceiveStream(recv_config);
|
|
|
|
|
EXPECT_NE(recv_stream, nullptr);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*recv_channel_proxy, AssociateSendChannel(testing::_)).Times(1);
|
|
|
|
|
AudioSendStream::Config send_config(nullptr);
|
|
|
|
|
send_config.rtp.ssrc = 777;
|
|
|
|
|
send_config.voe_channel_id = 123;
|
|
|
|
|
AudioSendStream* send_stream = call->CreateAudioSendStream(send_config);
|
|
|
|
|
EXPECT_NE(send_stream, nullptr);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*recv_channel_proxy, DisassociateSendChannel()).Times(1);
|
|
|
|
|
call->DestroyAudioSendStream(send_stream);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*recv_channel_proxy, DisassociateSendChannel()).Times(1);
|
|
|
|
|
call->DestroyAudioReceiveStream(recv_stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_SendFirst) {
|
|
|
|
|
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory(
|
|
|
|
|
new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>);
|
|
|
|
|
CallHelper call(decoder_factory);
|
|
|
|
|
|
|
|
|
|
constexpr int kRecvChannelId = 101;
|
|
|
|
|
|
|
|
|
|
// Set up the mock to create a channel proxy which we know of, so that we can
|
|
|
|
|
// add our expectations to it.
|
|
|
|
|
test::MockVoEChannelProxy* recv_channel_proxy = nullptr;
|
|
|
|
|
EXPECT_CALL(*call.voice_engine(), ChannelProxyFactory(testing::_))
|
|
|
|
|
.WillRepeatedly(testing::Invoke([&](int channel_id) {
|
|
|
|
|
test::MockVoEChannelProxy* channel_proxy =
|
|
|
|
|
new testing::NiceMock<test::MockVoEChannelProxy>();
|
|
|
|
|
EXPECT_CALL(*channel_proxy, GetAudioDecoderFactory())
|
|
|
|
|
.WillRepeatedly(testing::ReturnRef(decoder_factory));
|
2017-03-27 07:15:49 -07:00
|
|
|
EXPECT_CALL(*channel_proxy, SetReceiveCodecs(testing::_))
|
|
|
|
|
.WillRepeatedly(testing::Invoke(
|
|
|
|
|
[](const std::map<int, SdpAudioFormat>& codecs) {
|
|
|
|
|
EXPECT_THAT(codecs, testing::IsEmpty());
|
|
|
|
|
}));
|
2016-11-14 11:30:07 -08:00
|
|
|
// If being called for the send channel, save a pointer to the channel
|
|
|
|
|
// proxy for later.
|
|
|
|
|
if (channel_id == kRecvChannelId) {
|
|
|
|
|
EXPECT_FALSE(recv_channel_proxy);
|
|
|
|
|
recv_channel_proxy = channel_proxy;
|
|
|
|
|
// We need to set this expectation here since the channel proxy is
|
|
|
|
|
// created as a side effect of CreateAudioReceiveStream().
|
|
|
|
|
EXPECT_CALL(*recv_channel_proxy,
|
|
|
|
|
AssociateSendChannel(testing::_)).Times(1);
|
|
|
|
|
}
|
|
|
|
|
return channel_proxy;
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
AudioSendStream::Config send_config(nullptr);
|
|
|
|
|
send_config.rtp.ssrc = 777;
|
|
|
|
|
send_config.voe_channel_id = 123;
|
|
|
|
|
AudioSendStream* send_stream = call->CreateAudioSendStream(send_config);
|
|
|
|
|
EXPECT_NE(send_stream, nullptr);
|
|
|
|
|
|
|
|
|
|
AudioReceiveStream::Config recv_config;
|
|
|
|
|
recv_config.rtp.remote_ssrc = 42;
|
|
|
|
|
recv_config.rtp.local_ssrc = 777;
|
|
|
|
|
recv_config.voe_channel_id = kRecvChannelId;
|
|
|
|
|
recv_config.decoder_factory = decoder_factory;
|
|
|
|
|
AudioReceiveStream* recv_stream = call->CreateAudioReceiveStream(recv_config);
|
|
|
|
|
EXPECT_NE(recv_stream, nullptr);
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*recv_channel_proxy, DisassociateSendChannel()).Times(1);
|
|
|
|
|
call->DestroyAudioReceiveStream(recv_stream);
|
|
|
|
|
|
|
|
|
|
call->DestroyAudioSendStream(send_stream);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-23 23:37:14 -07:00
|
|
|
TEST(CallTest, CreateDestroy_FlexfecReceiveStream) {
|
|
|
|
|
CallHelper call;
|
2017-01-13 07:41:19 -08:00
|
|
|
MockTransport rtcp_send_transport;
|
|
|
|
|
FlexfecReceiveStream::Config config(&rtcp_send_transport);
|
2016-12-08 04:17:53 -08:00
|
|
|
config.payload_type = 118;
|
|
|
|
|
config.remote_ssrc = 38837212;
|
2016-10-23 23:37:14 -07:00
|
|
|
config.protected_media_ssrcs = {27273};
|
|
|
|
|
|
|
|
|
|
FlexfecReceiveStream* stream = call->CreateFlexfecReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
call->DestroyFlexfecReceiveStream(stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, CreateDestroy_FlexfecReceiveStreams) {
|
|
|
|
|
CallHelper call;
|
2017-01-13 07:41:19 -08:00
|
|
|
MockTransport rtcp_send_transport;
|
|
|
|
|
FlexfecReceiveStream::Config config(&rtcp_send_transport);
|
2016-12-08 04:17:53 -08:00
|
|
|
config.payload_type = 118;
|
2016-10-23 23:37:14 -07:00
|
|
|
std::list<FlexfecReceiveStream*> streams;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
|
for (uint32_t ssrc = 0; ssrc < 1234567; ssrc += 34567) {
|
2016-12-08 04:17:53 -08:00
|
|
|
config.remote_ssrc = ssrc;
|
2016-10-23 23:37:14 -07:00
|
|
|
config.protected_media_ssrcs = {ssrc + 1};
|
|
|
|
|
FlexfecReceiveStream* stream = call->CreateFlexfecReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
if (ssrc & 1) {
|
|
|
|
|
streams.push_back(stream);
|
|
|
|
|
} else {
|
|
|
|
|
streams.push_front(stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (auto s : streams) {
|
|
|
|
|
call->DestroyFlexfecReceiveStream(s);
|
|
|
|
|
}
|
|
|
|
|
streams.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(CallTest, MultipleFlexfecReceiveStreamsProtectingSingleVideoStream) {
|
|
|
|
|
CallHelper call;
|
2017-01-13 07:41:19 -08:00
|
|
|
MockTransport rtcp_send_transport;
|
|
|
|
|
FlexfecReceiveStream::Config config(&rtcp_send_transport);
|
2016-12-08 04:17:53 -08:00
|
|
|
config.payload_type = 118;
|
2016-10-23 23:37:14 -07:00
|
|
|
config.protected_media_ssrcs = {1324234};
|
|
|
|
|
FlexfecReceiveStream* stream;
|
|
|
|
|
std::list<FlexfecReceiveStream*> streams;
|
|
|
|
|
|
2016-12-08 04:17:53 -08:00
|
|
|
config.remote_ssrc = 838383;
|
2016-10-23 23:37:14 -07:00
|
|
|
stream = call->CreateFlexfecReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
streams.push_back(stream);
|
|
|
|
|
|
2016-12-08 04:17:53 -08:00
|
|
|
config.remote_ssrc = 424993;
|
2016-10-23 23:37:14 -07:00
|
|
|
stream = call->CreateFlexfecReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
streams.push_back(stream);
|
|
|
|
|
|
2016-12-08 04:17:53 -08:00
|
|
|
config.remote_ssrc = 99383;
|
2016-10-23 23:37:14 -07:00
|
|
|
stream = call->CreateFlexfecReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
streams.push_back(stream);
|
|
|
|
|
|
2016-12-08 04:17:53 -08:00
|
|
|
config.remote_ssrc = 5548;
|
2016-10-23 23:37:14 -07:00
|
|
|
stream = call->CreateFlexfecReceiveStream(config);
|
|
|
|
|
EXPECT_NE(stream, nullptr);
|
|
|
|
|
streams.push_back(stream);
|
|
|
|
|
|
|
|
|
|
for (auto s : streams) {
|
|
|
|
|
call->DestroyFlexfecReceiveStream(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-08 11:52:38 -07:00
|
|
|
// TODO(zstein): This is just a motivating example for
|
|
|
|
|
// MockSendSideCongestionController. It should be deleted once we have more
|
|
|
|
|
// meaningful tests.
|
|
|
|
|
TEST(CallTest, MockSendSideCongestionControllerExample) {
|
|
|
|
|
RtcEventLogNullImpl event_log;
|
|
|
|
|
Call::Config config(&event_log);
|
|
|
|
|
|
|
|
|
|
SimulatedClock clock(123456);
|
|
|
|
|
PacketRouter packet_router;
|
|
|
|
|
testing::NiceMock<test::MockSendSideCongestionController> mock_cc(
|
|
|
|
|
&clock, &event_log, &packet_router);
|
|
|
|
|
auto transport_send =
|
|
|
|
|
rtc::MakeUnique<FakeRtpTransportControllerSend>(&mock_cc);
|
|
|
|
|
std::unique_ptr<Call> call(Call::Create(config, std::move(transport_send)));
|
|
|
|
|
|
|
|
|
|
Call::Config::BitrateConfig bitrate_config;
|
|
|
|
|
bitrate_config.min_bitrate_bps = 1;
|
|
|
|
|
bitrate_config.start_bitrate_bps = 2;
|
|
|
|
|
bitrate_config.max_bitrate_bps = 3;
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(mock_cc, SetBweBitrates(1, 2, 3));
|
|
|
|
|
call->SetBitrateConfig(bitrate_config);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-16 14:35:07 -07:00
|
|
|
} // namespace webrtc
|