Skip to content
This repository has been archived by the owner on Oct 25, 2024. It is now read-only.

Commit

Permalink
Delay VoipCore initialization.
Browse files Browse the repository at this point in the history
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}
  • Loading branch information
timna authored and Commit Bot committed Nov 12, 2020
1 parent 428432d commit 254ad1b
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 39 deletions.
17 changes: 5 additions & 12 deletions api/voip/voip_engine_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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),
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;
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));
}

} // namespace webrtc
3 changes: 0 additions & 3 deletions api/voip/voip_engine_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions audio/voip/test/voip_core_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ 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),
CreateDefaultTaskQueueFactory(), audio_device_,
std::move(audio_processing), std::move(process_thread));
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));
}

std::unique_ptr<VoipCore> voip_core_;
Expand Down
37 changes: 30 additions & 7 deletions audio/voip/voip_core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ static constexpr int kMaxChannelId = 100000;

} // namespace

bool VoipCore::Init(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) {
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,
rtc::scoped_refptr<AudioProcessing> audio_processing,
std::unique_ptr<ProcessThread> process_thread) {
encoder_factory_ = std::move(encoder_factory);
decoder_factory_ = std::move(decoder_factory);
task_queue_factory_ = std::move(task_queue_factory);
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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";
Expand Down
35 changes: 22 additions & 13 deletions audio/voip/voip_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
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(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; }
Expand Down Expand Up @@ -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);
Expand All @@ -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_;

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 254ad1b

Please sign in to comment.