Store/restore RTP state for audio streams with same SSRC within a call

This functionality already exists for video streams, so not having it
for audio is unexpected and has lead to problems.

BUG=webrtc:7631

Review-Url: https://codereview.webrtc.org/2887733002
Cr-Commit-Position: refs/heads/master@{#18231}
This commit is contained in:
ossu
2017-05-23 06:07:11 -07:00
committed by Commit bot
parent 23ac8b49f4
commit c3d4b48e7e
7 changed files with 165 additions and 44 deletions

View File

@ -28,7 +28,6 @@
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/congestion_controller/include/send_side_congestion_controller.h"
#include "webrtc/modules/pacing/paced_sender.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/voice_engine/channel_proxy.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/transmit_mixer.h"
@ -59,7 +58,8 @@ AudioSendStream::AudioSendStream(
RtpTransportControllerSendInterface* transport,
BitrateAllocator* bitrate_allocator,
RtcEventLog* event_log,
RtcpRttStats* rtcp_rtt_stats)
RtcpRttStats* rtcp_rtt_stats,
const rtc::Optional<RtpState>& suspended_rtp_state)
: worker_queue_(worker_queue),
config_(Config(nullptr)),
audio_state_(audio_state),
@ -68,7 +68,9 @@ AudioSendStream::AudioSendStream(
transport_(transport),
packet_loss_tracker_(kPacketLossTrackerMaxWindowSizeMs,
kPacketLossRateMinNumAckedPackets,
kRecoverablePacketLossRateMinNumAckedPairs) {
kRecoverablePacketLossRateMinNumAckedPairs),
rtp_rtcp_module_(nullptr),
suspended_rtp_state_(suspended_rtp_state) {
LOG(LS_INFO) << "AudioSendStream: " << config.ToString();
RTC_DCHECK_NE(config.voe_channel_id, -1);
RTC_DCHECK(audio_state_.get());
@ -81,6 +83,9 @@ AudioSendStream::AudioSendStream(
channel_proxy_->SetRtcpRttStats(rtcp_rtt_stats);
channel_proxy_->SetRTCPStatus(true);
transport_->send_side_cc()->RegisterPacketFeedbackObserver(this);
RtpReceiver* rtpReceiver = nullptr; // Unused, but required for call.
channel_proxy_->GetRtpRtcp(&rtp_rtcp_module_, &rtpReceiver);
RTC_DCHECK(rtp_rtcp_module_);
ConfigureStream(this, config, true);
@ -112,6 +117,9 @@ void AudioSendStream::ConfigureStream(
if (first_time || old_config.rtp.ssrc != new_config.rtp.ssrc) {
channel_proxy->SetLocalSSRC(new_config.rtp.ssrc);
if (stream->suspended_rtp_state_) {
stream->rtp_rtcp_module_->SetRtpState(*stream->suspended_rtp_state_);
}
}
if (first_time || old_config.rtp.c_name != new_config.rtp.c_name) {
channel_proxy->SetRTCP_CNAME(new_config.rtp.c_name);
@ -375,6 +383,10 @@ void AudioSendStream::SetTransportOverhead(int transport_overhead_per_packet) {
channel_proxy_->SetTransportOverhead(transport_overhead_per_packet);
}
RtpState AudioSendStream::GetRtpState() const {
return rtp_rtcp_module_->GetRtpState();
}
VoiceEngine* AudioSendStream::voice_engine() const {
internal::AudioState* audio_state =
static_cast<internal::AudioState*>(audio_state_.get());
@ -588,13 +600,10 @@ void AudioSendStream::RemoveBitrateObserver() {
void AudioSendStream::RegisterCngPayloadType(int payload_type,
int clockrate_hz) {
RtpRtcp* rtpRtcpModule = nullptr;
RtpReceiver* rtpReceiver = nullptr; // Unused, but required for call.
channel_proxy_->GetRtpRtcp(&rtpRtcpModule, &rtpReceiver);
const CodecInst codec = {payload_type, "CN", clockrate_hz, 0, 1, 0};
if (rtpRtcpModule->RegisterSendPayload(codec) != 0) {
rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
if (rtpRtcpModule->RegisterSendPayload(codec) != 0) {
if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) {
rtp_rtcp_module_->DeRegisterSendPayload(codec.pltype);
if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) {
LOG(LS_ERROR) << "RegisterCngPayloadType() failed to register CN to "
"RTP/RTCP module";
}

View File

@ -19,7 +19,7 @@
#include "webrtc/call/audio_send_stream.h"
#include "webrtc/call/audio_state.h"
#include "webrtc/call/bitrate_allocator.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/voice_engine/transport_feedback_packet_loss_tracker.h"
namespace webrtc {
@ -44,7 +44,8 @@ class AudioSendStream final : public webrtc::AudioSendStream,
RtpTransportControllerSendInterface* transport,
BitrateAllocator* bitrate_allocator,
RtcEventLog* event_log,
RtcpRttStats* rtcp_rtt_stats);
RtcpRttStats* rtcp_rtt_stats,
const rtc::Optional<RtpState>& suspended_rtp_state);
~AudioSendStream() override;
// webrtc::AudioSendStream implementation.
@ -74,6 +75,8 @@ class AudioSendStream final : public webrtc::AudioSendStream,
const webrtc::AudioSendStream::Config& config() const;
void SetTransportOverhead(int transport_overhead_per_packet);
RtpState GetRtpState() const;
private:
VoiceEngine* voice_engine() const;
@ -111,6 +114,9 @@ class AudioSendStream final : public webrtc::AudioSendStream,
TransportFeedbackPacketLossTracker packet_loss_tracker_
GUARDED_BY(&packet_loss_tracker_cs_);
RtpRtcp* rtp_rtcp_module_;
rtc::Optional<RtpState> const suspended_rtp_state_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream);
};
} // namespace internal

View File

@ -354,7 +354,7 @@ TEST(AudioSendStreamTest, ConstructDestruct) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
}
TEST(AudioSendStreamTest, SendTelephoneEvent) {
@ -362,7 +362,7 @@ TEST(AudioSendStreamTest, SendTelephoneEvent) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
helper.SetupMockForSendTelephoneEvent();
EXPECT_TRUE(send_stream.SendTelephoneEvent(kTelephoneEventPayloadType,
kTelephoneEventPayloadFrequency, kTelephoneEventCode,
@ -374,7 +374,7 @@ TEST(AudioSendStreamTest, SetMuted) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
EXPECT_CALL(*helper.channel_proxy(), SetInputMute(true));
send_stream.SetMuted(true);
}
@ -384,7 +384,7 @@ TEST(AudioSendStreamTest, AudioBweCorrectObjectsOnChannelProxy) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
}
TEST(AudioSendStreamTest, NoAudioBweCorrectObjectsOnChannelProxy) {
@ -392,7 +392,7 @@ TEST(AudioSendStreamTest, NoAudioBweCorrectObjectsOnChannelProxy) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
}
TEST(AudioSendStreamTest, GetStats) {
@ -400,7 +400,7 @@ TEST(AudioSendStreamTest, GetStats) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
helper.SetupMockForGetStats();
AudioSendStream::Stats stats = send_stream.GetStats();
EXPECT_EQ(kSsrc, stats.local_ssrc);
@ -431,7 +431,7 @@ TEST(AudioSendStreamTest, GetStatsTypingNoiseDetected) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
helper.SetupMockForGetStats();
EXPECT_FALSE(send_stream.GetStats().typing_noise_detected);
@ -465,7 +465,7 @@ TEST(AudioSendStreamTest, SendCodecAppliesNetworkAdaptor) {
internal::AudioSendStream send_stream(
stream_config, helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
}
// VAD is applied when codec is mono and the CNG frequency matches the codec
@ -489,7 +489,7 @@ TEST(AudioSendStreamTest, SendCodecCanApplyVad) {
internal::AudioSendStream send_stream(
stream_config, helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
// We cannot truly determine if the encoder created is an AudioEncoderCng. It
// is the only reasonable implementation that will return something from
@ -503,7 +503,7 @@ TEST(AudioSendStreamTest, DoesNotPassHigherBitrateThanMaxBitrate) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
EXPECT_CALL(*helper.channel_proxy(),
SetBitrate(helper.config().max_bitrate_bps, _));
send_stream.OnBitrateUpdated(helper.config().max_bitrate_bps + 5000, 0.0, 50,
@ -515,7 +515,7 @@ TEST(AudioSendStreamTest, ProbingIntervalOnBitrateUpdated) {
internal::AudioSendStream send_stream(
helper.config(), helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
EXPECT_CALL(*helper.channel_proxy(), SetBitrate(_, 5000));
send_stream.OnBitrateUpdated(50000, 0.0, 50, 5000);
}
@ -538,7 +538,7 @@ TEST(AudioSendStreamTest, DontRecreateEncoder) {
internal::AudioSendStream send_stream(
stream_config, helper.audio_state(), helper.worker_queue(),
helper.transport(), helper.bitrate_allocator(), helper.event_log(),
helper.rtcp_rtt_stats());
helper.rtcp_rtt_stats(), rtc::Optional<RtpState>());
send_stream.Reconfigure(stream_config);
}

View File

@ -93,6 +93,7 @@ if (rtc_include_tests) {
]
deps = [
":call",
"../api:mock_audio_mixer",
"../base:rtc_base_approved",
"../logging:rtc_event_log_api",
"../modules/audio_device:mock_audio_device",

View File

@ -305,7 +305,12 @@ class Call : public webrtc::Call,
std::map<uint32_t, VideoSendStream*> video_send_ssrcs_ GUARDED_BY(send_crit_);
std::set<VideoSendStream*> video_send_streams_ GUARDED_BY(send_crit_);
VideoSendStream::RtpStateMap suspended_video_send_ssrcs_;
using RtpStateMap = std::map<uint32_t, RtpState>;
RtpStateMap suspended_audio_send_ssrcs_
GUARDED_BY(configuration_thread_checker_);
RtpStateMap suspended_video_send_ssrcs_
GUARDED_BY(configuration_thread_checker_);
webrtc::RtcEventLog* event_log_;
// The following members are only accessed (exclusively) from one thread and
@ -392,7 +397,7 @@ Call::Call(const Call::Config& config,
video_send_delay_stats_(new SendDelayStats(clock_)),
start_ms_(clock_->TimeInMilliseconds()),
worker_queue_("call_worker_queue") {
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RTC_DCHECK(config.event_log != nullptr);
RTC_DCHECK_GE(config.bitrate_config.min_bitrate_bps, 0);
RTC_DCHECK_GE(config.bitrate_config.start_bitrate_bps,
@ -426,7 +431,7 @@ Call::Call(const Call::Config& config,
}
Call::~Call() {
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RTC_CHECK(audio_send_ssrcs_.empty());
RTC_CHECK(video_send_ssrcs_.empty());
@ -553,18 +558,28 @@ void Call::UpdateReceiveHistograms() {
PacketReceiver* Call::Receiver() {
// TODO(solenberg): Some test cases in EndToEndTest use this from a different
// thread. Re-enable once that is fixed.
// RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
// RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
return this;
}
webrtc::AudioSendStream* Call::CreateAudioSendStream(
const webrtc::AudioSendStream::Config& config) {
TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
event_log_->LogAudioSendStreamConfig(CreateRtcLogStreamConfig(config));
rtc::Optional<RtpState> suspended_rtp_state;
{
const auto& iter = suspended_audio_send_ssrcs_.find(config.rtp.ssrc);
if (iter != suspended_audio_send_ssrcs_.end()) {
suspended_rtp_state.emplace(iter->second);
}
}
AudioSendStream* send_stream = new AudioSendStream(
config, config_.audio_state, &worker_queue_, transport_send_.get(),
bitrate_allocator_.get(), event_log_, call_stats_->rtcp_rtt_stats());
bitrate_allocator_.get(), event_log_, call_stats_->rtcp_rtt_stats(),
suspended_rtp_state);
{
WriteLockScoped write_lock(*send_crit_);
RTC_DCHECK(audio_send_ssrcs_.find(config.rtp.ssrc) ==
@ -586,14 +601,15 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream(
void Call::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) {
TRACE_EVENT0("webrtc", "Call::DestroyAudioSendStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RTC_DCHECK(send_stream != nullptr);
send_stream->Stop();
webrtc::internal::AudioSendStream* audio_send_stream =
static_cast<webrtc::internal::AudioSendStream*>(send_stream);
uint32_t ssrc = audio_send_stream->config().rtp.ssrc;
const uint32_t ssrc = audio_send_stream->config().rtp.ssrc;
suspended_audio_send_ssrcs_[ssrc] = audio_send_stream->GetRtpState();
{
WriteLockScoped write_lock(*send_crit_);
size_t num_deleted = audio_send_ssrcs_.erase(ssrc);
@ -614,7 +630,7 @@ void Call::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) {
webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream(
const webrtc::AudioReceiveStream::Config& config) {
TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
event_log_->LogAudioReceiveStreamConfig(CreateRtcLogStreamConfig(config));
AudioReceiveStream* receive_stream =
new AudioReceiveStream(transport_send_->packet_router(), config,
@ -643,7 +659,7 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream(
void Call::DestroyAudioReceiveStream(
webrtc::AudioReceiveStream* receive_stream) {
TRACE_EVENT0("webrtc", "Call::DestroyAudioReceiveStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RTC_DCHECK(receive_stream != nullptr);
webrtc::internal::AudioReceiveStream* audio_receive_stream =
static_cast<webrtc::internal::AudioReceiveStream*>(receive_stream);
@ -673,7 +689,7 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream(
webrtc::VideoSendStream::Config config,
VideoEncoderConfig encoder_config) {
TRACE_EVENT0("webrtc", "Call::CreateVideoSendStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
video_send_delay_stats_->AddSsrcs(config);
for (size_t ssrc_index = 0; ssrc_index < config.rtp.ssrcs.size();
@ -709,7 +725,7 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream(
void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
TRACE_EVENT0("webrtc", "Call::DestroyVideoSendStream");
RTC_DCHECK(send_stream != nullptr);
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
send_stream->Stop();
@ -744,7 +760,7 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
webrtc::VideoReceiveStream::Config configuration) {
TRACE_EVENT0("webrtc", "Call::CreateVideoReceiveStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
VideoReceiveStream* receive_stream =
new VideoReceiveStream(num_cpu_cores_, transport_send_->packet_router(),
@ -778,7 +794,7 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
void Call::DestroyVideoReceiveStream(
webrtc::VideoReceiveStream* receive_stream) {
TRACE_EVENT0("webrtc", "Call::DestroyVideoReceiveStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RTC_DCHECK(receive_stream != nullptr);
VideoReceiveStream* receive_stream_impl =
static_cast<VideoReceiveStream*>(receive_stream);
@ -807,7 +823,7 @@ void Call::DestroyVideoReceiveStream(
FlexfecReceiveStream* Call::CreateFlexfecReceiveStream(
const FlexfecReceiveStream::Config& config) {
TRACE_EVENT0("webrtc", "Call::CreateFlexfecReceiveStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RecoveredPacketReceiver* recovered_packet_receiver = this;
FlexfecReceiveStreamImpl* receive_stream = new FlexfecReceiveStreamImpl(
@ -834,7 +850,7 @@ FlexfecReceiveStream* Call::CreateFlexfecReceiveStream(
void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) {
TRACE_EVENT0("webrtc", "Call::DestroyFlexfecReceiveStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RTC_DCHECK(receive_stream != nullptr);
// There exist no other derived classes of FlexfecReceiveStream,
@ -862,7 +878,7 @@ void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) {
Call::Stats Call::GetStats() const {
// TODO(solenberg): Some test cases in EndToEndTest use this from a different
// thread. Re-enable once that is fixed.
// RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
// RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
Stats stats;
// Fetch available send/receive bitrates.
uint32_t send_bandwidth = 0;
@ -887,7 +903,7 @@ Call::Stats Call::GetStats() const {
void Call::SetBitrateConfig(
const webrtc::Call::Config::BitrateConfig& bitrate_config) {
TRACE_EVENT0("webrtc", "Call::SetBitrateConfig");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
RTC_DCHECK_GE(bitrate_config.min_bitrate_bps, 0);
if (bitrate_config.max_bitrate_bps != -1)
RTC_DCHECK_GT(bitrate_config.max_bitrate_bps, 0);
@ -914,7 +930,7 @@ void Call::SetBitrateConfig(
}
void Call::SignalChannelNetworkState(MediaType media, NetworkState state) {
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
switch (media) {
case MediaType::AUDIO:
audio_network_state_ = state;
@ -976,7 +992,7 @@ void Call::OnTransportOverheadChanged(MediaType media,
// TODO(honghaiz): Add tests for this method.
void Call::OnNetworkRouteChanged(const std::string& transport_name,
const rtc::NetworkRoute& network_route) {
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
// Check if the network route is connected.
if (!network_route.connected) {
LOG(LS_INFO) << "Transport " << transport_name << " is disconnected";
@ -1013,7 +1029,7 @@ void Call::OnNetworkRouteChanged(const std::string& transport_name,
}
void Call::UpdateAggregateNetworkState() {
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
bool have_audio = false;
bool have_video = false;

View File

@ -13,13 +13,16 @@
#include <memory>
#include <utility>
#include "webrtc/api/test/mock_audio_mixer.h"
#include "webrtc/base/ptr_util.h"
#include "webrtc/call/audio_state.h"
#include "webrtc/call/call.h"
#include "webrtc/call/fake_rtp_transport_controller_send.h"
#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
#include "webrtc/modules/audio_device/include/mock_audio_device.h"
#include "webrtc/modules/audio_mixer/audio_mixer_impl.h"
#include "webrtc/modules/congestion_controller/include/mock/mock_send_side_congestion_controller.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/test/gtest.h"
#include "webrtc/test/mock_audio_decoder_factory.h"
#include "webrtc/test/mock_transport.h"
@ -134,6 +137,7 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_RecvFirst) {
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory(
new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>);
CallHelper call(decoder_factory);
::testing::NiceMock<MockRtpRtcp> mock_rtp_rtcp;
constexpr int kRecvChannelId = 101;
@ -151,6 +155,8 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_RecvFirst) {
[](const std::map<int, SdpAudioFormat>& codecs) {
EXPECT_THAT(codecs, testing::IsEmpty());
}));
EXPECT_CALL(*channel_proxy, GetRtpRtcp(testing::_, testing::_))
.WillRepeatedly(testing::SetArgPointee<0>(&mock_rtp_rtcp));
// If being called for the send channel, save a pointer to the channel
// proxy for later.
if (channel_id == kRecvChannelId) {
@ -186,6 +192,7 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_SendFirst) {
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory(
new rtc::RefCountedObject<webrtc::MockAudioDecoderFactory>);
CallHelper call(decoder_factory);
::testing::NiceMock<MockRtpRtcp> mock_rtp_rtcp;
constexpr int kRecvChannelId = 101;
@ -203,6 +210,8 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_SendFirst) {
[](const std::map<int, SdpAudioFormat>& codecs) {
EXPECT_THAT(codecs, testing::IsEmpty());
}));
EXPECT_CALL(*channel_proxy, GetRtpRtcp(testing::_, testing::_))
.WillRepeatedly(testing::SetArgPointee<0>(&mock_rtp_rtcp));
// If being called for the send channel, save a pointer to the channel
// proxy for later.
if (channel_id == kRecvChannelId) {
@ -416,4 +425,69 @@ TEST(CallBitrateTest,
call->SetBitrateConfig(bitrate_config);
}
TEST(CallTest, RecreatingAudioStreamWithSameSsrcReusesRtpState) {
constexpr uint32_t kSSRC = 12345;
testing::NiceMock<test::MockAudioDeviceModule> mock_adm;
// Reply with a 10ms timer every time TimeUntilNextProcess is called to
// avoid entering a tight loop on the process thread.
EXPECT_CALL(mock_adm, TimeUntilNextProcess())
.WillRepeatedly(testing::Return(10));
rtc::scoped_refptr<test::MockAudioMixer> mock_mixer(
new rtc::RefCountedObject<test::MockAudioMixer>);
// There's similar functionality in cricket::VoEWrapper but it's not reachable
// from here. Since we're working on removing VoE interfaces, I doubt it's
// worth making VoEWrapper more easily available.
struct ScopedVoiceEngine {
ScopedVoiceEngine()
: voe(VoiceEngine::Create()),
base(VoEBase::GetInterface(voe)) {}
~ScopedVoiceEngine() {
base->Release();
EXPECT_TRUE(VoiceEngine::Delete(voe));
}
VoiceEngine* voe;
VoEBase* base;
};
ScopedVoiceEngine voice_engine;
voice_engine.base->Init(&mock_adm);
AudioState::Config audio_state_config;
audio_state_config.voice_engine = voice_engine.voe;
audio_state_config.audio_mixer = mock_mixer;
auto audio_state = AudioState::Create(audio_state_config);
RtcEventLogNullImpl event_log;
Call::Config call_config(&event_log);
call_config.audio_state = audio_state;
std::unique_ptr<Call> call(Call::Create(call_config));
auto create_stream_and_get_rtp_state = [&](uint32_t ssrc) {
AudioSendStream::Config config(nullptr);
config.rtp.ssrc = ssrc;
config.voe_channel_id = voice_engine.base->CreateChannel();
AudioSendStream* stream = call->CreateAudioSendStream(config);
VoiceEngineImpl* voe_impl = static_cast<VoiceEngineImpl*>(voice_engine.voe);
auto channel_proxy = voe_impl->GetChannelProxy(config.voe_channel_id);
RtpRtcp* rtp_rtcp = nullptr;
RtpReceiver* rtp_receiver = nullptr; // Unused but required for call.
channel_proxy->GetRtpRtcp(&rtp_rtcp, &rtp_receiver);
const RtpState rtp_state = rtp_rtcp->GetRtpState();
call->DestroyAudioSendStream(stream);
voice_engine.base->DeleteChannel(config.voe_channel_id);
return rtp_state;
};
const RtpState rtp_state1 = create_stream_and_get_rtp_state(kSSRC);
const RtpState rtp_state2 = create_stream_and_get_rtp_state(kSSRC);
EXPECT_EQ(rtp_state1.sequence_number, rtp_state2.sequence_number);
EXPECT_EQ(rtp_state1.start_timestamp, rtp_state2.start_timestamp);
EXPECT_EQ(rtp_state1.timestamp, rtp_state2.timestamp);
EXPECT_EQ(rtp_state1.capture_time_ms, rtp_state2.capture_time_ms);
EXPECT_EQ(rtp_state1.last_timestamp_time_ms,
rtp_state2.last_timestamp_time_ms);
EXPECT_EQ(rtp_state1.media_has_been_sent, rtp_state2.media_has_been_sent);
}
} // namespace webrtc

View File

@ -16,6 +16,7 @@
#include "webrtc/modules/audio_device/include/mock_audio_device.h"
#include "webrtc/modules/audio_device/include/mock_audio_transport.h"
#include "webrtc/modules/audio_processing/include/mock_audio_processing.h"
#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/mock_voe_channel_proxy.h"
#include "webrtc/voice_engine/voice_engine_impl.h"
@ -57,6 +58,9 @@ class MockVoiceEngine : public VoiceEngineImpl {
[](const std::map<int, SdpAudioFormat>& codecs) {
EXPECT_THAT(codecs, testing::IsEmpty());
}));
EXPECT_CALL(*proxy, GetRtpRtcp(testing::_, testing::_))
.WillRepeatedly(
testing::SetArgPointee<0>(GetMockRtpRtcp(channel_id)));
return proxy;
}));
@ -74,6 +78,15 @@ class MockVoiceEngine : public VoiceEngineImpl {
// trigger an assertion.
--_ref_count;
}
// These need to be the same each call to channel_id and must not leak.
MockRtpRtcp* GetMockRtpRtcp(int channel_id) {
if (mock_rtp_rtcps_.find(channel_id) == mock_rtp_rtcps_.end()) {
mock_rtp_rtcps_[channel_id].reset(new ::testing::NiceMock<MockRtpRtcp>);
}
return mock_rtp_rtcps_[channel_id].get();
}
// Allows injecting a ChannelProxy factory.
MOCK_METHOD1(ChannelProxyFactory, voe::ChannelProxy*(int channel_id));
@ -241,6 +254,8 @@ class MockVoiceEngine : public VoiceEngineImpl {
// voe::Channel does.
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
std::map<int, std::unique_ptr<MockRtpRtcp>> mock_rtp_rtcps_;
MockAudioDeviceModule mock_audio_device_;
MockAudioProcessing mock_audio_processing_;
MockAudioTransport mock_audio_transport_;