Add an option to avoid early initialization of audio capture

This can cause issues on Android S if this initialization happens when
the app doesn't have permission to access the microphone.

Bug: b/197461765
Change-Id: Iebccff9d15f5bb12a7b2c78e1c373e379b37a127
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/246104
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
Commit-Queue: Xavier Lepaul‎ <xalep@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35689}
This commit is contained in:
Xavier Lepaul 2022-01-13 17:06:26 +01:00 committed by WebRTC LUCI CQ
parent a3361ff2f5
commit 1e12f2a800
6 changed files with 58 additions and 9 deletions

View File

@ -65,6 +65,7 @@ void AudioOptions::SetAll(const AudioOptions& change) {
SetFrom(&combined_audio_video_bwe, change.combined_audio_video_bwe); SetFrom(&combined_audio_video_bwe, change.combined_audio_video_bwe);
SetFrom(&audio_network_adaptor, change.audio_network_adaptor); SetFrom(&audio_network_adaptor, change.audio_network_adaptor);
SetFrom(&audio_network_adaptor_config, change.audio_network_adaptor_config); SetFrom(&audio_network_adaptor_config, change.audio_network_adaptor_config);
SetFrom(&init_recording_on_send, change.init_recording_on_send);
} }
bool AudioOptions::operator==(const AudioOptions& o) const { bool AudioOptions::operator==(const AudioOptions& o) const {
@ -92,7 +93,8 @@ bool AudioOptions::operator==(const AudioOptions& o) const {
tx_agc_limiter == o.tx_agc_limiter && tx_agc_limiter == o.tx_agc_limiter &&
combined_audio_video_bwe == o.combined_audio_video_bwe && combined_audio_video_bwe == o.combined_audio_video_bwe &&
audio_network_adaptor == o.audio_network_adaptor && audio_network_adaptor == o.audio_network_adaptor &&
audio_network_adaptor_config == o.audio_network_adaptor_config; audio_network_adaptor_config == o.audio_network_adaptor_config &&
init_recording_on_send == o.init_recording_on_send;
} }
std::string AudioOptions::ToString() const { std::string AudioOptions::ToString() const {
@ -126,6 +128,7 @@ std::string AudioOptions::ToString() const {
ToStringIfSet(&result, "tx_agc_limiter", tx_agc_limiter); ToStringIfSet(&result, "tx_agc_limiter", tx_agc_limiter);
ToStringIfSet(&result, "combined_audio_video_bwe", combined_audio_video_bwe); ToStringIfSet(&result, "combined_audio_video_bwe", combined_audio_video_bwe);
ToStringIfSet(&result, "audio_network_adaptor", audio_network_adaptor); ToStringIfSet(&result, "audio_network_adaptor", audio_network_adaptor);
ToStringIfSet(&result, "init_recording_on_send", init_recording_on_send);
result << "}"; result << "}";
return result.str(); return result.str();
} }

View File

@ -83,6 +83,10 @@ struct RTC_EXPORT AudioOptions {
absl::optional<bool> audio_network_adaptor; absl::optional<bool> audio_network_adaptor;
// Config string for audio network adaptor. // Config string for audio network adaptor.
absl::optional<std::string> audio_network_adaptor_config; absl::optional<std::string> audio_network_adaptor_config;
// Pre-initialize the ADM for recording when starting to send. Default to
// true.
// TODO(webrtc:13566): Remove this option. See issue for details.
absl::optional<bool> init_recording_on_send;
}; };
} // namespace cricket } // namespace cricket

View File

@ -1862,13 +1862,15 @@ void WebRtcVoiceMediaChannel::SetSend(bool send) {
return; return;
} }
// Apply channel specific options, and initialize the ADM for recording (this // Apply channel specific options.
// may take time on some platforms, e.g. Android).
if (send) { if (send) {
engine()->ApplyOptions(options_); engine()->ApplyOptions(options_);
// InitRecording() may return an error if the ADM is already recording. // Initialize the ADM for recording (this may take time on some platforms,
if (!engine()->adm()->RecordingIsInitialized() && // e.g. Android).
if (options_.init_recording_on_send.value_or(true) &&
// InitRecording() may return an error if the ADM is already recording.
!engine()->adm()->RecordingIsInitialized() &&
!engine()->adm()->Recording()) { !engine()->adm()->Recording()) {
if (engine()->adm()->InitRecording() != 0) { if (engine()->adm()->InitRecording() != 0) {
RTC_LOG(LS_WARNING) << "Failed to initialize recording"; RTC_LOG(LS_WARNING) << "Failed to initialize recording";

View File

@ -305,9 +305,15 @@ class WebRtcVoiceEngineTestFake : public ::testing::TestWithParam<bool> {
void SetSend(bool enable) { void SetSend(bool enable) {
ASSERT_TRUE(channel_); ASSERT_TRUE(channel_);
if (enable) { if (enable) {
EXPECT_CALL(*adm_, RecordingIsInitialized()).WillOnce(Return(false)); EXPECT_CALL(*adm_, RecordingIsInitialized())
EXPECT_CALL(*adm_, Recording()).WillOnce(Return(false)); .Times(::testing::AtMost(1))
EXPECT_CALL(*adm_, InitRecording()).WillOnce(Return(0)); .WillOnce(Return(false));
EXPECT_CALL(*adm_, Recording())
.Times(::testing::AtMost(1))
.WillOnce(Return(false));
EXPECT_CALL(*adm_, InitRecording())
.Times(::testing::AtMost(1))
.WillOnce(Return(0));
} }
channel_->SetSend(enable); channel_->SetSend(enable);
} }
@ -3122,6 +3128,34 @@ TEST_P(WebRtcVoiceEngineTestFake, SetAudioOptions) {
} }
} }
TEST_P(WebRtcVoiceEngineTestFake, InitRecordingOnSend) {
EXPECT_CALL(*adm_, RecordingIsInitialized()).WillOnce(Return(false));
EXPECT_CALL(*adm_, Recording()).WillOnce(Return(false));
EXPECT_CALL(*adm_, InitRecording()).Times(1);
std::unique_ptr<cricket::VoiceMediaChannel> channel(
engine_->CreateMediaChannel(&call_, cricket::MediaConfig(),
cricket::AudioOptions(),
webrtc::CryptoOptions()));
channel->SetSend(true);
}
TEST_P(WebRtcVoiceEngineTestFake, SkipInitRecordingOnSend) {
EXPECT_CALL(*adm_, RecordingIsInitialized()).Times(0);
EXPECT_CALL(*adm_, Recording()).Times(0);
EXPECT_CALL(*adm_, InitRecording()).Times(0);
cricket::AudioOptions options;
options.init_recording_on_send = false;
std::unique_ptr<cricket::VoiceMediaChannel> channel(
engine_->CreateMediaChannel(&call_, cricket::MediaConfig(), options,
webrtc::CryptoOptions()));
channel->SetSend(true);
}
TEST_P(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) { TEST_P(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
EXPECT_TRUE(SetupSendStream()); EXPECT_TRUE(SetupSendStream());
EXPECT_CALL(*adm_, BuiltInAECIsAvailable()) EXPECT_CALL(*adm_, BuiltInAECIsAvailable())

View File

@ -106,6 +106,8 @@ const char MediaConstraints::kTypingNoiseDetection[] =
const char MediaConstraints::kAudioMirroring[] = "googAudioMirroring"; const char MediaConstraints::kAudioMirroring[] = "googAudioMirroring";
const char MediaConstraints::kAudioNetworkAdaptorConfig[] = const char MediaConstraints::kAudioNetworkAdaptorConfig[] =
"googAudioNetworkAdaptorConfig"; "googAudioNetworkAdaptorConfig";
const char MediaConstraints::kInitAudioRecordingOnSend[] =
"InitAudioRecordingOnSend";
// Constraint keys for CreateOffer / CreateAnswer defined in W3C specification. // Constraint keys for CreateOffer / CreateAnswer defined in W3C specification.
const char MediaConstraints::kOfferToReceiveAudio[] = "OfferToReceiveAudio"; const char MediaConstraints::kOfferToReceiveAudio[] = "OfferToReceiveAudio";
@ -211,6 +213,9 @@ void CopyConstraintsIntoAudioOptions(const MediaConstraints* constraints,
if (options->audio_network_adaptor_config) { if (options->audio_network_adaptor_config) {
options->audio_network_adaptor = true; options->audio_network_adaptor = true;
} }
ConstraintToOptional<bool>(constraints,
MediaConstraints::kInitAudioRecordingOnSend,
&options->init_recording_on_send);
} }
bool CopyConstraintsIntoOfferAnswerOptions( bool CopyConstraintsIntoOfferAnswerOptions(

View File

@ -67,7 +67,8 @@ class MediaConstraints {
static const char kTypingNoiseDetection[]; // googTypingNoiseDetection static const char kTypingNoiseDetection[]; // googTypingNoiseDetection
static const char kAudioMirroring[]; // googAudioMirroring static const char kAudioMirroring[]; // googAudioMirroring
static const char static const char
kAudioNetworkAdaptorConfig[]; // goodAudioNetworkAdaptorConfig kAudioNetworkAdaptorConfig[]; // googAudioNetworkAdaptorConfig
static const char kInitAudioRecordingOnSend[]; // InitAudioRecordingOnSend;
// Constraint keys for CreateOffer / CreateAnswer // Constraint keys for CreateOffer / CreateAnswer
// Specified by the W3C PeerConnection spec // Specified by the W3C PeerConnection spec