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:
@ -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";
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
|
Reference in New Issue
Block a user