Delay VoipCore initialization.

Starting from Android N, mobile app may not be able to access
microphone while in background where it fails the call.
In order to mitigate the issue, delay the ADM initialization
as late as possible.

Bug: webrtc:12120
Change-Id: I0fbf0300299b6c53413dfaaf88f748edc0a06bc1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/191100
Commit-Queue: Tim Na <natim@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32598}
This commit is contained in:
Tim Na
2020-11-12 09:40:24 -08:00
committed by Commit Bot
parent 428432d09e
commit 254ad1b914
5 changed files with 61 additions and 39 deletions

View File

@ -27,18 +27,11 @@ std::unique_ptr<VoipEngine> CreateVoipEngine(VoipEngineConfig config) {
RTC_DLOG(INFO) << "No audio processing functionality provided.";
}
auto voip_core = std::make_unique<VoipCore>();
if (!voip_core->Init(std::move(config.encoder_factory),
return std::make_unique<VoipCore>(std::move(config.encoder_factory),
std::move(config.decoder_factory),
std::move(config.task_queue_factory),
std::move(config.audio_device_module),
std::move(config.audio_processing))) {
RTC_DLOG(LS_ERROR) << "Failed to initialize VoIP core.";
return nullptr;
}
return voip_core;
std::move(config.audio_processing));
}
} // namespace webrtc

View File

@ -61,9 +61,6 @@ struct VoipEngineConfig {
};
// Creates a VoipEngine instance with provided VoipEngineConfig.
// This could return nullptr if AudioDeviceModule (ADM) initialization fails
// during construction of VoipEngine which would render VoipEngine
// nonfunctional.
std::unique_ptr<VoipEngine> CreateVoipEngine(VoipEngineConfig config);
} // namespace webrtc

View File

@ -45,8 +45,8 @@ class VoipCoreTest : public ::testing::Test {
// Hold the pointer to use for testing.
process_thread_ = process_thread.get();
voip_core_ = std::make_unique<VoipCore>();
voip_core_->Init(std::move(encoder_factory), std::move(decoder_factory),
voip_core_ = std::make_unique<VoipCore>(
std::move(encoder_factory), std::move(decoder_factory),
CreateDefaultTaskQueueFactory(), audio_device_,
std::move(audio_processing), std::move(process_thread));
}

View File

@ -37,7 +37,7 @@ static constexpr int kMaxChannelId = 100000;
} // namespace
bool VoipCore::Init(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
VoipCore::VoipCore(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
std::unique_ptr<TaskQueueFactory> task_queue_factory,
rtc::scoped_refptr<AudioDeviceModule> audio_device_module,
@ -58,6 +58,18 @@ bool VoipCore::Init(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
// AudioTransportImpl depends on audio mixer and audio processing instances.
audio_transport_ = std::make_unique<AudioTransportImpl>(
audio_mixer_.get(), audio_processing_.get(), nullptr);
}
bool VoipCore::InitializeIfNeeded() {
// |audio_device_module_| internally owns a lock and the whole logic here
// needs to be executed atomically once using another lock in VoipCore.
// Further changes in this method will need to make sure that no deadlock is
// introduced in the future.
MutexLock lock(&lock_);
if (initialized_) {
return true;
}
// Initialize ADM.
if (audio_device_module_->Init() != 0) {
@ -70,7 +82,6 @@ bool VoipCore::Init(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
// recording device functioning (e.g webinar where only speaker is available).
// It's also possible that there are other audio devices available that may
// work.
// TODO(natim@webrtc.org): consider moving this part out of initialization.
// Initialize default speaker device.
if (audio_device_module_->SetPlayoutDevice(kAudioDeviceId) != 0) {
@ -111,6 +122,8 @@ bool VoipCore::Init(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
RTC_LOG(LS_WARNING) << "Unable to register audio callback.";
}
initialized_ = true;
return true;
}
@ -243,6 +256,11 @@ bool VoipCore::UpdateAudioTransportWithSenders() {
// Depending on availability of senders, turn on or off ADM recording.
if (!audio_senders.empty()) {
// Initialize audio device module and default device if needed.
if (!InitializeIfNeeded()) {
return false;
}
if (!audio_device_module_->Recording()) {
if (audio_device_module_->InitRecording() != 0) {
RTC_LOG(LS_ERROR) << "InitRecording failed";
@ -300,6 +318,11 @@ bool VoipCore::StartPlayout(ChannelId channel_id) {
return false;
}
// Initialize audio device module and default device if needed.
if (!InitializeIfNeeded()) {
return false;
}
if (!audio_device_module_->Playing()) {
if (audio_device_module_->InitPlayout() != 0) {
RTC_LOG(LS_ERROR) << "InitPlayout failed";

View File

@ -51,21 +51,17 @@ class VoipCore : public VoipEngine,
public VoipDtmf,
public VoipStatistics {
public:
~VoipCore() override = default;
// Initialize VoipCore components with provided arguments.
// Returns false only when |audio_device_module| fails to initialize which
// would presumably render further processing useless.
// Construct VoipCore with provided arguments.
// ProcessThread implementation can be injected by |process_thread|
// (mainly for testing purpose) and when set to nullptr, default
// implementation will be used.
// TODO(natim@webrtc.org): Need to report audio device errors to user layer.
bool Init(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
VoipCore(rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
std::unique_ptr<TaskQueueFactory> task_queue_factory,
rtc::scoped_refptr<AudioDeviceModule> audio_device_module,
rtc::scoped_refptr<AudioProcessing> audio_processing,
std::unique_ptr<ProcessThread> process_thread = nullptr);
~VoipCore() override = default;
// Implements VoipEngine interfaces.
VoipBase& Base() override { return *this; }
@ -111,6 +107,16 @@ class VoipCore : public VoipEngine,
ChannelId channel_id) override;
private:
// Initialize ADM and default audio device if needed.
// Returns true if ADM is successfully initialized or already in such state
// (e.g called more than once). Returns false when ADM fails to initialize
// which would presumably render further processing useless. Note that such
// failure won't necessarily succeed in next initialization attempt as it
// would mean changing the ADM implementation. From Android N and onwards, the
// mobile app may not be able to gain microphone access when in background
// mode. Therefore it would be better to delay the logic as late as possible.
bool InitializeIfNeeded();
// Fetches the corresponding AudioChannel assigned with given |channel|.
// Returns nullptr if not found.
rtc::scoped_refptr<AudioChannel> GetChannel(ChannelId channel_id);
@ -126,7 +132,7 @@ class VoipCore : public VoipEngine,
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
std::unique_ptr<TaskQueueFactory> task_queue_factory_;
// Synchronization is handled internally by AudioProessing.
// Synchronization is handled internally by AudioProcessing.
// Must be placed before |audio_device_module_| for proper destruction.
rtc::scoped_refptr<AudioProcessing> audio_processing_;
@ -154,6 +160,9 @@ class VoipCore : public VoipEngine,
// ChannelId.
std::unordered_map<ChannelId, rtc::scoped_refptr<AudioChannel>> channels_
RTC_GUARDED_BY(lock_);
// Boolean flag to ensure initialization only occurs once.
bool initialized_ RTC_GUARDED_BY(lock_) = false;
};
} // namespace webrtc