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:
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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);
|
||||
@ -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";
|
||||
|
||||
@ -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; }
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user