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}
diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc
index 3d636c2..1a5f28e 100644
--- a/webrtc/audio/audio_send_stream.cc
+++ b/webrtc/audio/audio_send_stream.cc
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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::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";
}
diff --git a/webrtc/audio/audio_send_stream.h b/webrtc/audio/audio_send_stream.h
index 065fee7..881c68e 100644
--- a/webrtc/audio/audio_send_stream.h
+++ b/webrtc/audio/audio_send_stream.h
@@ -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 @@
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 @@
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 @@
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
diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc
index 69ac2e4..e6acf92 100644
--- a/webrtc/audio/audio_send_stream_unittest.cc
+++ b/webrtc/audio/audio_send_stream_unittest.cc
@@ -354,7 +354,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
}
diff --git a/webrtc/call/BUILD.gn b/webrtc/call/BUILD.gn
index 7728104..a6afe30 100644
--- a/webrtc/call/BUILD.gn
+++ b/webrtc/call/BUILD.gn
@@ -93,6 +93,7 @@
]
deps = [
":call",
+ "../api:mock_audio_mixer",
"../base:rtc_base_approved",
"../logging:rtc_event_log_api",
"../modules/audio_device:mock_audio_device",
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc
index 87e41b0..a1aa1de 100644
--- a/webrtc/call/call.cc
+++ b/webrtc/call/call.cc
@@ -305,7 +305,12 @@
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 @@
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() {
- 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 @@
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 @@
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 @@
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 @@
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::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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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::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 @@
// 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::UpdateAggregateNetworkState() {
- RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
+ RTC_DCHECK_RUN_ON(&configuration_thread_checker_);
bool have_audio = false;
bool have_video = false;
diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc
index 9576beb..06ee200 100644
--- a/webrtc/call/call_unittest.cc
+++ b/webrtc/call/call_unittest.cc
@@ -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 @@
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 @@
[](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 @@
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 @@
[](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 @@
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
diff --git a/webrtc/test/mock_voice_engine.h b/webrtc/test/mock_voice_engine.h
index 6b1f9cf..7655d3b 100644
--- a/webrtc/test/mock_voice_engine.h
+++ b/webrtc/test/mock_voice_engine.h
@@ -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 @@
[](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 @@
// 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 @@
// 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_;