Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Unified Diff: webrtc/modules/audio_device/ios/audio_device_ios.mm

Issue 1796983004: Use RTCAudioSessionDelegate in AudioDeviceIOS. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Some nits. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/audio_device/ios/audio_device_ios.mm
diff --git a/webrtc/modules/audio_device/ios/audio_device_ios.mm b/webrtc/modules/audio_device/ios/audio_device_ios.mm
index 1c2fe829e68e0f2f7ee7ab8893d0079864b5de95..6f20c6a8b730243954bb4f47388d558b6e6c2223 100644
--- a/webrtc/modules/audio_device/ios/audio_device_ios.mm
+++ b/webrtc/modules/audio_device/ios/audio_device_ios.mm
@@ -18,16 +18,20 @@
#include "webrtc/modules/audio_device/ios/audio_device_ios.h"
#include "webrtc/base/atomicops.h"
+#include "webrtc/base/bind.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/logging.h"
+#include "webrtc/base/thread.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/modules/audio_device/fine_audio_buffer.h"
#include "webrtc/modules/utility/include/helpers_ios.h"
#import "webrtc/base/objc/RTCLogging.h"
#import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h"
+#import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h"
#import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h"
+#import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionDelegateAdapter.h"
namespace webrtc {
@@ -106,20 +110,24 @@ static void LogDeviceInfo() {
#endif // !defined(NDEBUG)
AudioDeviceIOS::AudioDeviceIOS()
- : audio_device_buffer_(nullptr),
- vpio_unit_(nullptr),
- recording_(0),
- playing_(0),
- initialized_(false),
- rec_is_initialized_(false),
- play_is_initialized_(false),
- audio_interruption_observer_(nullptr),
- route_change_observer_(nullptr) {
+ : async_invoker_(new rtc::AsyncInvoker()),
+ audio_device_buffer_(nullptr),
+ vpio_unit_(nullptr),
+ recording_(0),
+ playing_(0),
+ initialized_(false),
+ rec_is_initialized_(false),
+ play_is_initialized_(false),
+ is_interrupted_(false) {
LOGI() << "ctor" << ios::GetCurrentThreadDescription();
+ thread_ = rtc::Thread::Current();
+ audio_session_observer_ =
+ [[RTCAudioSessionDelegateAdapter alloc] initWithObserver:this];
}
AudioDeviceIOS::~AudioDeviceIOS() {
LOGI() << "~dtor" << ios::GetCurrentThreadDescription();
+ audio_session_observer_ = nil;
RTC_DCHECK(thread_checker_.CalledOnValidThread());
Terminate();
}
@@ -332,6 +340,80 @@ int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const {
return 0;
}
+void AudioDeviceIOS::OnInterruptionBegin() {
+ RTC_DCHECK(async_invoker_);
+ RTC_DCHECK(thread_);
+ if (thread_->IsCurrent()) {
+ HandleInterruptionBegin();
+ return;
+ }
+ async_invoker_->AsyncInvoke<void>(
+ thread_,
+ rtc::Bind(&webrtc::AudioDeviceIOS::HandleInterruptionBegin, this));
+}
+
+void AudioDeviceIOS::OnInterruptionEnd() {
+ RTC_DCHECK(async_invoker_);
+ RTC_DCHECK(thread_);
+ if (thread_->IsCurrent()) {
+ HandleInterruptionEnd();
+ return;
+ }
+ async_invoker_->AsyncInvoke<void>(
+ thread_,
+ rtc::Bind(&webrtc::AudioDeviceIOS::HandleInterruptionEnd, this));
+}
+
+void AudioDeviceIOS::OnValidRouteChange() {
+ RTC_DCHECK(async_invoker_);
+ RTC_DCHECK(thread_);
+ if (thread_->IsCurrent()) {
+ HandleValidRouteChange();
+ return;
+ }
+ async_invoker_->AsyncInvoke<void>(
+ thread_,
+ rtc::Bind(&webrtc::AudioDeviceIOS::HandleValidRouteChange, this));
+}
+
+void AudioDeviceIOS::HandleInterruptionBegin() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTCLog(@"Stopping the audio unit due to interruption begin.");
+ LOG_IF_ERROR(AudioOutputUnitStop(vpio_unit_),
+ "Failed to stop the the Voice-Processing I/O unit");
+ is_interrupted_ = true;
+}
+
+void AudioDeviceIOS::HandleInterruptionEnd() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTCLog(@"Starting the audio unit due to interruption end.");
+ LOG_IF_ERROR(AudioOutputUnitStart(vpio_unit_),
+ "Failed to start the the Voice-Processing I/O unit");
+ is_interrupted_ = false;
+}
+
+void AudioDeviceIOS::HandleValidRouteChange() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Don't do anything if we're interrupted.
+ if (is_interrupted_) {
+ return;
+ }
+
+ // Only restart audio for a valid route change if the session sample rate
+ // has changed.
+ RTCAudioSession* session = [RTCAudioSession sharedInstance];
+ const double current_sample_rate = playout_parameters_.sample_rate();
+ const double session_sample_rate = session.sampleRate;
+ if (current_sample_rate != session_sample_rate) {
+ RTCLog(@"Route changed caused sample rate to change from %f to %f. "
+ "Restarting audio unit.", current_sample_rate, session_sample_rate);
+ if (!RestartAudioUnitWithNewFormat(session_sample_rate)) {
+ RTCLogError(@"Audio restart failed.");
+ }
+ }
+}
+
void AudioDeviceIOS::UpdateAudioDeviceBuffer() {
LOGI() << "UpdateAudioDevicebuffer";
// AttachAudioBuffer() is called at construction by the main class but check
@@ -345,155 +427,14 @@ void AudioDeviceIOS::UpdateAudioDeviceBuffer() {
audio_device_buffer_->SetRecordingChannels(record_parameters_.channels());
}
-void AudioDeviceIOS::RegisterNotificationObservers() {
- LOGI() << "RegisterNotificationObservers";
- // This code block will be called when AVAudioSessionInterruptionNotification
- // is observed.
- void (^interrupt_block)(NSNotification*) = ^(NSNotification* notification) {
- NSNumber* type_number =
- notification.userInfo[AVAudioSessionInterruptionTypeKey];
- AVAudioSessionInterruptionType type =
- (AVAudioSessionInterruptionType)type_number.unsignedIntegerValue;
- LOG(LS_INFO) << "Audio session interruption:";
- switch (type) {
- case AVAudioSessionInterruptionTypeBegan:
- // The system has deactivated our audio session.
- // Stop the active audio unit.
- LOG(LS_INFO) << " Began => stopping the audio unit";
- LOG_IF_ERROR(AudioOutputUnitStop(vpio_unit_),
- "Failed to stop the the Voice-Processing I/O unit");
- break;
- case AVAudioSessionInterruptionTypeEnded:
- // The interruption has ended. Restart the audio session and start the
- // initialized audio unit again.
- LOG(LS_INFO) << " Ended => restarting audio session and audio unit";
- NSError* error = nil;
- BOOL success = NO;
- AVAudioSession* session = [AVAudioSession sharedInstance];
- success = [session setActive:YES error:&error];
- if (CheckAndLogError(success, error)) {
- LOG_IF_ERROR(AudioOutputUnitStart(vpio_unit_),
- "Failed to start the the Voice-Processing I/O unit");
- }
- break;
- }
- };
-
- // This code block will be called when AVAudioSessionRouteChangeNotification
- // is observed.
- void (^route_change_block)(NSNotification*) =
- ^(NSNotification* notification) {
- // Get reason for current route change.
- NSNumber* reason_number =
- notification.userInfo[AVAudioSessionRouteChangeReasonKey];
- AVAudioSessionRouteChangeReason reason =
- (AVAudioSessionRouteChangeReason)reason_number.unsignedIntegerValue;
- bool valid_route_change = true;
- LOG(LS_INFO) << "Route change:";
- switch (reason) {
- case AVAudioSessionRouteChangeReasonUnknown:
- LOG(LS_INFO) << " ReasonUnknown";
- break;
- case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
- LOG(LS_INFO) << " NewDeviceAvailable";
- break;
- case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
- LOG(LS_INFO) << " OldDeviceUnavailable";
- break;
- case AVAudioSessionRouteChangeReasonCategoryChange:
- // It turns out that we see this notification (at least in iOS 9.2)
- // when making a switch from a BT device to e.g. Speaker using the
- // iOS Control Center and that we therefore must check if the sample
- // rate has changed. And if so is the case, restart the audio unit.
- LOG(LS_INFO) << " CategoryChange";
- LOG(LS_INFO) << " New category: " << ios::GetAudioSessionCategory();
- break;
- case AVAudioSessionRouteChangeReasonOverride:
- LOG(LS_INFO) << " Override";
- break;
- case AVAudioSessionRouteChangeReasonWakeFromSleep:
- LOG(LS_INFO) << " WakeFromSleep";
- break;
- case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
- LOG(LS_INFO) << " NoSuitableRouteForCategory";
- break;
- case AVAudioSessionRouteChangeReasonRouteConfigurationChange:
- // The set of input and output ports has not changed, but their
- // configuration has, e.g., a port’s selected data source has
- // changed. Ignore this type of route change since we are focusing
- // on detecting headset changes.
- LOG(LS_INFO) << " RouteConfigurationChange (ignored)";
- valid_route_change = false;
- break;
- }
-
- if (valid_route_change) {
- // Log previous route configuration.
- AVAudioSessionRouteDescription* prev_route =
- notification.userInfo[AVAudioSessionRouteChangePreviousRouteKey];
- LOG(LS_INFO) << "Previous route:";
- LOG(LS_INFO) << ios::StdStringFromNSString(
- [NSString stringWithFormat:@"%@", prev_route]);
-
- // Only restart audio for a valid route change and if the
- // session sample rate has changed.
- RTCAudioSession* session = [RTCAudioSession sharedInstance];
- const double session_sample_rate = session.sampleRate;
- LOG(LS_INFO) << "session sample rate: " << session_sample_rate;
- if (playout_parameters_.sample_rate() != session_sample_rate) {
- if (!RestartAudioUnitWithNewFormat(session_sample_rate)) {
- LOG(LS_ERROR) << "Audio restart failed";
- }
- }
- }
- };
-
- // Get the default notification center of the current process.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
-
- // Add AVAudioSessionInterruptionNotification observer.
- id interruption_observer =
- [center addObserverForName:AVAudioSessionInterruptionNotification
- object:nil
- queue:[NSOperationQueue mainQueue]
- usingBlock:interrupt_block];
- // Add AVAudioSessionRouteChangeNotification observer.
- id route_change_observer =
- [center addObserverForName:AVAudioSessionRouteChangeNotification
- object:nil
- queue:[NSOperationQueue mainQueue]
- usingBlock:route_change_block];
-
- // Increment refcount on observers using ARC bridge. Instance variable is a
- // void* instead of an id because header is included in other pure C++
- // files.
- audio_interruption_observer_ = (__bridge_retained void*)interruption_observer;
- route_change_observer_ = (__bridge_retained void*)route_change_observer;
-}
-
-void AudioDeviceIOS::UnregisterNotificationObservers() {
- LOGI() << "UnregisterNotificationObservers";
- // Transfer ownership of observer back to ARC, which will deallocate the
- // observer once it exits this scope.
- NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
- if (audio_interruption_observer_ != nullptr) {
- id observer = (__bridge_transfer id)audio_interruption_observer_;
- [center removeObserver:observer];
- audio_interruption_observer_ = nullptr;
- }
- if (route_change_observer_ != nullptr) {
- id observer = (__bridge_transfer id)route_change_observer_;
- [center removeObserver:observer];
- route_change_observer_ = nullptr;
- }
-}
-
void AudioDeviceIOS::SetupAudioBuffersForActiveAudioSession() {
LOGI() << "SetupAudioBuffersForActiveAudioSession";
// Verify the current values once the audio session has been activated.
RTCAudioSession* session = [RTCAudioSession sharedInstance];
- LOG(LS_INFO) << " sample rate: " << session.sampleRate;
- LOG(LS_INFO) << " IO buffer duration: " << session.IOBufferDuration;
+ double sample_rate = session.sampleRate;
+ NSTimeInterval io_buffer_duration = session.IOBufferDuration;
+ LOG(LS_INFO) << " sample rate: " << sample_rate;
+ LOG(LS_INFO) << " IO buffer duration: " << io_buffer_duration;
LOG(LS_INFO) << " output channels: " << session.outputNumberOfChannels;
LOG(LS_INFO) << " input channels: " << session.inputNumberOfChannels;
LOG(LS_INFO) << " output latency: " << session.outputLatency;
@@ -505,7 +446,7 @@ void AudioDeviceIOS::SetupAudioBuffersForActiveAudioSession() {
// 16kHz.
RTCAudioSessionConfiguration* webRTCConfig =
[RTCAudioSessionConfiguration webRTCConfiguration];
- if (session.sampleRate != webRTCConfig.sampleRate) {
+ if (sample_rate != webRTCConfig.sampleRate) {
LOG(LS_WARNING) << "Unable to set the preferred sample rate";
}
@@ -514,11 +455,11 @@ void AudioDeviceIOS::SetupAudioBuffersForActiveAudioSession() {
// number of audio frames.
// Example: IO buffer size = 0.008 seconds <=> 128 audio frames at 16kHz.
// Hence, 128 is the size we expect to see in upcoming render callbacks.
- playout_parameters_.reset(session.sampleRate, playout_parameters_.channels(),
- session.IOBufferDuration);
+ playout_parameters_.reset(sample_rate, playout_parameters_.channels(),
+ io_buffer_duration);
RTC_DCHECK(playout_parameters_.is_complete());
- record_parameters_.reset(session.sampleRate, record_parameters_.channels(),
- session.IOBufferDuration);
+ record_parameters_.reset(sample_rate, record_parameters_.channels(),
+ io_buffer_duration);
RTC_DCHECK(record_parameters_.is_complete());
LOG(LS_INFO) << " frames per I/O buffer: "
<< playout_parameters_.frames_per_buffer();
@@ -784,7 +725,7 @@ bool AudioDeviceIOS::InitPlayOrRecord() {
}
// Start observing audio session interruptions and route changes.
- RegisterNotificationObservers();
+ [session pushDelegate:audio_session_observer_];
// Ensure that we got what what we asked for in our active audio session.
SetupAudioBuffersForActiveAudioSession();
@@ -816,11 +757,11 @@ void AudioDeviceIOS::ShutdownPlayOrRecord() {
}
// Remove audio session notification observers.
- UnregisterNotificationObservers();
+ RTCAudioSession* session = [RTCAudioSession sharedInstance];
+ [session removeDelegate:audio_session_observer_];
// All I/O should be stopped or paused prior to deactivating the audio
// session, hence we deactivate as last action.
- RTCAudioSession* session = [RTCAudioSession sharedInstance];
[session lockForConfiguration];
[session setActive:NO error:nil];
[session unlockForConfiguration];
« no previous file with comments | « webrtc/modules/audio_device/ios/audio_device_ios.h ('k') | webrtc/modules/audio_device/ios/audio_session_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698