diff --git a/audio/audio_state.cc b/audio/audio_state.cc index 1ab023df37..2b4dcaa56c 100644 --- a/audio/audio_state.cc +++ b/audio/audio_state.cc @@ -184,9 +184,10 @@ void AudioState::OnMuteStreamChanged() { if (!adm->Recording() && adm->InitRecording() == 0) { adm->StartRecording(); } - } else { - adm->StopRecording(); } + // Do not stop recording when all send streams are muted. On iOS, tearing + // down input recreates the audio graph as output-only and changes playout + // loudness; explicit SetRecording(false) and stream removal still stop input. } void AudioState::UpdateAudioTransportWithSendingStreams() { diff --git a/audio/audio_state_unittest.cc b/audio/audio_state_unittest.cc index 7b6f9f5fdd..f9b4f5024d 100644 --- a/audio/audio_state_unittest.cc +++ b/audio/audio_state_unittest.cc @@ -52,6 +52,7 @@ using ::testing::InSequence; using ::testing::Matcher; using ::testing::NiceMock; using ::testing::NotNull; +using ::testing::Return; using ::testing::StrictMock; using ::testing::Values; @@ -449,6 +450,29 @@ TEST_P(AudioStateTest, AlwaysCallInitRecordingBeforeStartRecording) { audio_state->RemoveSendingStream(&stream); } +TEST_P(AudioStateTest, MuteStreamChangeDoesNotStopRecording) { + ConfigHelper helper(GetParam()); + scoped_refptr audio_state( + make_ref_counted(helper.config())); + + auto* adm = reinterpret_cast( + helper.config().audio_device_module.get()); + + MockAudioSendStream stream; + EXPECT_CALL(*adm, InitRecording()); + EXPECT_CALL(*adm, StartRecording()); + audio_state->AddSendingStream(&stream, kSampleRate, kNumberOfChannels); + + EXPECT_CALL(stream, GetMuted()).WillRepeatedly(Return(true)); + EXPECT_CALL(*adm, StopRecording()).Times(0); + audio_state->OnMuteStreamChanged(); + + testing::Mock::VerifyAndClearExpectations(&stream); + testing::Mock::VerifyAndClearExpectations(adm); + EXPECT_CALL(*adm, StopRecording()); + audio_state->RemoveSendingStream(&stream); +} + // The recording can also be initialized by WebRtcVoiceSendChannel // options_.init_recording_on_send. Make sure StopRecording is still // being called in this scenario.