Make the audio channel communicate network state changes to the call.
This change enables voice-only calls to keep track of the network state. This is only a partial fix - the last modality to change state controls the state for the entire call, so a call with a failed video transport will also stop sending audio packets. Handling this condition correctly would require the call to keep track of network state for each media type separately, and take care of conditions such as a failed video channel getting removed, while a functioning audio channel remains. BUG=webrtc:5307 Review URL: https://codereview.webrtc.org/1757683002 Cr-Commit-Position: refs/heads/master@{#12093}
This commit is contained in:
parent
01bcbd0df6
commit
7a43d253f9
@ -133,7 +133,12 @@ class Call {
|
||||
// implemented.
|
||||
virtual void SetBitrateConfig(
|
||||
const Config::BitrateConfig& bitrate_config) = 0;
|
||||
virtual void SignalNetworkState(NetworkState state) = 0;
|
||||
|
||||
// TODO(skvlad): When the unbundled case with multiple streams for the same
|
||||
// media type going over different networks is supported, track the state
|
||||
// for each stream separately. Right now it's global per media type.
|
||||
virtual void SignalChannelNetworkState(MediaType media,
|
||||
NetworkState state) = 0;
|
||||
|
||||
virtual void OnSentPacket(const rtc::SentPacket& sent_packet) = 0;
|
||||
|
||||
|
||||
@ -86,7 +86,8 @@ class Call : public webrtc::Call, public PacketReceiver,
|
||||
|
||||
void SetBitrateConfig(
|
||||
const webrtc::Call::Config::BitrateConfig& bitrate_config) override;
|
||||
void SignalNetworkState(NetworkState state) override;
|
||||
|
||||
void SignalChannelNetworkState(MediaType media, NetworkState state) override;
|
||||
|
||||
void OnSentPacket(const rtc::SentPacket& sent_packet) override;
|
||||
|
||||
@ -116,6 +117,7 @@ class Call : public webrtc::Call, public PacketReceiver,
|
||||
|
||||
void UpdateSendHistograms() EXCLUSIVE_LOCKS_REQUIRED(&bitrate_crit_);
|
||||
void UpdateReceiveHistograms();
|
||||
void UpdateAggregateNetworkState();
|
||||
|
||||
Clock* const clock_;
|
||||
|
||||
@ -127,7 +129,8 @@ class Call : public webrtc::Call, public PacketReceiver,
|
||||
Call::Config config_;
|
||||
rtc::ThreadChecker configuration_thread_checker_;
|
||||
|
||||
bool network_enabled_;
|
||||
NetworkState audio_network_state_;
|
||||
NetworkState video_network_state_;
|
||||
|
||||
std::unique_ptr<RWLockWrapper> receive_crit_;
|
||||
// Audio and Video receive streams are owned by the client that creates them.
|
||||
@ -189,7 +192,8 @@ Call::Call(const Call::Config& config)
|
||||
call_stats_(new CallStats(clock_)),
|
||||
bitrate_allocator_(new BitrateAllocator()),
|
||||
config_(config),
|
||||
network_enabled_(true),
|
||||
audio_network_state_(kNetworkUp),
|
||||
video_network_state_(kNetworkUp),
|
||||
receive_crit_(RWLockWrapper::CreateRWLock()),
|
||||
send_crit_(RWLockWrapper::CreateRWLock()),
|
||||
received_video_bytes_(0),
|
||||
@ -317,14 +321,14 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream(
|
||||
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
|
||||
AudioSendStream* send_stream = new AudioSendStream(
|
||||
config, config_.audio_state, congestion_controller_.get());
|
||||
if (!network_enabled_)
|
||||
send_stream->SignalNetworkState(kNetworkDown);
|
||||
{
|
||||
WriteLockScoped write_lock(*send_crit_);
|
||||
RTC_DCHECK(audio_send_ssrcs_.find(config.rtp.ssrc) ==
|
||||
audio_send_ssrcs_.end());
|
||||
audio_send_ssrcs_[config.rtp.ssrc] = send_stream;
|
||||
}
|
||||
send_stream->SignalNetworkState(audio_network_state_);
|
||||
UpdateAggregateNetworkState();
|
||||
return send_stream;
|
||||
}
|
||||
|
||||
@ -343,6 +347,7 @@ void Call::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) {
|
||||
audio_send_stream->config().rtp.ssrc);
|
||||
RTC_DCHECK(num_deleted == 1);
|
||||
}
|
||||
UpdateAggregateNetworkState();
|
||||
delete audio_send_stream;
|
||||
}
|
||||
|
||||
@ -359,6 +364,8 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream(
|
||||
audio_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
||||
ConfigureSync(config.sync_group);
|
||||
}
|
||||
receive_stream->SignalNetworkState(audio_network_state_);
|
||||
UpdateAggregateNetworkState();
|
||||
return receive_stream;
|
||||
}
|
||||
|
||||
@ -382,6 +389,7 @@ void Call::DestroyAudioReceiveStream(
|
||||
ConfigureSync(sync_group);
|
||||
}
|
||||
}
|
||||
UpdateAggregateNetworkState();
|
||||
delete audio_receive_stream;
|
||||
}
|
||||
|
||||
@ -397,20 +405,18 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream(
|
||||
num_cpu_cores_, module_process_thread_.get(), call_stats_.get(),
|
||||
congestion_controller_.get(), bitrate_allocator_.get(), &remb_, config,
|
||||
encoder_config, suspended_video_send_ssrcs_);
|
||||
|
||||
if (!network_enabled_)
|
||||
send_stream->SignalNetworkState(kNetworkDown);
|
||||
|
||||
WriteLockScoped write_lock(*send_crit_);
|
||||
for (uint32_t ssrc : config.rtp.ssrcs) {
|
||||
RTC_DCHECK(video_send_ssrcs_.find(ssrc) == video_send_ssrcs_.end());
|
||||
video_send_ssrcs_[ssrc] = send_stream;
|
||||
{
|
||||
WriteLockScoped write_lock(*send_crit_);
|
||||
for (uint32_t ssrc : config.rtp.ssrcs) {
|
||||
RTC_DCHECK(video_send_ssrcs_.find(ssrc) == video_send_ssrcs_.end());
|
||||
video_send_ssrcs_[ssrc] = send_stream;
|
||||
}
|
||||
video_send_streams_.insert(send_stream);
|
||||
}
|
||||
video_send_streams_.insert(send_stream);
|
||||
|
||||
send_stream->SignalNetworkState(video_network_state_);
|
||||
UpdateAggregateNetworkState();
|
||||
if (event_log_)
|
||||
event_log_->LogVideoSendStreamConfig(config);
|
||||
|
||||
return send_stream;
|
||||
}
|
||||
|
||||
@ -445,6 +451,7 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
|
||||
suspended_video_send_ssrcs_[it->first] = it->second;
|
||||
}
|
||||
|
||||
UpdateAggregateNetworkState();
|
||||
delete send_stream_impl;
|
||||
}
|
||||
|
||||
@ -455,26 +462,24 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
|
||||
VideoReceiveStream* receive_stream = new VideoReceiveStream(
|
||||
num_cpu_cores_, congestion_controller_.get(), config, voice_engine(),
|
||||
module_process_thread_.get(), call_stats_.get(), &remb_);
|
||||
{
|
||||
WriteLockScoped write_lock(*receive_crit_);
|
||||
RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) ==
|
||||
video_receive_ssrcs_.end());
|
||||
video_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
||||
// TODO(pbos): Configure different RTX payloads per receive payload.
|
||||
VideoReceiveStream::Config::Rtp::RtxMap::const_iterator it =
|
||||
config.rtp.rtx.begin();
|
||||
if (it != config.rtp.rtx.end())
|
||||
video_receive_ssrcs_[it->second.ssrc] = receive_stream;
|
||||
video_receive_streams_.insert(receive_stream);
|
||||
|
||||
WriteLockScoped write_lock(*receive_crit_);
|
||||
RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) ==
|
||||
video_receive_ssrcs_.end());
|
||||
video_receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
||||
// TODO(pbos): Configure different RTX payloads per receive payload.
|
||||
VideoReceiveStream::Config::Rtp::RtxMap::const_iterator it =
|
||||
config.rtp.rtx.begin();
|
||||
if (it != config.rtp.rtx.end())
|
||||
video_receive_ssrcs_[it->second.ssrc] = receive_stream;
|
||||
video_receive_streams_.insert(receive_stream);
|
||||
|
||||
ConfigureSync(config.sync_group);
|
||||
|
||||
if (!network_enabled_)
|
||||
receive_stream->SignalNetworkState(kNetworkDown);
|
||||
|
||||
ConfigureSync(config.sync_group);
|
||||
}
|
||||
receive_stream->SignalNetworkState(video_network_state_);
|
||||
UpdateAggregateNetworkState();
|
||||
if (event_log_)
|
||||
event_log_->LogVideoReceiveStreamConfig(config);
|
||||
|
||||
return receive_stream;
|
||||
}
|
||||
|
||||
@ -503,6 +508,7 @@ void Call::DestroyVideoReceiveStream(
|
||||
RTC_CHECK(receive_stream_impl != nullptr);
|
||||
ConfigureSync(receive_stream_impl->config().sync_group);
|
||||
}
|
||||
UpdateAggregateNetworkState();
|
||||
delete receive_stream_impl;
|
||||
}
|
||||
|
||||
@ -549,27 +555,74 @@ void Call::SetBitrateConfig(
|
||||
bitrate_config.max_bitrate_bps);
|
||||
}
|
||||
|
||||
void Call::SignalNetworkState(NetworkState state) {
|
||||
void Call::SignalChannelNetworkState(MediaType media, NetworkState state) {
|
||||
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
|
||||
network_enabled_ = state == kNetworkUp;
|
||||
congestion_controller_->SignalNetworkState(state);
|
||||
switch (media) {
|
||||
case MediaType::AUDIO:
|
||||
audio_network_state_ = state;
|
||||
break;
|
||||
case MediaType::VIDEO:
|
||||
video_network_state_ = state;
|
||||
break;
|
||||
case MediaType::ANY:
|
||||
case MediaType::DATA:
|
||||
RTC_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateAggregateNetworkState();
|
||||
{
|
||||
ReadLockScoped write_lock(*send_crit_);
|
||||
ReadLockScoped read_lock(*send_crit_);
|
||||
for (auto& kv : audio_send_ssrcs_) {
|
||||
kv.second->SignalNetworkState(state);
|
||||
kv.second->SignalNetworkState(audio_network_state_);
|
||||
}
|
||||
for (auto& kv : video_send_ssrcs_) {
|
||||
kv.second->SignalNetworkState(state);
|
||||
kv.second->SignalNetworkState(video_network_state_);
|
||||
}
|
||||
}
|
||||
{
|
||||
ReadLockScoped write_lock(*receive_crit_);
|
||||
ReadLockScoped read_lock(*receive_crit_);
|
||||
for (auto& kv : audio_receive_ssrcs_) {
|
||||
kv.second->SignalNetworkState(audio_network_state_);
|
||||
}
|
||||
for (auto& kv : video_receive_ssrcs_) {
|
||||
kv.second->SignalNetworkState(state);
|
||||
kv.second->SignalNetworkState(video_network_state_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Call::UpdateAggregateNetworkState() {
|
||||
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
|
||||
|
||||
bool have_audio = false;
|
||||
bool have_video = false;
|
||||
{
|
||||
ReadLockScoped read_lock(*send_crit_);
|
||||
if (audio_send_ssrcs_.size() > 0)
|
||||
have_audio = true;
|
||||
if (video_send_ssrcs_.size() > 0)
|
||||
have_video = true;
|
||||
}
|
||||
{
|
||||
ReadLockScoped read_lock(*receive_crit_);
|
||||
if (audio_receive_ssrcs_.size() > 0)
|
||||
have_audio = true;
|
||||
if (video_receive_ssrcs_.size() > 0)
|
||||
have_video = true;
|
||||
}
|
||||
|
||||
NetworkState aggregate_state = kNetworkDown;
|
||||
if ((have_video && video_network_state_ == kNetworkUp) ||
|
||||
(have_audio && audio_network_state_ == kNetworkUp)) {
|
||||
aggregate_state = kNetworkUp;
|
||||
}
|
||||
|
||||
LOG(LS_INFO) << "UpdateAggregateNetworkState: aggregate_state="
|
||||
<< (aggregate_state == kNetworkUp ? "up" : "down");
|
||||
|
||||
congestion_controller_->SignalNetworkState(aggregate_state);
|
||||
}
|
||||
|
||||
void Call::OnSentPacket(const rtc::SentPacket& sent_packet) {
|
||||
if (first_packet_sent_ms_ == -1)
|
||||
first_packet_sent_ms_ = clock_->TimeInMilliseconds();
|
||||
|
||||
@ -233,7 +233,8 @@ void FakeVideoReceiveStream::SetStats(
|
||||
|
||||
FakeCall::FakeCall(const webrtc::Call::Config& config)
|
||||
: config_(config),
|
||||
network_state_(webrtc::kNetworkUp),
|
||||
audio_network_state_(webrtc::kNetworkUp),
|
||||
video_network_state_(webrtc::kNetworkUp),
|
||||
num_created_send_streams_(0),
|
||||
num_created_receive_streams_(0) {}
|
||||
|
||||
@ -282,8 +283,22 @@ const FakeAudioReceiveStream* FakeCall::GetAudioReceiveStream(uint32_t ssrc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
webrtc::NetworkState FakeCall::GetNetworkState() const {
|
||||
return network_state_;
|
||||
webrtc::NetworkState FakeCall::GetNetworkState(webrtc::MediaType media) const {
|
||||
switch (media) {
|
||||
case webrtc::MediaType::AUDIO:
|
||||
return audio_network_state_;
|
||||
case webrtc::MediaType::VIDEO:
|
||||
return video_network_state_;
|
||||
case webrtc::MediaType::DATA:
|
||||
case webrtc::MediaType::ANY:
|
||||
ADD_FAILURE() << "GetNetworkState called with unknown parameter.";
|
||||
return webrtc::kNetworkDown;
|
||||
}
|
||||
// Even though all the values for the enum class are listed above,the compiler
|
||||
// will emit a warning as the method may be called with a value outside of the
|
||||
// valid enum range, unless this case is also handled.
|
||||
ADD_FAILURE() << "GetNetworkState called with unknown parameter.";
|
||||
return webrtc::kNetworkDown;
|
||||
}
|
||||
|
||||
webrtc::AudioSendStream* FakeCall::CreateAudioSendStream(
|
||||
@ -299,7 +314,7 @@ void FakeCall::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) {
|
||||
audio_send_streams_.end(),
|
||||
static_cast<FakeAudioSendStream*>(send_stream));
|
||||
if (it == audio_send_streams_.end()) {
|
||||
ADD_FAILURE() << "DestroyAudioSendStream called with unknown paramter.";
|
||||
ADD_FAILURE() << "DestroyAudioSendStream called with unknown parameter.";
|
||||
} else {
|
||||
delete *it;
|
||||
audio_send_streams_.erase(it);
|
||||
@ -319,7 +334,7 @@ void FakeCall::DestroyAudioReceiveStream(
|
||||
audio_receive_streams_.end(),
|
||||
static_cast<FakeAudioReceiveStream*>(receive_stream));
|
||||
if (it == audio_receive_streams_.end()) {
|
||||
ADD_FAILURE() << "DestroyAudioReceiveStream called with unknown paramter.";
|
||||
ADD_FAILURE() << "DestroyAudioReceiveStream called with unknown parameter.";
|
||||
} else {
|
||||
delete *it;
|
||||
audio_receive_streams_.erase(it);
|
||||
@ -341,7 +356,7 @@ void FakeCall::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
|
||||
video_send_streams_.end(),
|
||||
static_cast<FakeVideoSendStream*>(send_stream));
|
||||
if (it == video_send_streams_.end()) {
|
||||
ADD_FAILURE() << "DestroyVideoSendStream called with unknown paramter.";
|
||||
ADD_FAILURE() << "DestroyVideoSendStream called with unknown parameter.";
|
||||
} else {
|
||||
delete *it;
|
||||
video_send_streams_.erase(it);
|
||||
@ -361,7 +376,7 @@ void FakeCall::DestroyVideoReceiveStream(
|
||||
video_receive_streams_.end(),
|
||||
static_cast<FakeVideoReceiveStream*>(receive_stream));
|
||||
if (it == video_receive_streams_.end()) {
|
||||
ADD_FAILURE() << "DestroyVideoReceiveStream called with unknown paramter.";
|
||||
ADD_FAILURE() << "DestroyVideoReceiveStream called with unknown parameter.";
|
||||
} else {
|
||||
delete *it;
|
||||
video_receive_streams_.erase(it);
|
||||
@ -422,8 +437,20 @@ void FakeCall::SetBitrateConfig(
|
||||
config_.bitrate_config = bitrate_config;
|
||||
}
|
||||
|
||||
void FakeCall::SignalNetworkState(webrtc::NetworkState state) {
|
||||
network_state_ = state;
|
||||
void FakeCall::SignalChannelNetworkState(webrtc::MediaType media,
|
||||
webrtc::NetworkState state) {
|
||||
switch (media) {
|
||||
case webrtc::MediaType::AUDIO:
|
||||
audio_network_state_ = state;
|
||||
break;
|
||||
case webrtc::MediaType::VIDEO:
|
||||
video_network_state_ = state;
|
||||
break;
|
||||
case webrtc::MediaType::DATA:
|
||||
case webrtc::MediaType::ANY:
|
||||
ADD_FAILURE()
|
||||
<< "SignalChannelNetworkState called with unknown parameter.";
|
||||
}
|
||||
}
|
||||
|
||||
void FakeCall::OnSentPacket(const rtc::SentPacket& sent_packet) {
|
||||
|
||||
@ -200,7 +200,7 @@ class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver {
|
||||
const FakeAudioReceiveStream* GetAudioReceiveStream(uint32_t ssrc);
|
||||
|
||||
rtc::SentPacket last_sent_packet() const { return last_sent_packet_; }
|
||||
webrtc::NetworkState GetNetworkState() const;
|
||||
webrtc::NetworkState GetNetworkState(webrtc::MediaType media) const;
|
||||
int GetNumCreatedSendStreams() const;
|
||||
int GetNumCreatedReceiveStreams() const;
|
||||
void SetStats(const webrtc::Call::Stats& stats);
|
||||
@ -235,11 +235,13 @@ class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver {
|
||||
|
||||
void SetBitrateConfig(
|
||||
const webrtc::Call::Config::BitrateConfig& bitrate_config) override;
|
||||
void SignalNetworkState(webrtc::NetworkState state) override;
|
||||
void SignalChannelNetworkState(webrtc::MediaType media,
|
||||
webrtc::NetworkState state) override;
|
||||
void OnSentPacket(const rtc::SentPacket& sent_packet) override;
|
||||
|
||||
webrtc::Call::Config config_;
|
||||
webrtc::NetworkState network_state_;
|
||||
webrtc::NetworkState audio_network_state_;
|
||||
webrtc::NetworkState video_network_state_;
|
||||
rtc::SentPacket last_sent_packet_;
|
||||
webrtc::Call::Stats stats_;
|
||||
std::vector<FakeVideoSendStream*> video_send_streams_;
|
||||
|
||||
@ -1421,7 +1421,9 @@ void WebRtcVideoChannel2::OnRtcpReceived(
|
||||
|
||||
void WebRtcVideoChannel2::OnReadyToSend(bool ready) {
|
||||
LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready.");
|
||||
call_->SignalNetworkState(ready ? webrtc::kNetworkUp : webrtc::kNetworkDown);
|
||||
call_->SignalChannelNetworkState(
|
||||
webrtc::MediaType::VIDEO,
|
||||
ready ? webrtc::kNetworkUp : webrtc::kNetworkDown);
|
||||
}
|
||||
|
||||
bool WebRtcVideoChannel2::MuteStream(uint32_t ssrc, bool mute) {
|
||||
|
||||
@ -2656,13 +2656,22 @@ TEST_F(WebRtcVideoChannel2Test, TestSetRecvRtcpReducedSize) {
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannel2Test, OnReadyToSendSignalsNetworkState) {
|
||||
EXPECT_EQ(webrtc::kNetworkUp, fake_call_->GetNetworkState());
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
fake_call_->GetNetworkState(webrtc::MediaType::VIDEO));
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
fake_call_->GetNetworkState(webrtc::MediaType::AUDIO));
|
||||
|
||||
channel_->OnReadyToSend(false);
|
||||
EXPECT_EQ(webrtc::kNetworkDown, fake_call_->GetNetworkState());
|
||||
EXPECT_EQ(webrtc::kNetworkDown,
|
||||
fake_call_->GetNetworkState(webrtc::MediaType::VIDEO));
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
fake_call_->GetNetworkState(webrtc::MediaType::AUDIO));
|
||||
|
||||
channel_->OnReadyToSend(true);
|
||||
EXPECT_EQ(webrtc::kNetworkUp, fake_call_->GetNetworkState());
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
fake_call_->GetNetworkState(webrtc::MediaType::VIDEO));
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
fake_call_->GetNetworkState(webrtc::MediaType::AUDIO));
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannel2Test, GetStatsReportsSentCodecName) {
|
||||
|
||||
@ -2419,6 +2419,14 @@ bool WebRtcVoiceMediaChannel::SetSendBitrateInternal(int bps) {
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcVoiceMediaChannel::OnReadyToSend(bool ready) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready.");
|
||||
call_->SignalChannelNetworkState(
|
||||
webrtc::MediaType::AUDIO,
|
||||
ready ? webrtc::kNetworkUp : webrtc::kNetworkDown);
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
|
||||
TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::GetStats");
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
|
||||
@ -183,7 +183,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
const rtc::PacketTime& packet_time) override;
|
||||
void OnRtcpReceived(rtc::CopyOnWriteBuffer* packet,
|
||||
const rtc::PacketTime& packet_time) override;
|
||||
void OnReadyToSend(bool ready) override {}
|
||||
void OnReadyToSend(bool ready) override;
|
||||
bool GetStats(VoiceMediaInfo* info) override;
|
||||
|
||||
void SetRawAudioSink(
|
||||
|
||||
@ -3193,6 +3193,29 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRawAudioSinkDefaultRecvStream) {
|
||||
EXPECT_NE(nullptr, GetRecvStream(0x01).sink());
|
||||
}
|
||||
|
||||
// Test that, just like the video channel, the voice channel communicates the
|
||||
// network state to the call.
|
||||
TEST_F(WebRtcVoiceEngineTestFake, OnReadyToSendSignalsNetworkState) {
|
||||
EXPECT_TRUE(SetupEngine());
|
||||
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
call_.GetNetworkState(webrtc::MediaType::AUDIO));
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
call_.GetNetworkState(webrtc::MediaType::VIDEO));
|
||||
|
||||
channel_->OnReadyToSend(false);
|
||||
EXPECT_EQ(webrtc::kNetworkDown,
|
||||
call_.GetNetworkState(webrtc::MediaType::AUDIO));
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
call_.GetNetworkState(webrtc::MediaType::VIDEO));
|
||||
|
||||
channel_->OnReadyToSend(true);
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
call_.GetNetworkState(webrtc::MediaType::AUDIO));
|
||||
EXPECT_EQ(webrtc::kNetworkUp,
|
||||
call_.GetNetworkState(webrtc::MediaType::VIDEO));
|
||||
}
|
||||
|
||||
// Tests that the library initializes and shuts down properly.
|
||||
TEST(WebRtcVoiceEngineTest, StartupShutdown) {
|
||||
cricket::WebRtcVoiceEngine engine;
|
||||
|
||||
@ -76,6 +76,35 @@ class EndToEndTest : public test::CallTest {
|
||||
}
|
||||
};
|
||||
|
||||
class RequiredTransport : public Transport {
|
||||
public:
|
||||
RequiredTransport(bool rtp_required, bool rtcp_required)
|
||||
: need_rtp_(rtp_required), need_rtcp_(rtcp_required) {}
|
||||
~RequiredTransport() {
|
||||
if (need_rtp_) {
|
||||
ADD_FAILURE() << "Expected RTP packet not sent.";
|
||||
}
|
||||
if (need_rtcp_) {
|
||||
ADD_FAILURE() << "Expected RTCP packet not sent.";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool SendRtp(const uint8_t* packet,
|
||||
size_t length,
|
||||
const PacketOptions& options) override {
|
||||
need_rtp_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SendRtcp(const uint8_t* packet, size_t length) override {
|
||||
need_rtcp_ = false;
|
||||
return true;
|
||||
}
|
||||
bool need_rtp_;
|
||||
bool need_rtcp_;
|
||||
};
|
||||
|
||||
void DecodesRetransmittedFrame(bool enable_rtx, bool enable_red);
|
||||
void ReceivesPliAndRecovers(int rtp_history_ms);
|
||||
void RespectsRtcpMode(RtcpMode rtcp_mode);
|
||||
@ -83,6 +112,13 @@ class EndToEndTest : public test::CallTest {
|
||||
void TestSendsSetSsrcs(size_t num_ssrcs, bool send_single_ssrc_first);
|
||||
void TestRtpStatePreservation(bool use_rtx);
|
||||
void VerifyHistogramStats(bool use_rtx, bool use_red, bool screenshare);
|
||||
void VerifyNewVideoSendStreamsRespectNetworkState(
|
||||
MediaType network_to_bring_down,
|
||||
VideoEncoder* encoder,
|
||||
Transport* transport);
|
||||
void VerifyNewVideoReceiveStreamsRespectNetworkState(
|
||||
MediaType network_to_bring_down,
|
||||
Transport* transport);
|
||||
};
|
||||
|
||||
TEST_F(EndToEndTest, ReceiverCanBeStartedTwice) {
|
||||
@ -3193,8 +3229,16 @@ TEST_F(EndToEndTest, RespectsNetworkState) {
|
||||
// Wait for packets from both sender/receiver.
|
||||
WaitForPacketsOrSilence(false, false);
|
||||
|
||||
// Sender-side network down for audio; there should be no effect on video
|
||||
sender_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkDown);
|
||||
WaitForPacketsOrSilence(false, false);
|
||||
|
||||
// Receiver-side network down for audio; no change expected
|
||||
receiver_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkDown);
|
||||
WaitForPacketsOrSilence(false, false);
|
||||
|
||||
// Sender-side network down.
|
||||
sender_call_->SignalNetworkState(kNetworkDown);
|
||||
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkDown);
|
||||
{
|
||||
rtc::CritScope lock(&test_crit_);
|
||||
// After network goes down we shouldn't be encoding more frames.
|
||||
@ -3204,7 +3248,13 @@ TEST_F(EndToEndTest, RespectsNetworkState) {
|
||||
WaitForPacketsOrSilence(true, false);
|
||||
|
||||
// Receiver-side network down.
|
||||
receiver_call_->SignalNetworkState(kNetworkDown);
|
||||
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkDown);
|
||||
WaitForPacketsOrSilence(true, true);
|
||||
|
||||
// Network up for audio for both sides; video is still not expected to
|
||||
// start
|
||||
sender_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp);
|
||||
receiver_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp);
|
||||
WaitForPacketsOrSilence(true, true);
|
||||
|
||||
// Network back up again for both.
|
||||
@ -3214,9 +3264,13 @@ TEST_F(EndToEndTest, RespectsNetworkState) {
|
||||
// network.
|
||||
sender_state_ = kNetworkUp;
|
||||
}
|
||||
sender_call_->SignalNetworkState(kNetworkUp);
|
||||
receiver_call_->SignalNetworkState(kNetworkUp);
|
||||
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
||||
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
|
||||
WaitForPacketsOrSilence(false, false);
|
||||
|
||||
// TODO(skvlad): add tests to verify that the audio streams are stopped
|
||||
// when the network goes down for audio once the workaround in
|
||||
// paced_sender.cc is removed.
|
||||
}
|
||||
|
||||
int32_t Encode(const VideoFrame& input_image,
|
||||
@ -3267,7 +3321,7 @@ TEST_F(EndToEndTest, RespectsNetworkState) {
|
||||
sender_done = true;
|
||||
}
|
||||
} else {
|
||||
if (sender_rtp_ > initial_sender_rtp)
|
||||
if (sender_rtp_ > initial_sender_rtp + kNumAcceptedDowntimeRtp)
|
||||
sender_done = true;
|
||||
}
|
||||
if (receiver_down) {
|
||||
@ -3279,7 +3333,7 @@ TEST_F(EndToEndTest, RespectsNetworkState) {
|
||||
receiver_done = true;
|
||||
}
|
||||
} else {
|
||||
if (receiver_rtcp_ > initial_receiver_rtcp)
|
||||
if (receiver_rtcp_ > initial_receiver_rtcp + kNumAcceptedDowntimeRtcp)
|
||||
receiver_done = true;
|
||||
}
|
||||
}
|
||||
@ -3338,26 +3392,15 @@ TEST_F(EndToEndTest, CallReportsRttForSender) {
|
||||
DestroyStreams();
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewSendStreamsRespectNetworkDown) {
|
||||
class UnusedEncoder : public test::FakeEncoder {
|
||||
public:
|
||||
UnusedEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
|
||||
int32_t Encode(const VideoFrame& input_image,
|
||||
const CodecSpecificInfo* codec_specific_info,
|
||||
const std::vector<FrameType>* frame_types) override {
|
||||
ADD_FAILURE() << "Unexpected frame encode.";
|
||||
return test::FakeEncoder::Encode(
|
||||
input_image, codec_specific_info, frame_types);
|
||||
}
|
||||
};
|
||||
|
||||
void EndToEndTest::VerifyNewVideoSendStreamsRespectNetworkState(
|
||||
MediaType network_to_bring_down,
|
||||
VideoEncoder* encoder,
|
||||
Transport* transport) {
|
||||
CreateSenderCall(Call::Config());
|
||||
sender_call_->SignalNetworkState(kNetworkDown);
|
||||
sender_call_->SignalChannelNetworkState(network_to_bring_down, kNetworkDown);
|
||||
|
||||
UnusedTransport transport;
|
||||
CreateSendConfig(1, 0, &transport);
|
||||
UnusedEncoder unused_encoder;
|
||||
video_send_config_.encoder_settings.encoder = &unused_encoder;
|
||||
CreateSendConfig(1, 0, transport);
|
||||
video_send_config_.encoder_settings.encoder = encoder;
|
||||
CreateVideoStreams();
|
||||
CreateFrameGeneratorCapturer();
|
||||
|
||||
@ -3368,15 +3411,17 @@ TEST_F(EndToEndTest, NewSendStreamsRespectNetworkDown) {
|
||||
DestroyStreams();
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewReceiveStreamsRespectNetworkDown) {
|
||||
void EndToEndTest::VerifyNewVideoReceiveStreamsRespectNetworkState(
|
||||
MediaType network_to_bring_down,
|
||||
Transport* transport) {
|
||||
CreateCalls(Call::Config(), Call::Config());
|
||||
receiver_call_->SignalNetworkState(kNetworkDown);
|
||||
receiver_call_->SignalChannelNetworkState(network_to_bring_down,
|
||||
kNetworkDown);
|
||||
|
||||
test::DirectTransport sender_transport(sender_call_.get());
|
||||
sender_transport.SetReceiver(receiver_call_->Receiver());
|
||||
CreateSendConfig(1, 0, &sender_transport);
|
||||
UnusedTransport transport;
|
||||
CreateMatchingReceiveConfigs(&transport);
|
||||
CreateMatchingReceiveConfigs(transport);
|
||||
CreateVideoStreams();
|
||||
CreateFrameGeneratorCapturer();
|
||||
|
||||
@ -3389,6 +3434,63 @@ TEST_F(EndToEndTest, NewReceiveStreamsRespectNetworkDown) {
|
||||
DestroyStreams();
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewVideoSendStreamsRespectVideoNetworkDown) {
|
||||
class UnusedEncoder : public test::FakeEncoder {
|
||||
public:
|
||||
UnusedEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
|
||||
int32_t Encode(const VideoFrame& input_image,
|
||||
const CodecSpecificInfo* codec_specific_info,
|
||||
const std::vector<FrameType>* frame_types) override {
|
||||
ADD_FAILURE() << "Unexpected frame encode.";
|
||||
return test::FakeEncoder::Encode(input_image, codec_specific_info,
|
||||
frame_types);
|
||||
}
|
||||
};
|
||||
|
||||
UnusedEncoder unused_encoder;
|
||||
UnusedTransport unused_transport;
|
||||
VerifyNewVideoSendStreamsRespectNetworkState(
|
||||
MediaType::VIDEO, &unused_encoder, &unused_transport);
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewVideoSendStreamsIgnoreAudioNetworkDown) {
|
||||
class RequiredEncoder : public test::FakeEncoder {
|
||||
public:
|
||||
RequiredEncoder()
|
||||
: FakeEncoder(Clock::GetRealTimeClock()), encoded_frame_(false) {}
|
||||
~RequiredEncoder() {
|
||||
if (!encoded_frame_) {
|
||||
ADD_FAILURE() << "Didn't encode an expected frame";
|
||||
}
|
||||
}
|
||||
int32_t Encode(const VideoFrame& input_image,
|
||||
const CodecSpecificInfo* codec_specific_info,
|
||||
const std::vector<FrameType>* frame_types) override {
|
||||
encoded_frame_ = true;
|
||||
return test::FakeEncoder::Encode(input_image, codec_specific_info,
|
||||
frame_types);
|
||||
}
|
||||
|
||||
private:
|
||||
bool encoded_frame_;
|
||||
};
|
||||
|
||||
RequiredTransport required_transport(true /*rtp*/, false /*rtcp*/);
|
||||
RequiredEncoder required_encoder;
|
||||
VerifyNewVideoSendStreamsRespectNetworkState(
|
||||
MediaType::AUDIO, &required_encoder, &required_transport);
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewVideoReceiveStreamsRespectVideoNetworkDown) {
|
||||
UnusedTransport transport;
|
||||
VerifyNewVideoReceiveStreamsRespectNetworkState(MediaType::VIDEO, &transport);
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewVideoReceiveStreamsIgnoreAudioNetworkDown) {
|
||||
RequiredTransport transport(false /*rtp*/, true /*rtcp*/);
|
||||
VerifyNewVideoReceiveStreamsRespectNetworkState(MediaType::AUDIO, &transport);
|
||||
}
|
||||
|
||||
void VerifyEmptyNackConfig(const NackConfig& config) {
|
||||
EXPECT_EQ(0, config.rtp_history_ms)
|
||||
<< "Enabling NACK requires rtcp-fb: nack negotiation.";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user