Update ios AudioDevice away from rtc::MessageHandler
Align thread checkers with the class comment,
i.e. ensure AudioDevice is used and destroyed on the same thread it was constructed on, not just the same thread AudioDevice::Init was called.
Bug: webrtc:9702
Change-Id: Ib905978cc8173266151adf26e1b7317f1d3852bc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/274164
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Auto-Submit: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38018}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index a30c6bc..759682f 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -270,9 +270,11 @@
":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 dc9f462..a86acb5 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 <atomic>
#include <memory>
+#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 @@
// 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 @@
UInt32 num_frames,
AudioBufferList* io_data) override;
- // Handles messages from posts.
- void OnMessage(rtc::Message* msg) override;
-
bool IsInterrupted();
private:
@@ -213,10 +211,6 @@
// 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 @@
std::atomic<int> 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 @@
// 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<PendingTaskSafetyFlag> 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 f3f87c0..dd2c11b 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 <cmath>
#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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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::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::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 @@
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::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 @@
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::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 @@
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<bool>(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 @@
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 @@
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<bool>* data = static_cast<rtc::TypedMessageData<bool>*>(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::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::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::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::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::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 @@
}
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 @@
}
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::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 @@
}
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 @@
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 @@
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();