diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index a30c6bc952..759682f1d4 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -270,9 +270,11 @@ if (is_ios || is_mac) { ":audio_session_observer", ":base_objc", "../api:array_view", + "../api:scoped_refptr", "../api:sequence_checker", "../api/task_queue", "../api/task_queue:default_task_queue_factory", + "../api/task_queue:pending_task_safety_flag", "../modules/audio_device:audio_device_api", "../modules/audio_device:audio_device_buffer", "../modules/audio_device:audio_device_generic", diff --git a/sdk/objc/native/src/audio/audio_device_ios.h b/sdk/objc/native/src/audio/audio_device_ios.h index dc9f462063..a86acb56fe 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.h +++ b/sdk/objc/native/src/audio/audio_device_ios.h @@ -14,7 +14,9 @@ #include #include +#include "api/scoped_refptr.h" #include "api/sequence_checker.h" +#include "api/task_queue/pending_task_safety_flag.h" #include "audio_session_observer.h" #include "modules/audio_device/audio_device_generic.h" #include "rtc_base/buffer.h" @@ -46,8 +48,7 @@ namespace ios_adm { // same thread. class AudioDeviceIOS : public AudioDeviceGeneric, public AudioSessionObserver, - public VoiceProcessingAudioUnitObserver, - public rtc::MessageHandler { + public VoiceProcessingAudioUnitObserver { public: explicit AudioDeviceIOS(bool bypass_voice_processing); ~AudioDeviceIOS() override; @@ -159,9 +160,6 @@ class AudioDeviceIOS : public AudioDeviceGeneric, UInt32 num_frames, AudioBufferList* io_data) override; - // Handles messages from posts. - void OnMessage(rtc::Message* msg) override; - bool IsInterrupted(); private: @@ -213,10 +211,6 @@ class AudioDeviceIOS : public AudioDeviceGeneric, // Determines whether voice processing should be enabled or disabled. const bool bypass_voice_processing_; - // Ensures that methods are called from the same thread as this object is - // created on. - SequenceChecker thread_checker_; - // Native I/O audio thread checker. SequenceChecker io_thread_checker_; @@ -273,7 +267,7 @@ class AudioDeviceIOS : public AudioDeviceGeneric, std::atomic playing_; // Set to true after successful call to Init(), false otherwise. - bool initialized_ RTC_GUARDED_BY(thread_checker_); + bool initialized_ RTC_GUARDED_BY(thread_); // Set to true after successful call to InitRecording() or InitPlayout(), // false otherwise. @@ -284,23 +278,27 @@ class AudioDeviceIOS : public AudioDeviceGeneric, // Audio interruption observer instance. RTCNativeAudioSessionDelegateAdapter* audio_session_observer_ - RTC_GUARDED_BY(thread_checker_); + RTC_GUARDED_BY(thread_); // Set to true if we've activated the audio session. - bool has_configured_session_ RTC_GUARDED_BY(thread_checker_); + bool has_configured_session_ RTC_GUARDED_BY(thread_); // Counts number of detected audio glitches on the playout side. - int64_t num_detected_playout_glitches_ RTC_GUARDED_BY(thread_checker_); + int64_t num_detected_playout_glitches_ RTC_GUARDED_BY(thread_); int64_t last_playout_time_ RTC_GUARDED_BY(io_thread_checker_); // Counts number of playout callbacks per call. - // The value isupdated on the native I/O thread and later read on the - // creating thread (see thread_checker_) but at this stage no audio is - // active. Hence, it is a "thread safe" design and no lock is needed. + // The value is updated on the native I/O thread and later read on the + // creating `thread_` but at this stage no audio is active. + // Hence, it is a "thread safe" design and no lock is needed. int64_t num_playout_callbacks_; // Contains the time for when the last output volume change was detected. - int64_t last_output_volume_change_time_ RTC_GUARDED_BY(thread_checker_); + int64_t last_output_volume_change_time_ RTC_GUARDED_BY(thread_); + + // Avoids running pending task after `this` is Terminated. + rtc::scoped_refptr safety_ = + PendingTaskSafetyFlag::Create(); }; } // namespace ios_adm } // namespace webrtc diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm index f3f87c04b6..dd2c11bdd2 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -16,6 +16,7 @@ #include #include "api/array_view.h" +#include "api/task_queue/pending_task_safety_flag.h" #include "helpers.h" #include "modules/audio_device/fine_audio_buffer.h" #include "rtc_base/checks.h" @@ -60,15 +61,6 @@ namespace ios_adm { const UInt16 kFixedPlayoutDelayEstimate = 30; const UInt16 kFixedRecordDelayEstimate = 30; -enum AudioDeviceMessageType : uint32_t { - kMessageTypeInterruptionBegin, - kMessageTypeInterruptionEnd, - kMessageTypeValidRouteChange, - kMessageTypeCanPlayOrRecordChange, - kMessageTypePlayoutGlitchDetected, - kMessageOutputVolumeChange, -}; - using ios::CheckAndLogError; #if !defined(NDEBUG) @@ -115,16 +107,15 @@ AudioDeviceIOS::AudioDeviceIOS(bool bypass_voice_processing) LOGI() << "ctor" << ios::GetCurrentThreadDescription() << ",bypass_voice_processing=" << bypass_voice_processing_; io_thread_checker_.Detach(); - thread_checker_.Detach(); thread_ = rtc::Thread::Current(); audio_session_observer_ = [[RTCNativeAudioSessionDelegateAdapter alloc] initWithObserver:this]; } AudioDeviceIOS::~AudioDeviceIOS() { - RTC_DCHECK(thread_checker_.IsCurrent()); + RTC_DCHECK_RUN_ON(thread_); LOGI() << "~dtor" << ios::GetCurrentThreadDescription(); - thread_->Clear(this); + safety_->SetNotAlive(); Terminate(); audio_session_observer_ = nil; } @@ -132,16 +123,15 @@ AudioDeviceIOS::~AudioDeviceIOS() { void AudioDeviceIOS::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { LOGI() << "AttachAudioBuffer"; RTC_DCHECK(audioBuffer); - RTC_DCHECK(thread_checker_.IsCurrent()); + RTC_DCHECK_RUN_ON(thread_); audio_device_buffer_ = audioBuffer; } AudioDeviceGeneric::InitStatus AudioDeviceIOS::Init() { LOGI() << "Init"; io_thread_checker_.Detach(); - thread_checker_.Detach(); - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); if (initialized_) { return InitStatus::OK; } @@ -167,7 +157,7 @@ AudioDeviceGeneric::InitStatus AudioDeviceIOS::Init() { int32_t AudioDeviceIOS::Terminate() { LOGI() << "Terminate"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); if (!initialized_) { return 0; } @@ -178,13 +168,13 @@ int32_t AudioDeviceIOS::Terminate() { } bool AudioDeviceIOS::Initialized() const { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); return initialized_; } int32_t AudioDeviceIOS::InitPlayout() { LOGI() << "InitPlayout"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTC_DCHECK(initialized_); RTC_DCHECK(!audio_is_initialized_); RTC_DCHECK(!playing_.load()); @@ -199,18 +189,18 @@ int32_t AudioDeviceIOS::InitPlayout() { } bool AudioDeviceIOS::PlayoutIsInitialized() const { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); return audio_is_initialized_; } bool AudioDeviceIOS::RecordingIsInitialized() const { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); return audio_is_initialized_; } int32_t AudioDeviceIOS::InitRecording() { LOGI() << "InitRecording"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTC_DCHECK(initialized_); RTC_DCHECK(!audio_is_initialized_); RTC_DCHECK(!recording_.load()); @@ -226,7 +216,7 @@ int32_t AudioDeviceIOS::InitRecording() { int32_t AudioDeviceIOS::StartPlayout() { LOGI() << "StartPlayout"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTC_DCHECK(audio_is_initialized_); RTC_DCHECK(!playing_.load()); RTC_DCHECK(audio_unit_); @@ -251,7 +241,7 @@ int32_t AudioDeviceIOS::StartPlayout() { int32_t AudioDeviceIOS::StopPlayout() { LOGI() << "StopPlayout"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); if (!audio_is_initialized_ || !playing_.load()) { return 0; } @@ -282,7 +272,7 @@ bool AudioDeviceIOS::Playing() const { int32_t AudioDeviceIOS::StartRecording() { LOGI() << "StartRecording"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTC_DCHECK(audio_is_initialized_); RTC_DCHECK(!recording_.load()); RTC_DCHECK(audio_unit_); @@ -305,7 +295,7 @@ int32_t AudioDeviceIOS::StartRecording() { int32_t AudioDeviceIOS::StopRecording() { LOGI() << "StopRecording"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); if (!audio_is_initialized_ || !recording_.load()) { return 0; } @@ -329,7 +319,7 @@ int32_t AudioDeviceIOS::PlayoutDelay(uint16_t& delayMS) const { int AudioDeviceIOS::GetPlayoutAudioParameters(AudioParameters* params) const { LOGI() << "GetPlayoutAudioParameters"; RTC_DCHECK(playout_parameters_.is_valid()); - RTC_DCHECK(thread_checker_.IsCurrent()); + RTC_DCHECK_RUN_ON(thread_); *params = playout_parameters_; return 0; } @@ -337,7 +327,7 @@ int AudioDeviceIOS::GetPlayoutAudioParameters(AudioParameters* params) const { int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const { LOGI() << "GetRecordAudioParameters"; RTC_DCHECK(record_parameters_.is_valid()); - RTC_DCHECK(thread_checker_.IsCurrent()); + RTC_DCHECK_RUN_ON(thread_); *params = record_parameters_; return 0; } @@ -345,31 +335,29 @@ int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const { void AudioDeviceIOS::OnInterruptionBegin() { RTC_DCHECK(thread_); LOGI() << "OnInterruptionBegin"; - thread_->Post(RTC_FROM_HERE, this, kMessageTypeInterruptionBegin); + thread_->PostTask(SafeTask(safety_, [this] { HandleInterruptionBegin(); })); } void AudioDeviceIOS::OnInterruptionEnd() { RTC_DCHECK(thread_); LOGI() << "OnInterruptionEnd"; - thread_->Post(RTC_FROM_HERE, this, kMessageTypeInterruptionEnd); + thread_->PostTask(SafeTask(safety_, [this] { HandleInterruptionEnd(); })); } void AudioDeviceIOS::OnValidRouteChange() { RTC_DCHECK(thread_); - thread_->Post(RTC_FROM_HERE, this, kMessageTypeValidRouteChange); + thread_->PostTask(SafeTask(safety_, [this] { HandleValidRouteChange(); })); } void AudioDeviceIOS::OnCanPlayOrRecordChange(bool can_play_or_record) { RTC_DCHECK(thread_); - thread_->Post(RTC_FROM_HERE, - this, - kMessageTypeCanPlayOrRecordChange, - new rtc::TypedMessageData(can_play_or_record)); + thread_->PostTask(SafeTask( + safety_, [this, can_play_or_record] { HandleCanPlayOrRecordChange(can_play_or_record); })); } void AudioDeviceIOS::OnChangedOutputVolume() { RTC_DCHECK(thread_); - thread_->Post(RTC_FROM_HERE, this, kMessageOutputVolumeChange); + thread_->PostTask(SafeTask(safety_, [this] { HandleOutputVolumeChange(); })); } OSStatus AudioDeviceIOS::OnDeliverRecordedData(AudioUnitRenderActionFlags* flags, @@ -464,7 +452,7 @@ OSStatus AudioDeviceIOS::OnGetPlayoutData(AudioUnitRenderActionFlags* flags, if (glitch_threshold < 120 && delta_time > 120) { RTCLog(@"Glitch warning is ignored. Probably caused by device switch."); } else { - thread_->Post(RTC_FROM_HERE, this, kMessageTypePlayoutGlitchDetected); + thread_->PostTask(SafeTask(safety_, [this] { HandlePlayoutGlitchDetected(); })); } } } @@ -479,34 +467,8 @@ OSStatus AudioDeviceIOS::OnGetPlayoutData(AudioUnitRenderActionFlags* flags, return noErr; } -void AudioDeviceIOS::OnMessage(rtc::Message* msg) { - switch (msg->message_id) { - case kMessageTypeInterruptionBegin: - HandleInterruptionBegin(); - break; - case kMessageTypeInterruptionEnd: - HandleInterruptionEnd(); - break; - case kMessageTypeValidRouteChange: - HandleValidRouteChange(); - break; - case kMessageTypeCanPlayOrRecordChange: { - rtc::TypedMessageData* data = static_cast*>(msg->pdata); - HandleCanPlayOrRecordChange(data->data()); - delete data; - break; - } - case kMessageTypePlayoutGlitchDetected: - HandlePlayoutGlitchDetected(); - break; - case kMessageOutputVolumeChange: - HandleOutputVolumeChange(); - break; - } -} - void AudioDeviceIOS::HandleInterruptionBegin() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Interruption begin. IsInterrupted changed from %d to 1.", is_interrupted_); if (audio_unit_ && audio_unit_->GetState() == VoiceProcessingAudioUnit::kStarted) { RTCLog(@"Stopping the audio unit due to interruption begin."); @@ -519,7 +481,7 @@ void AudioDeviceIOS::HandleInterruptionBegin() { } void AudioDeviceIOS::HandleInterruptionEnd() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Interruption ended. IsInterrupted changed from %d to 0. " "Updating audio unit state.", is_interrupted_); @@ -542,7 +504,7 @@ void AudioDeviceIOS::HandleInterruptionEnd() { } void AudioDeviceIOS::HandleValidRouteChange() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTC_OBJC_TYPE(RTCAudioSession)* session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; RTCLog(@"%@", session); HandleSampleRateChange(); @@ -554,7 +516,7 @@ void AudioDeviceIOS::HandleCanPlayOrRecordChange(bool can_play_or_record) { } void AudioDeviceIOS::HandleSampleRateChange() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Handling sample rate change."); // Don't do anything if we're interrupted. @@ -639,7 +601,7 @@ void AudioDeviceIOS::HandleSampleRateChange() { } void AudioDeviceIOS::HandlePlayoutGlitchDetected() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); // Don't update metrics if we're interrupted since a "glitch" is expected // in this state. if (is_interrupted_) { @@ -664,7 +626,7 @@ void AudioDeviceIOS::HandlePlayoutGlitchDetected() { } void AudioDeviceIOS::HandleOutputVolumeChange() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Output volume change detected."); // Store time of this detection so it can be used to defer detection of // glitches too close in time to this event. @@ -752,7 +714,7 @@ bool AudioDeviceIOS::CreateAudioUnit() { } void AudioDeviceIOS::UpdateAudioUnit(bool can_play_or_record) { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Updating audio unit state. CanPlayOrRecord=%d IsInterrupted=%d", can_play_or_record, is_interrupted_); @@ -839,7 +801,7 @@ void AudioDeviceIOS::UpdateAudioUnit(bool can_play_or_record) { } bool AudioDeviceIOS::ConfigureAudioSession() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Configuring audio session."); if (has_configured_session_) { RTCLogWarning(@"Audio session already configured."); @@ -859,7 +821,7 @@ bool AudioDeviceIOS::ConfigureAudioSession() { } bool AudioDeviceIOS::ConfigureAudioSessionLocked() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Configuring audio session."); if (has_configured_session_) { RTCLogWarning(@"Audio session already configured."); @@ -877,7 +839,7 @@ bool AudioDeviceIOS::ConfigureAudioSessionLocked() { } void AudioDeviceIOS::UnconfigureAudioSession() { - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); RTCLog(@"Unconfiguring audio session."); if (!has_configured_session_) { RTCLogWarning(@"Audio session already unconfigured."); @@ -894,7 +856,7 @@ void AudioDeviceIOS::UnconfigureAudioSession() { bool AudioDeviceIOS::InitPlayOrRecord() { LOGI() << "InitPlayOrRecord"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); // There should be no audio unit at this point. if (!CreateAudioUnit()) { @@ -938,7 +900,7 @@ bool AudioDeviceIOS::InitPlayOrRecord() { void AudioDeviceIOS::ShutdownPlayOrRecord() { LOGI() << "ShutdownPlayOrRecord"; - RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK_RUN_ON(thread_); // Stop the audio unit to prevent any additional audio callbacks. audio_unit_->Stop();