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

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

Issue 1778793005: Refactor AVAudioSession intialization code. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Make isConfigured private 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 4390f4925832986d0cfa7a56349711e9febc8374..1c2fe829e68e0f2f7ee7ab8893d0079864b5de95 100644
--- a/webrtc/modules/audio_device/ios/audio_device_ios.mm
+++ b/webrtc/modules/audio_device/ios/audio_device_ios.mm
@@ -25,7 +25,9 @@
#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/RTCAudioSessionConfiguration.h"
namespace webrtc {
@@ -48,38 +50,7 @@ namespace webrtc {
} \
} while (0)
-// Preferred hardware sample rate (unit is in Hertz). The client sample rate
-// will be set to this value as well to avoid resampling the the audio unit's
-// format converter. Note that, some devices, e.g. BT headsets, only supports
-// 8000Hz as native sample rate.
-const double kHighPerformanceSampleRate = 48000.0;
-// A lower sample rate will be used for devices with only one core
-// (e.g. iPhone 4). The goal is to reduce the CPU load of the application.
-const double kLowComplexitySampleRate = 16000.0;
-// Use a hardware I/O buffer size (unit is in seconds) that matches the 10ms
-// size used by WebRTC. The exact actual size will differ between devices.
-// Example: using 48kHz on iPhone 6 results in a native buffer size of
-// ~10.6667ms or 512 audio frames per buffer. The FineAudioBuffer instance will
-// take care of any buffering required to convert between native buffers and
-// buffers used by WebRTC. It is beneficial for the performance if the native
-// size is as close to 10ms as possible since it results in "clean" callback
-// sequence without bursts of callbacks back to back.
-const double kHighPerformanceIOBufferDuration = 0.01;
-// Use a larger buffer size on devices with only one core (e.g. iPhone 4).
-// It will result in a lower CPU consumption at the cost of a larger latency.
-// The size of 60ms is based on instrumentation that shows a significant
-// reduction in CPU load compared with 10ms on low-end devices.
-// TODO(henrika): monitor this size and determine if it should be modified.
-const double kLowComplexityIOBufferDuration = 0.06;
-// Try to use mono to save resources. Also avoids channel format conversion
-// in the I/O audio unit. Initial tests have shown that it is possible to use
-// mono natively for built-in microphones and for BT headsets but not for
-// wired headsets. Wired headsets only support stereo as native channel format
-// but it is a low cost operation to do a format conversion to mono in the
-// audio unit. Hence, we will not hit a RTC_CHECK in
-// VerifyAudioParametersForActiveAudioSession() for a mismatch between the
-// preferred number of channels and the actual number of channels.
-const int kPreferredNumberOfChannels = 1;
+
// Number of bytes per audio sample for 16-bit signed integer representation.
const UInt32 kBytesPerSample = 2;
// Hardcoded delay estimates based on real measurements.
@@ -95,149 +66,6 @@ const int kMaxNumberOfAudioUnitInitializeAttempts = 5;
using ios::CheckAndLogError;
-// Return the preferred sample rate given number of CPU cores. Use highest
-// possible if the CPU has more than one core.
-static double GetPreferredSampleRate() {
- return (ios::GetProcessorCount() > 1) ? kHighPerformanceSampleRate
- : kLowComplexitySampleRate;
-}
-
-// Return the preferred I/O buffer size given number of CPU cores. Use smallest
-// possible if the CPU has more than one core.
-static double GetPreferredIOBufferDuration() {
- return (ios::GetProcessorCount() > 1) ? kHighPerformanceIOBufferDuration
- : kLowComplexityIOBufferDuration;
-}
-
-// Verifies that the current audio session supports input audio and that the
-// required category and mode are enabled.
-static bool VerifyAudioSession(RTCAudioSession* session) {
- LOG(LS_INFO) << "VerifyAudioSession";
- // Ensure that the device currently supports audio input.
- if (!session.inputAvailable) {
- LOG(LS_ERROR) << "No audio input path is available!";
- return false;
- }
-
- // Ensure that the required category and mode are actually activated.
- if (![session.category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) {
- LOG(LS_ERROR)
- << "Failed to set category to AVAudioSessionCategoryPlayAndRecord";
- return false;
- }
- if (![session.mode isEqualToString:AVAudioSessionModeVoiceChat]) {
- LOG(LS_ERROR) << "Failed to set mode to AVAudioSessionModeVoiceChat";
- return false;
- }
- return true;
-}
-
-// Activates an audio session suitable for full duplex VoIP sessions when
-// |activate| is true. Also sets the preferred sample rate and IO buffer
-// duration. Deactivates an active audio session if |activate| is set to false.
-static bool ActivateAudioSession(RTCAudioSession* session, bool activate) {
- LOG(LS_INFO) << "ActivateAudioSession(" << activate << ")";
-
- NSError* error = nil;
- BOOL success = NO;
-
- [session lockForConfiguration];
- if (!activate) {
- success = [session setActive:NO
- error:&error];
- [session unlockForConfiguration];
- return CheckAndLogError(success, error);
- }
-
- // Go ahead and active our own audio session since |activate| is true.
- // Use a category which supports simultaneous recording and playback.
- // By default, using this category implies that our app’s audio is
- // nonmixable, hence activating the session will interrupt any other
- // audio sessions which are also nonmixable.
- if (session.category != AVAudioSessionCategoryPlayAndRecord) {
- error = nil;
- success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
- withOptions:AVAudioSessionCategoryOptionAllowBluetooth
- error:&error];
- RTC_DCHECK(CheckAndLogError(success, error));
- }
-
- // Specify mode for two-way voice communication (e.g. VoIP).
- if (session.mode != AVAudioSessionModeVoiceChat) {
- error = nil;
- success = [session setMode:AVAudioSessionModeVoiceChat error:&error];
- RTC_DCHECK(CheckAndLogError(success, error));
- }
-
- // Set the session's sample rate or the hardware sample rate.
- // It is essential that we use the same sample rate as stream format
- // to ensure that the I/O unit does not have to do sample rate conversion.
- error = nil;
- success =
- [session setPreferredSampleRate:GetPreferredSampleRate() error:&error];
- RTC_DCHECK(CheckAndLogError(success, error));
-
- // Set the preferred audio I/O buffer duration, in seconds.
- error = nil;
- success = [session setPreferredIOBufferDuration:GetPreferredIOBufferDuration()
- error:&error];
- RTC_DCHECK(CheckAndLogError(success, error));
-
- // Activate the audio session. Activation can fail if another active audio
- // session (e.g. phone call) has higher priority than ours.
- error = nil;
- success = [session setActive:YES error:&error];
- if (!CheckAndLogError(success, error)) {
- [session unlockForConfiguration];
- return false;
- }
-
- // Ensure that the active audio session has the correct category and mode.
- if (!VerifyAudioSession(session)) {
- LOG(LS_ERROR) << "Failed to verify audio session category and mode";
- [session unlockForConfiguration];
- return false;
- }
-
- // Try to set the preferred number of hardware audio channels. These calls
- // must be done after setting the audio session’s category and mode and
- // activating the session.
- // We try to use mono in both directions to save resources and format
- // conversions in the audio unit. Some devices does only support stereo;
- // e.g. wired headset on iPhone 6.
- // TODO(henrika): add support for stereo if needed.
- error = nil;
- success =
- [session setPreferredInputNumberOfChannels:kPreferredNumberOfChannels
- error:&error];
- RTC_DCHECK(CheckAndLogError(success, error));
- error = nil;
- success =
- [session setPreferredOutputNumberOfChannels:kPreferredNumberOfChannels
- error:&error];
- RTC_DCHECK(CheckAndLogError(success, error));
- [session unlockForConfiguration];
- return true;
-}
-
-// An application can create more than one ADM and start audio streaming
-// for all of them. It is essential that we only activate the app's audio
-// session once (for the first one) and deactivate it once (for the last).
-static bool ActivateAudioSession() {
- LOGI() << "ActivateAudioSession";
- RTCAudioSession* session = [RTCAudioSession sharedInstance];
- return ActivateAudioSession(session, true);
-}
-
-// If more than one object is using the audio session, ensure that only the
-// last object deactivates. Apple recommends: "activate your audio session
-// only as needed and deactivate it when you are not using audio".
-static bool DeactivateAudioSession() {
- LOGI() << "DeactivateAudioSession";
- RTCAudioSession* session = [RTCAudioSession sharedInstance];
- return ActivateAudioSession(session, false);
-}
-
#if !defined(NDEBUG)
// Helper method for printing out an AudioStreamBasicDescription structure.
static void LogABSD(AudioStreamBasicDescription absd) {
@@ -313,13 +141,15 @@ int32_t AudioDeviceIOS::Init() {
LogDeviceInfo();
#endif
// Store the preferred sample rate and preferred number of channels already
- // here. They have not been set and confirmed yet since ActivateAudioSession()
+ // here. They have not been set and confirmed yet since configureForWebRTC
// is not called until audio is about to start. However, it makes sense to
// store the parameters now and then verify at a later stage.
- playout_parameters_.reset(GetPreferredSampleRate(),
- kPreferredNumberOfChannels);
- record_parameters_.reset(GetPreferredSampleRate(),
- kPreferredNumberOfChannels);
+ RTCAudioSessionConfiguration* config =
+ [RTCAudioSessionConfiguration webRTCConfiguration];
+ playout_parameters_.reset(config.sampleRate,
+ config.outputNumberOfChannels);
+ record_parameters_.reset(config.sampleRate,
+ config.inputNumberOfChannels);
// Ensure that the audio device buffer (ADB) knows about the internal audio
// parameters. Note that, even if we are unable to get a mono audio session,
// we will always tell the I/O audio unit to do a channel format conversion
@@ -673,7 +503,9 @@ void AudioDeviceIOS::SetupAudioBuffersForActiveAudioSession() {
// hardware sample rate but continue and use the non-ideal sample rate after
// reinitializing the audio parameters. Most BT headsets only support 8kHz or
// 16kHz.
- if (session.sampleRate != GetPreferredSampleRate()) {
+ RTCAudioSessionConfiguration* webRTCConfig =
+ [RTCAudioSessionConfiguration webRTCConfiguration];
+ if (session.sampleRate != webRTCConfig.sampleRate) {
LOG(LS_WARNING) << "Unable to set the preferred sample rate";
}
@@ -791,7 +623,7 @@ bool AudioDeviceIOS::SetupAndInitializeVoiceProcessingAudioUnit() {
UInt32 size = sizeof(application_format);
RTC_DCHECK_EQ(playout_parameters_.sample_rate(),
record_parameters_.sample_rate());
- RTC_DCHECK_EQ(1, kPreferredNumberOfChannels);
+ RTC_DCHECK_EQ(1, kRTCAudioSessionPreferredNumberOfChannels);
application_format.mSampleRate = playout_parameters_.sample_rate();
application_format.mFormatID = kAudioFormatLinearPCM;
application_format.mFormatFlags =
@@ -799,7 +631,8 @@ bool AudioDeviceIOS::SetupAndInitializeVoiceProcessingAudioUnit() {
application_format.mBytesPerPacket = kBytesPerSample;
application_format.mFramesPerPacket = 1; // uncompressed
application_format.mBytesPerFrame = kBytesPerSample;
- application_format.mChannelsPerFrame = kPreferredNumberOfChannels;
+ application_format.mChannelsPerFrame =
+ kRTCAudioSessionPreferredNumberOfChannels;
application_format.mBitsPerChannel = 8 * kBytesPerSample;
// Store the new format.
application_format_ = application_format;
@@ -937,16 +770,16 @@ bool AudioDeviceIOS::RestartAudioUnitWithNewFormat(float sample_rate) {
bool AudioDeviceIOS::InitPlayOrRecord() {
LOGI() << "InitPlayOrRecord";
- // Activate the audio session if not already activated.
- if (!ActivateAudioSession()) {
- return false;
- }
- // Ensure that the active audio session has the correct category and mode.
+ // Use the correct audio session configuration for WebRTC.
+ // This will attempt to activate the audio session.
RTCAudioSession* session = [RTCAudioSession sharedInstance];
- if (!VerifyAudioSession(session)) {
- DeactivateAudioSession();
- LOG(LS_ERROR) << "Failed to verify audio session category and mode";
+ [session lockForConfiguration];
+ NSError* error = nil;
+ if (![session configureWebRTCSession:&error]) {
+ RTCLogError(@"Failed to configure WebRTC session: %@",
+ error.localizedDescription);
+ [session unlockForConfiguration];
return false;
}
@@ -958,11 +791,11 @@ bool AudioDeviceIOS::InitPlayOrRecord() {
// Create, setup and initialize a new Voice-Processing I/O unit.
if (!SetupAndInitializeVoiceProcessingAudioUnit()) {
- // Reduce usage count for the audio session and possibly deactivate it if
- // this object is the only user.
- DeactivateAudioSession();
+ [session setActive:NO error:nil];
+ [session unlockForConfiguration];
return false;
}
+ [session unlockForConfiguration];
return true;
}
@@ -987,7 +820,10 @@ void AudioDeviceIOS::ShutdownPlayOrRecord() {
// All I/O should be stopped or paused prior to deactivating the audio
// session, hence we deactivate as last action.
- DeactivateAudioSession();
+ RTCAudioSession* session = [RTCAudioSession sharedInstance];
+ [session lockForConfiguration];
+ [session setActive:NO error:nil];
+ [session unlockForConfiguration];
}
void AudioDeviceIOS::DisposeAudioUnit() {
« no previous file with comments | « webrtc/modules/audio_device/audio_device.gypi ('k') | webrtc/modules/audio_device/ios/objc/RTCAudioSession.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698