Home | History | Annotate | Download | only in ios
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #if !defined(__has_feature) || !__has_feature(objc_arc)
     12 #error "This file requires ARC support."
     13 #endif
     14 
     15 #import <AVFoundation/AVFoundation.h>
     16 #import <Foundation/Foundation.h>
     17 
     18 #include "webrtc/modules/audio_device/ios/audio_device_ios.h"
     19 
     20 #include "webrtc/base/atomicops.h"
     21 #include "webrtc/base/checks.h"
     22 #include "webrtc/base/criticalsection.h"
     23 #include "webrtc/base/logging.h"
     24 #include "webrtc/base/thread_annotations.h"
     25 #include "webrtc/modules/audio_device/fine_audio_buffer.h"
     26 #include "webrtc/modules/utility/include/helpers_ios.h"
     27 
     28 namespace webrtc {
     29 
     30 // Protects |g_audio_session_users|.
     31 static rtc::GlobalLockPod g_lock;
     32 
     33 // Counts number of users (=instances of this object) who needs an active
     34 // audio session. This variable is used to ensure that we only activate an audio
     35 // session for the first user and deactivate it for the last.
     36 // Member is static to ensure that the value is counted for all instances
     37 // and not per instance.
     38 static int g_audio_session_users GUARDED_BY(g_lock) = 0;
     39 
     40 #define LOGI() LOG(LS_INFO) << "AudioDeviceIOS::"
     41 
     42 #define LOG_AND_RETURN_IF_ERROR(error, message) \
     43   do {                                          \
     44     OSStatus err = error;                       \
     45     if (err) {                                  \
     46       LOG(LS_ERROR) << message << ": " << err;  \
     47       return false;                             \
     48     }                                           \
     49   } while (0)
     50 
     51 #define LOG_IF_ERROR(error, message)           \
     52   do {                                         \
     53     OSStatus err = error;                      \
     54     if (err) {                                 \
     55       LOG(LS_ERROR) << message << ": " << err; \
     56     }                                          \
     57   } while (0)
     58 
     59 // Preferred hardware sample rate (unit is in Hertz). The client sample rate
     60 // will be set to this value as well to avoid resampling the the audio unit's
     61 // format converter. Note that, some devices, e.g. BT headsets, only supports
     62 // 8000Hz as native sample rate.
     63 const double kPreferredSampleRate = 48000.0;
     64 // Use a hardware I/O buffer size (unit is in seconds) that matches the 10ms
     65 // size used by WebRTC. The exact actual size will differ between devices.
     66 // Example: using 48kHz on iPhone 6 results in a native buffer size of
     67 // ~10.6667ms or 512 audio frames per buffer. The FineAudioBuffer instance will
     68 // take care of any buffering required to convert between native buffers and
     69 // buffers used by WebRTC. It is beneficial for the performance if the native
     70 // size is as close to 10ms as possible since it results in "clean" callback
     71 // sequence without bursts of callbacks back to back.
     72 const double kPreferredIOBufferDuration = 0.01;
     73 // Try to use mono to save resources. Also avoids channel format conversion
     74 // in the I/O audio unit. Initial tests have shown that it is possible to use
     75 // mono natively for built-in microphones and for BT headsets but not for
     76 // wired headsets. Wired headsets only support stereo as native channel format
     77 // but it is a low cost operation to do a format conversion to mono in the
     78 // audio unit. Hence, we will not hit a RTC_CHECK in
     79 // VerifyAudioParametersForActiveAudioSession() for a mismatch between the
     80 // preferred number of channels and the actual number of channels.
     81 const int kPreferredNumberOfChannels = 1;
     82 // Number of bytes per audio sample for 16-bit signed integer representation.
     83 const UInt32 kBytesPerSample = 2;
     84 // Hardcoded delay estimates based on real measurements.
     85 // TODO(henrika): these value is not used in combination with built-in AEC.
     86 // Can most likely be removed.
     87 const UInt16 kFixedPlayoutDelayEstimate = 30;
     88 const UInt16 kFixedRecordDelayEstimate = 30;
     89 // Calls to AudioUnitInitialize() can fail if called back-to-back on different
     90 // ADM instances. A fall-back solution is to allow multiple sequential calls
     91 // with as small delay between each. This factor sets the max number of allowed
     92 // initialization attempts.
     93 const int kMaxNumberOfAudioUnitInitializeAttempts = 5;
     94 
     95 
     96 using ios::CheckAndLogError;
     97 
     98 // Verifies that the current audio session supports input audio and that the
     99 // required category and mode are enabled.
    100 static bool VerifyAudioSession(AVAudioSession* session) {
    101   LOG(LS_INFO) << "VerifyAudioSession";
    102   // Ensure that the device currently supports audio input.
    103   if (!session.isInputAvailable) {
    104     LOG(LS_ERROR) << "No audio input path is available!";
    105     return false;
    106   }
    107 
    108   // Ensure that the required category and mode are actually activated.
    109   if (![session.category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) {
    110     LOG(LS_ERROR)
    111         << "Failed to set category to AVAudioSessionCategoryPlayAndRecord";
    112     return false;
    113   }
    114   if (![session.mode isEqualToString:AVAudioSessionModeVoiceChat]) {
    115     LOG(LS_ERROR) << "Failed to set mode to AVAudioSessionModeVoiceChat";
    116     return false;
    117   }
    118   return true;
    119 }
    120 
    121 // Activates an audio session suitable for full duplex VoIP sessions when
    122 // |activate| is true. Also sets the preferred sample rate and IO buffer
    123 // duration. Deactivates an active audio session if |activate| is set to false.
    124 static bool ActivateAudioSession(AVAudioSession* session, bool activate)
    125     EXCLUSIVE_LOCKS_REQUIRED(g_lock) {
    126   LOG(LS_INFO) << "ActivateAudioSession(" << activate << ")";
    127   @autoreleasepool {
    128     NSError* error = nil;
    129     BOOL success = NO;
    130 
    131     if (!activate) {
    132       // Deactivate the audio session using an extra option and then return.
    133       // AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation is used to
    134       // ensure that other audio sessions that were interrupted by our session
    135       // can return to their active state. It is recommended for VoIP apps to
    136       // use this option.
    137       success = [session
    138             setActive:NO
    139           withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
    140                 error:&error];
    141       return CheckAndLogError(success, error);
    142     }
    143 
    144     // Go ahead and active our own audio session since |activate| is true.
    145     // Use a category which supports simultaneous recording and playback.
    146     // By default, using this category implies that our apps audio is
    147     // nonmixable, hence activating the session will interrupt any other
    148     // audio sessions which are also nonmixable.
    149     if (session.category != AVAudioSessionCategoryPlayAndRecord) {
    150       error = nil;
    151       success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
    152                          withOptions:AVAudioSessionCategoryOptionAllowBluetooth
    153                                error:&error];
    154       RTC_DCHECK(CheckAndLogError(success, error));
    155     }
    156 
    157     // Specify mode for two-way voice communication (e.g. VoIP).
    158     if (session.mode != AVAudioSessionModeVoiceChat) {
    159       error = nil;
    160       success = [session setMode:AVAudioSessionModeVoiceChat error:&error];
    161       RTC_DCHECK(CheckAndLogError(success, error));
    162     }
    163 
    164     // Set the session's sample rate or the hardware sample rate.
    165     // It is essential that we use the same sample rate as stream format
    166     // to ensure that the I/O unit does not have to do sample rate conversion.
    167     error = nil;
    168     success =
    169         [session setPreferredSampleRate:kPreferredSampleRate error:&error];
    170     RTC_DCHECK(CheckAndLogError(success, error));
    171 
    172     // Set the preferred audio I/O buffer duration, in seconds.
    173     error = nil;
    174     success = [session setPreferredIOBufferDuration:kPreferredIOBufferDuration
    175                                               error:&error];
    176     RTC_DCHECK(CheckAndLogError(success, error));
    177 
    178     // Activate the audio session. Activation can fail if another active audio
    179     // session (e.g. phone call) has higher priority than ours.
    180     error = nil;
    181     success = [session setActive:YES error:&error];
    182     if (!CheckAndLogError(success, error)) {
    183       return false;
    184     }
    185 
    186     // Ensure that the active audio session has the correct category and mode.
    187     if (!VerifyAudioSession(session)) {
    188       LOG(LS_ERROR) << "Failed to verify audio session category and mode";
    189       return false;
    190     }
    191 
    192     // Try to set the preferred number of hardware audio channels. These calls
    193     // must be done after setting the audio sessions category and mode and
    194     // activating the session.
    195     // We try to use mono in both directions to save resources and format
    196     // conversions in the audio unit. Some devices does only support stereo;
    197     // e.g. wired headset on iPhone 6.
    198     // TODO(henrika): add support for stereo if needed.
    199     error = nil;
    200     success =
    201         [session setPreferredInputNumberOfChannels:kPreferredNumberOfChannels
    202                                              error:&error];
    203     RTC_DCHECK(CheckAndLogError(success, error));
    204     error = nil;
    205     success =
    206         [session setPreferredOutputNumberOfChannels:kPreferredNumberOfChannels
    207                                               error:&error];
    208     RTC_DCHECK(CheckAndLogError(success, error));
    209     return true;
    210   }
    211 }
    212 
    213 // An application can create more than one ADM and start audio streaming
    214 // for all of them. It is essential that we only activate the app's audio
    215 // session once (for the first one) and deactivate it once (for the last).
    216 static bool ActivateAudioSession() {
    217   LOGI() << "ActivateAudioSession";
    218   rtc::GlobalLockScope ls(&g_lock);
    219   if (g_audio_session_users == 0) {
    220     // The system provides an audio session object upon launch of an
    221     // application. However, we must initialize the session in order to
    222     // handle interruptions. Implicit initialization occurs when obtaining
    223     // a reference to the AVAudioSession object.
    224     AVAudioSession* session = [AVAudioSession sharedInstance];
    225     // Try to activate the audio session and ask for a set of preferred audio
    226     // parameters.
    227     if (!ActivateAudioSession(session, true)) {
    228       LOG(LS_ERROR) << "Failed to activate the audio session";
    229       return false;
    230     }
    231     LOG(LS_INFO) << "The audio session is now activated";
    232   }
    233   ++g_audio_session_users;
    234   LOG(LS_INFO) << "Number of audio session users: " << g_audio_session_users;
    235   return true;
    236 }
    237 
    238 // If more than one object is using the audio session, ensure that only the
    239 // last object deactivates. Apple recommends: "activate your audio session
    240 // only as needed and deactivate it when you are not using audio".
    241 static bool DeactivateAudioSession() {
    242   LOGI() << "DeactivateAudioSession";
    243   rtc::GlobalLockScope ls(&g_lock);
    244   if (g_audio_session_users == 1) {
    245     AVAudioSession* session = [AVAudioSession sharedInstance];
    246     if (!ActivateAudioSession(session, false)) {
    247       LOG(LS_ERROR) << "Failed to deactivate the audio session";
    248       return false;
    249     }
    250     LOG(LS_INFO) << "Our audio session is now deactivated";
    251   }
    252   --g_audio_session_users;
    253   LOG(LS_INFO) << "Number of audio session users: " << g_audio_session_users;
    254   return true;
    255 }
    256 
    257 #if !defined(NDEBUG)
    258 // Helper method for printing out an AudioStreamBasicDescription structure.
    259 static void LogABSD(AudioStreamBasicDescription absd) {
    260   char formatIDString[5];
    261   UInt32 formatID = CFSwapInt32HostToBig(absd.mFormatID);
    262   bcopy(&formatID, formatIDString, 4);
    263   formatIDString[4] = '\0';
    264   LOG(LS_INFO) << "LogABSD";
    265   LOG(LS_INFO) << " sample rate: " << absd.mSampleRate;
    266   LOG(LS_INFO) << " format ID: " << formatIDString;
    267   LOG(LS_INFO) << " format flags: " << std::hex << absd.mFormatFlags;
    268   LOG(LS_INFO) << " bytes per packet: " << absd.mBytesPerPacket;
    269   LOG(LS_INFO) << " frames per packet: " << absd.mFramesPerPacket;
    270   LOG(LS_INFO) << " bytes per frame: " << absd.mBytesPerFrame;
    271   LOG(LS_INFO) << " channels per packet: " << absd.mChannelsPerFrame;
    272   LOG(LS_INFO) << " bits per channel: " << absd.mBitsPerChannel;
    273   LOG(LS_INFO) << " reserved: " << absd.mReserved;
    274 }
    275 
    276 // Helper method that logs essential device information strings.
    277 static void LogDeviceInfo() {
    278   LOG(LS_INFO) << "LogDeviceInfo";
    279   @autoreleasepool {
    280     LOG(LS_INFO) << " system name: " << ios::GetSystemName();
    281     LOG(LS_INFO) << " system version: " << ios::GetSystemVersion();
    282     LOG(LS_INFO) << " device type: " << ios::GetDeviceType();
    283     LOG(LS_INFO) << " device name: " << ios::GetDeviceName();
    284   }
    285 }
    286 #endif  // !defined(NDEBUG)
    287 
    288 AudioDeviceIOS::AudioDeviceIOS()
    289     : audio_device_buffer_(nullptr),
    290       vpio_unit_(nullptr),
    291       recording_(0),
    292       playing_(0),
    293       initialized_(false),
    294       rec_is_initialized_(false),
    295       play_is_initialized_(false),
    296       audio_interruption_observer_(nullptr),
    297       route_change_observer_(nullptr) {
    298   LOGI() << "ctor" << ios::GetCurrentThreadDescription();
    299 }
    300 
    301 AudioDeviceIOS::~AudioDeviceIOS() {
    302   LOGI() << "~dtor" << ios::GetCurrentThreadDescription();
    303   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    304   Terminate();
    305 }
    306 
    307 void AudioDeviceIOS::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
    308   LOGI() << "AttachAudioBuffer";
    309   RTC_DCHECK(audioBuffer);
    310   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    311   audio_device_buffer_ = audioBuffer;
    312 }
    313 
    314 int32_t AudioDeviceIOS::Init() {
    315   LOGI() << "Init";
    316   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    317   if (initialized_) {
    318     return 0;
    319   }
    320 #if !defined(NDEBUG)
    321   LogDeviceInfo();
    322 #endif
    323   // Store the preferred sample rate and preferred number of channels already
    324   // here. They have not been set and confirmed yet since ActivateAudioSession()
    325   // is not called until audio is about to start. However, it makes sense to
    326   // store the parameters now and then verify at a later stage.
    327   playout_parameters_.reset(kPreferredSampleRate, kPreferredNumberOfChannels);
    328   record_parameters_.reset(kPreferredSampleRate, kPreferredNumberOfChannels);
    329   // Ensure that the audio device buffer (ADB) knows about the internal audio
    330   // parameters. Note that, even if we are unable to get a mono audio session,
    331   // we will always tell the I/O audio unit to do a channel format conversion
    332   // to guarantee mono on the "input side" of the audio unit.
    333   UpdateAudioDeviceBuffer();
    334   initialized_ = true;
    335   return 0;
    336 }
    337 
    338 int32_t AudioDeviceIOS::Terminate() {
    339   LOGI() << "Terminate";
    340   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    341   if (!initialized_) {
    342     return 0;
    343   }
    344   StopPlayout();
    345   StopRecording();
    346   initialized_ = false;
    347   {
    348     rtc::GlobalLockScope ls(&g_lock);
    349     if (g_audio_session_users != 0) {
    350       LOG(LS_WARNING) << "Object is destructed with an active audio session";
    351     }
    352     RTC_DCHECK_GE(g_audio_session_users, 0);
    353   }
    354   return 0;
    355 }
    356 
    357 int32_t AudioDeviceIOS::InitPlayout() {
    358   LOGI() << "InitPlayout";
    359   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    360   RTC_DCHECK(initialized_);
    361   RTC_DCHECK(!play_is_initialized_);
    362   RTC_DCHECK(!playing_);
    363   if (!rec_is_initialized_) {
    364     if (!InitPlayOrRecord()) {
    365       LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitPlayout!";
    366       return -1;
    367     }
    368   }
    369   play_is_initialized_ = true;
    370   return 0;
    371 }
    372 
    373 int32_t AudioDeviceIOS::InitRecording() {
    374   LOGI() << "InitRecording";
    375   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    376   RTC_DCHECK(initialized_);
    377   RTC_DCHECK(!rec_is_initialized_);
    378   RTC_DCHECK(!recording_);
    379   if (!play_is_initialized_) {
    380     if (!InitPlayOrRecord()) {
    381       LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitRecording!";
    382       return -1;
    383     }
    384   }
    385   rec_is_initialized_ = true;
    386   return 0;
    387 }
    388 
    389 int32_t AudioDeviceIOS::StartPlayout() {
    390   LOGI() << "StartPlayout";
    391   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    392   RTC_DCHECK(play_is_initialized_);
    393   RTC_DCHECK(!playing_);
    394   fine_audio_buffer_->ResetPlayout();
    395   if (!recording_) {
    396     OSStatus result = AudioOutputUnitStart(vpio_unit_);
    397     if (result != noErr) {
    398       LOG_F(LS_ERROR) << "AudioOutputUnitStart failed for StartPlayout: "
    399                       << result;
    400       return -1;
    401     }
    402     LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started";
    403   }
    404   rtc::AtomicOps::ReleaseStore(&playing_, 1);
    405   return 0;
    406 }
    407 
    408 int32_t AudioDeviceIOS::StopPlayout() {
    409   LOGI() << "StopPlayout";
    410   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    411   if (!play_is_initialized_ || !playing_) {
    412     return 0;
    413   }
    414   if (!recording_) {
    415     ShutdownPlayOrRecord();
    416   }
    417   play_is_initialized_ = false;
    418   rtc::AtomicOps::ReleaseStore(&playing_, 0);
    419   return 0;
    420 }
    421 
    422 int32_t AudioDeviceIOS::StartRecording() {
    423   LOGI() << "StartRecording";
    424   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    425   RTC_DCHECK(rec_is_initialized_);
    426   RTC_DCHECK(!recording_);
    427   fine_audio_buffer_->ResetRecord();
    428   if (!playing_) {
    429     OSStatus result = AudioOutputUnitStart(vpio_unit_);
    430     if (result != noErr) {
    431       LOG_F(LS_ERROR) << "AudioOutputUnitStart failed for StartRecording: "
    432                       << result;
    433       return -1;
    434     }
    435     LOG(LS_INFO) << "Voice-Processing I/O audio unit is now started";
    436   }
    437   rtc::AtomicOps::ReleaseStore(&recording_, 1);
    438   return 0;
    439 }
    440 
    441 int32_t AudioDeviceIOS::StopRecording() {
    442   LOGI() << "StopRecording";
    443   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    444   if (!rec_is_initialized_ || !recording_) {
    445     return 0;
    446   }
    447   if (!playing_) {
    448     ShutdownPlayOrRecord();
    449   }
    450   rec_is_initialized_ = false;
    451   rtc::AtomicOps::ReleaseStore(&recording_, 0);
    452   return 0;
    453 }
    454 
    455 // Change the default receiver playout route to speaker.
    456 int32_t AudioDeviceIOS::SetLoudspeakerStatus(bool enable) {
    457   LOGI() << "SetLoudspeakerStatus(" << enable << ")";
    458 
    459   AVAudioSession* session = [AVAudioSession sharedInstance];
    460   NSString* category = session.category;
    461   AVAudioSessionCategoryOptions options = session.categoryOptions;
    462   // Respect old category options if category is
    463   // AVAudioSessionCategoryPlayAndRecord. Otherwise reset it since old options
    464   // might not be valid for this category.
    465   if ([category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) {
    466     if (enable) {
    467       options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
    468     } else {
    469       options &= ~AVAudioSessionCategoryOptionDefaultToSpeaker;
    470     }
    471   } else {
    472     options = AVAudioSessionCategoryOptionDefaultToSpeaker;
    473   }
    474   NSError* error = nil;
    475   BOOL success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
    476                           withOptions:options
    477                                 error:&error];
    478   ios::CheckAndLogError(success, error);
    479   return (error == nil) ? 0 : -1;
    480 }
    481 
    482 int32_t AudioDeviceIOS::GetLoudspeakerStatus(bool& enabled) const {
    483   LOGI() << "GetLoudspeakerStatus";
    484   AVAudioSession* session = [AVAudioSession sharedInstance];
    485   AVAudioSessionCategoryOptions options = session.categoryOptions;
    486   enabled = options & AVAudioSessionCategoryOptionDefaultToSpeaker;
    487   return 0;
    488 }
    489 
    490 int32_t AudioDeviceIOS::PlayoutDelay(uint16_t& delayMS) const {
    491   delayMS = kFixedPlayoutDelayEstimate;
    492   return 0;
    493 }
    494 
    495 int32_t AudioDeviceIOS::RecordingDelay(uint16_t& delayMS) const {
    496   delayMS = kFixedRecordDelayEstimate;
    497   return 0;
    498 }
    499 
    500 int AudioDeviceIOS::GetPlayoutAudioParameters(AudioParameters* params) const {
    501   LOGI() << "GetPlayoutAudioParameters";
    502   RTC_DCHECK(playout_parameters_.is_valid());
    503   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    504   *params = playout_parameters_;
    505   return 0;
    506 }
    507 
    508 int AudioDeviceIOS::GetRecordAudioParameters(AudioParameters* params) const {
    509   LOGI() << "GetRecordAudioParameters";
    510   RTC_DCHECK(record_parameters_.is_valid());
    511   RTC_DCHECK(thread_checker_.CalledOnValidThread());
    512   *params = record_parameters_;
    513   return 0;
    514 }
    515 
    516 void AudioDeviceIOS::UpdateAudioDeviceBuffer() {
    517   LOGI() << "UpdateAudioDevicebuffer";
    518   // AttachAudioBuffer() is called at construction by the main class but check
    519   // just in case.
    520   RTC_DCHECK(audio_device_buffer_) << "AttachAudioBuffer must be called first";
    521   // Inform the audio device buffer (ADB) about the new audio format.
    522   audio_device_buffer_->SetPlayoutSampleRate(playout_parameters_.sample_rate());
    523   audio_device_buffer_->SetPlayoutChannels(playout_parameters_.channels());
    524   audio_device_buffer_->SetRecordingSampleRate(
    525       record_parameters_.sample_rate());
    526   audio_device_buffer_->SetRecordingChannels(record_parameters_.channels());
    527 }
    528 
    529 void AudioDeviceIOS::RegisterNotificationObservers() {
    530   LOGI() << "RegisterNotificationObservers";
    531   // This code block will be called when AVAudioSessionInterruptionNotification
    532   // is observed.
    533   void (^interrupt_block)(NSNotification*) = ^(NSNotification* notification) {
    534     NSNumber* type_number =
    535         notification.userInfo[AVAudioSessionInterruptionTypeKey];
    536     AVAudioSessionInterruptionType type =
    537         (AVAudioSessionInterruptionType)type_number.unsignedIntegerValue;
    538     LOG(LS_INFO) << "Audio session interruption:";
    539     switch (type) {
    540       case AVAudioSessionInterruptionTypeBegan:
    541         // The system has deactivated our audio session.
    542         // Stop the active audio unit.
    543         LOG(LS_INFO) << " Began => stopping the audio unit";
    544         LOG_IF_ERROR(AudioOutputUnitStop(vpio_unit_),
    545                      "Failed to stop the the Voice-Processing I/O unit");
    546         break;
    547       case AVAudioSessionInterruptionTypeEnded:
    548         // The interruption has ended. Restart the audio session and start the
    549         // initialized audio unit again.
    550         LOG(LS_INFO) << " Ended => restarting audio session and audio unit";
    551         NSError* error = nil;
    552         BOOL success = NO;
    553         AVAudioSession* session = [AVAudioSession sharedInstance];
    554         success = [session setActive:YES error:&error];
    555         if (CheckAndLogError(success, error)) {
    556           LOG_IF_ERROR(AudioOutputUnitStart(vpio_unit_),
    557                        "Failed to start the the Voice-Processing I/O unit");
    558         }
    559         break;
    560     }
    561   };
    562 
    563   // This code block will be called when AVAudioSessionRouteChangeNotification
    564   // is observed.
    565   void (^route_change_block)(NSNotification*) =
    566       ^(NSNotification* notification) {
    567         // Get reason for current route change.
    568         NSNumber* reason_number =
    569             notification.userInfo[AVAudioSessionRouteChangeReasonKey];
    570         AVAudioSessionRouteChangeReason reason =
    571             (AVAudioSessionRouteChangeReason)reason_number.unsignedIntegerValue;
    572         bool valid_route_change = true;
    573         LOG(LS_INFO) << "Route change:";
    574         switch (reason) {
    575           case AVAudioSessionRouteChangeReasonUnknown:
    576             LOG(LS_INFO) << " ReasonUnknown";
    577             break;
    578           case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
    579             LOG(LS_INFO) << " NewDeviceAvailable";
    580             break;
    581           case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
    582             LOG(LS_INFO) << " OldDeviceUnavailable";
    583             break;
    584           case AVAudioSessionRouteChangeReasonCategoryChange:
    585             // It turns out that we see this notification (at least in iOS 9.2)
    586             // when making a switch from a BT device to e.g. Speaker using the
    587             // iOS Control Center and that we therefore must check if the sample
    588             // rate has changed. And if so is the case, restart the audio unit.
    589             LOG(LS_INFO) << " CategoryChange";
    590             LOG(LS_INFO) << " New category: " << ios::GetAudioSessionCategory();
    591             break;
    592           case AVAudioSessionRouteChangeReasonOverride:
    593             LOG(LS_INFO) << " Override";
    594             break;
    595           case AVAudioSessionRouteChangeReasonWakeFromSleep:
    596             LOG(LS_INFO) << " WakeFromSleep";
    597             break;
    598           case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
    599             LOG(LS_INFO) << " NoSuitableRouteForCategory";
    600             break;
    601           case AVAudioSessionRouteChangeReasonRouteConfigurationChange:
    602             // The set of input and output ports has not changed, but their
    603             // configuration has, e.g., a ports selected data source has
    604             // changed. Ignore this type of route change since we are focusing
    605             // on detecting headset changes.
    606             LOG(LS_INFO) << " RouteConfigurationChange (ignored)";
    607             valid_route_change = false;
    608             break;
    609         }
    610 
    611         if (valid_route_change) {
    612           // Log previous route configuration.
    613           AVAudioSessionRouteDescription* prev_route =
    614               notification.userInfo[AVAudioSessionRouteChangePreviousRouteKey];
    615           LOG(LS_INFO) << "Previous route:";
    616           LOG(LS_INFO) << ios::StdStringFromNSString(
    617               [NSString stringWithFormat:@"%@", prev_route]);
    618 
    619           // Only restart audio for a valid route change and if the
    620           // session sample rate has changed.
    621           AVAudioSession* session = [AVAudioSession sharedInstance];
    622           const double session_sample_rate = session.sampleRate;
    623           LOG(LS_INFO) << "session sample rate: " << session_sample_rate;
    624           if (playout_parameters_.sample_rate() != session_sample_rate) {
    625             if (!RestartAudioUnitWithNewFormat(session_sample_rate)) {
    626               LOG(LS_ERROR) << "Audio restart failed";
    627             }
    628           }
    629         }
    630       };
    631 
    632   // Get the default notification center of the current process.
    633   NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
    634 
    635   // Add AVAudioSessionInterruptionNotification observer.
    636   id interruption_observer =
    637       [center addObserverForName:AVAudioSessionInterruptionNotification
    638                           object:nil
    639                            queue:[NSOperationQueue mainQueue]
    640                       usingBlock:interrupt_block];
    641   // Add AVAudioSessionRouteChangeNotification observer.
    642   id route_change_observer =
    643       [center addObserverForName:AVAudioSessionRouteChangeNotification
    644                           object:nil
    645                            queue:[NSOperationQueue mainQueue]
    646                       usingBlock:route_change_block];
    647 
    648   // Increment refcount on observers using ARC bridge. Instance variable is a
    649   // void* instead of an id because header is included in other pure C++
    650   // files.
    651   audio_interruption_observer_ = (__bridge_retained void*)interruption_observer;
    652   route_change_observer_ = (__bridge_retained void*)route_change_observer;
    653 }
    654 
    655 void AudioDeviceIOS::UnregisterNotificationObservers() {
    656   LOGI() << "UnregisterNotificationObservers";
    657   // Transfer ownership of observer back to ARC, which will deallocate the
    658   // observer once it exits this scope.
    659   NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
    660   if (audio_interruption_observer_ != nullptr) {
    661     id observer = (__bridge_transfer id)audio_interruption_observer_;
    662     [center removeObserver:observer];
    663     audio_interruption_observer_ = nullptr;
    664   }
    665   if (route_change_observer_ != nullptr) {
    666     id observer = (__bridge_transfer id)route_change_observer_;
    667     [center removeObserver:observer];
    668     route_change_observer_ = nullptr;
    669   }
    670 }
    671 
    672 void AudioDeviceIOS::SetupAudioBuffersForActiveAudioSession() {
    673   LOGI() << "SetupAudioBuffersForActiveAudioSession";
    674   // Verify the current values once the audio session has been activated.
    675   AVAudioSession* session = [AVAudioSession sharedInstance];
    676   LOG(LS_INFO) << " sample rate: " << session.sampleRate;
    677   LOG(LS_INFO) << " IO buffer duration: " << session.IOBufferDuration;
    678   LOG(LS_INFO) << " output channels: " << session.outputNumberOfChannels;
    679   LOG(LS_INFO) << " input channels: " << session.inputNumberOfChannels;
    680   LOG(LS_INFO) << " output latency: " << session.outputLatency;
    681   LOG(LS_INFO) << " input latency: " << session.inputLatency;
    682 
    683   // Log a warning message for the case when we are unable to set the preferred
    684   // hardware sample rate but continue and use the non-ideal sample rate after
    685   // reinitializing the audio parameters. Most BT headsets only support 8kHz or
    686   // 16kHz.
    687   if (session.sampleRate != kPreferredSampleRate) {
    688     LOG(LS_WARNING) << "Unable to set the preferred sample rate";
    689   }
    690 
    691   // At this stage, we also know the exact IO buffer duration and can add
    692   // that info to the existing audio parameters where it is converted into
    693   // number of audio frames.
    694   // Example: IO buffer size = 0.008 seconds <=> 128 audio frames at 16kHz.
    695   // Hence, 128 is the size we expect to see in upcoming render callbacks.
    696   playout_parameters_.reset(session.sampleRate, playout_parameters_.channels(),
    697                             session.IOBufferDuration);
    698   RTC_DCHECK(playout_parameters_.is_complete());
    699   record_parameters_.reset(session.sampleRate, record_parameters_.channels(),
    700                            session.IOBufferDuration);
    701   RTC_DCHECK(record_parameters_.is_complete());
    702   LOG(LS_INFO) << " frames per I/O buffer: "
    703                << playout_parameters_.frames_per_buffer();
    704   LOG(LS_INFO) << " bytes per I/O buffer: "
    705                << playout_parameters_.GetBytesPerBuffer();
    706   RTC_DCHECK_EQ(playout_parameters_.GetBytesPerBuffer(),
    707                 record_parameters_.GetBytesPerBuffer());
    708 
    709   // Update the ADB parameters since the sample rate might have changed.
    710   UpdateAudioDeviceBuffer();
    711 
    712   // Create a modified audio buffer class which allows us to ask for,
    713   // or deliver, any number of samples (and not only multiple of 10ms) to match
    714   // the native audio unit buffer size.
    715   RTC_DCHECK(audio_device_buffer_);
    716   fine_audio_buffer_.reset(new FineAudioBuffer(
    717       audio_device_buffer_, playout_parameters_.GetBytesPerBuffer(),
    718       playout_parameters_.sample_rate()));
    719 
    720   // The extra/temporary playoutbuffer must be of this size to avoid
    721   // unnecessary memcpy while caching data between successive callbacks.
    722   const int required_playout_buffer_size =
    723       fine_audio_buffer_->RequiredPlayoutBufferSizeBytes();
    724   LOG(LS_INFO) << " required playout buffer size: "
    725                << required_playout_buffer_size;
    726   playout_audio_buffer_.reset(new SInt8[required_playout_buffer_size]);
    727 
    728   // Allocate AudioBuffers to be used as storage for the received audio.
    729   // The AudioBufferList structure works as a placeholder for the
    730   // AudioBuffer structure, which holds a pointer to the actual data buffer
    731   // in |record_audio_buffer_|. Recorded audio will be rendered into this memory
    732   // at each input callback when calling AudioUnitRender().
    733   const int data_byte_size = record_parameters_.GetBytesPerBuffer();
    734   record_audio_buffer_.reset(new SInt8[data_byte_size]);
    735   audio_record_buffer_list_.mNumberBuffers = 1;
    736   AudioBuffer* audio_buffer = &audio_record_buffer_list_.mBuffers[0];
    737   audio_buffer->mNumberChannels = record_parameters_.channels();
    738   audio_buffer->mDataByteSize = data_byte_size;
    739   audio_buffer->mData = record_audio_buffer_.get();
    740 }
    741 
    742 bool AudioDeviceIOS::SetupAndInitializeVoiceProcessingAudioUnit() {
    743   LOGI() << "SetupAndInitializeVoiceProcessingAudioUnit";
    744   RTC_DCHECK(!vpio_unit_) << "VoiceProcessingIO audio unit already exists";
    745   // Create an audio component description to identify the Voice-Processing
    746   // I/O audio unit.
    747   AudioComponentDescription vpio_unit_description;
    748   vpio_unit_description.componentType = kAudioUnitType_Output;
    749   vpio_unit_description.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
    750   vpio_unit_description.componentManufacturer = kAudioUnitManufacturer_Apple;
    751   vpio_unit_description.componentFlags = 0;
    752   vpio_unit_description.componentFlagsMask = 0;
    753 
    754   // Obtain an audio unit instance given the description.
    755   AudioComponent found_vpio_unit_ref =
    756       AudioComponentFindNext(nullptr, &vpio_unit_description);
    757 
    758   // Create a Voice-Processing IO audio unit.
    759   OSStatus result = noErr;
    760   result = AudioComponentInstanceNew(found_vpio_unit_ref, &vpio_unit_);
    761   if (result != noErr) {
    762     vpio_unit_ = nullptr;
    763     LOG(LS_ERROR) << "AudioComponentInstanceNew failed: " << result;
    764     return false;
    765   }
    766 
    767   // A VP I/O unit's bus 1 connects to input hardware (microphone). Enable
    768   // input on the input scope of the input element.
    769   AudioUnitElement input_bus = 1;
    770   UInt32 enable_input = 1;
    771   result = AudioUnitSetProperty(vpio_unit_, kAudioOutputUnitProperty_EnableIO,
    772                                 kAudioUnitScope_Input, input_bus, &enable_input,
    773                                 sizeof(enable_input));
    774   if (result != noErr) {
    775     DisposeAudioUnit();
    776     LOG(LS_ERROR) << "Failed to enable input on input scope of input element: "
    777                   << result;
    778     return false;
    779   }
    780 
    781   // A VP I/O unit's bus 0 connects to output hardware (speaker). Enable
    782   // output on the output scope of the output element.
    783   AudioUnitElement output_bus = 0;
    784   UInt32 enable_output = 1;
    785   result = AudioUnitSetProperty(vpio_unit_, kAudioOutputUnitProperty_EnableIO,
    786                                 kAudioUnitScope_Output, output_bus,
    787                                 &enable_output, sizeof(enable_output));
    788   if (result != noErr) {
    789     DisposeAudioUnit();
    790     LOG(LS_ERROR)
    791         << "Failed to enable output on output scope of output element: "
    792         << result;
    793     return false;
    794   }
    795 
    796   // Set the application formats for input and output:
    797   // - use same format in both directions
    798   // - avoid resampling in the I/O unit by using the hardware sample rate
    799   // - linear PCM => noncompressed audio data format with one frame per packet
    800   // - no need to specify interleaving since only mono is supported
    801   AudioStreamBasicDescription application_format = {0};
    802   UInt32 size = sizeof(application_format);
    803   RTC_DCHECK_EQ(playout_parameters_.sample_rate(),
    804                 record_parameters_.sample_rate());
    805   RTC_DCHECK_EQ(1, kPreferredNumberOfChannels);
    806   application_format.mSampleRate = playout_parameters_.sample_rate();
    807   application_format.mFormatID = kAudioFormatLinearPCM;
    808   application_format.mFormatFlags =
    809       kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    810   application_format.mBytesPerPacket = kBytesPerSample;
    811   application_format.mFramesPerPacket = 1;  // uncompressed
    812   application_format.mBytesPerFrame = kBytesPerSample;
    813   application_format.mChannelsPerFrame = kPreferredNumberOfChannels;
    814   application_format.mBitsPerChannel = 8 * kBytesPerSample;
    815   // Store the new format.
    816   application_format_ = application_format;
    817 #if !defined(NDEBUG)
    818   LogABSD(application_format_);
    819 #endif
    820 
    821   // Set the application format on the output scope of the input element/bus.
    822   result = AudioUnitSetProperty(vpio_unit_, kAudioUnitProperty_StreamFormat,
    823                                 kAudioUnitScope_Output, input_bus,
    824                                 &application_format, size);
    825   if (result != noErr) {
    826     DisposeAudioUnit();
    827     LOG(LS_ERROR)
    828         << "Failed to set application format on output scope of input bus: "
    829         << result;
    830     return false;
    831   }
    832 
    833   // Set the application format on the input scope of the output element/bus.
    834   result = AudioUnitSetProperty(vpio_unit_, kAudioUnitProperty_StreamFormat,
    835                                 kAudioUnitScope_Input, output_bus,
    836                                 &application_format, size);
    837   if (result != noErr) {
    838     DisposeAudioUnit();
    839     LOG(LS_ERROR)
    840         << "Failed to set application format on input scope of output bus: "
    841         << result;
    842     return false;
    843   }
    844 
    845   // Specify the callback function that provides audio samples to the audio
    846   // unit.
    847   AURenderCallbackStruct render_callback;
    848   render_callback.inputProc = GetPlayoutData;
    849   render_callback.inputProcRefCon = this;
    850   result = AudioUnitSetProperty(
    851       vpio_unit_, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
    852       output_bus, &render_callback, sizeof(render_callback));
    853   if (result != noErr) {
    854     DisposeAudioUnit();
    855     LOG(LS_ERROR) << "Failed to specify the render callback on the output bus: "
    856                   << result;
    857     return false;
    858   }
    859 
    860   // Disable AU buffer allocation for the recorder, we allocate our own.
    861   // TODO(henrika): not sure that it actually saves resource to make this call.
    862   UInt32 flag = 0;
    863   result = AudioUnitSetProperty(
    864       vpio_unit_, kAudioUnitProperty_ShouldAllocateBuffer,
    865       kAudioUnitScope_Output, input_bus, &flag, sizeof(flag));
    866   if (result != noErr) {
    867     DisposeAudioUnit();
    868     LOG(LS_ERROR) << "Failed to disable buffer allocation on the input bus: "
    869                   << result;
    870   }
    871 
    872   // Specify the callback to be called by the I/O thread to us when input audio
    873   // is available. The recorded samples can then be obtained by calling the
    874   // AudioUnitRender() method.
    875   AURenderCallbackStruct input_callback;
    876   input_callback.inputProc = RecordedDataIsAvailable;
    877   input_callback.inputProcRefCon = this;
    878   result = AudioUnitSetProperty(vpio_unit_,
    879                                 kAudioOutputUnitProperty_SetInputCallback,
    880                                 kAudioUnitScope_Global, input_bus,
    881                                 &input_callback, sizeof(input_callback));
    882   if (result != noErr) {
    883     DisposeAudioUnit();
    884     LOG(LS_ERROR) << "Failed to specify the input callback on the input bus: "
    885                   << result;
    886   }
    887 
    888   // Initialize the Voice-Processing I/O unit instance.
    889   // Calls to AudioUnitInitialize() can fail if called back-to-back on
    890   // different ADM instances. The error message in this case is -66635 which is
    891   // undocumented. Tests have shown that calling AudioUnitInitialize a second
    892   // time, after a short sleep, avoids this issue.
    893   // See webrtc:5166 for details.
    894   int failed_initalize_attempts = 0;
    895   result = AudioUnitInitialize(vpio_unit_);
    896   while (result != noErr) {
    897     LOG(LS_ERROR) << "Failed to initialize the Voice-Processing I/O unit: "
    898                   << result;
    899     ++failed_initalize_attempts;
    900     if (failed_initalize_attempts == kMaxNumberOfAudioUnitInitializeAttempts) {
    901       // Max number of initialization attempts exceeded, hence abort.
    902       LOG(LS_WARNING) << "Too many initialization attempts";
    903       DisposeAudioUnit();
    904       return false;
    905     }
    906     LOG(LS_INFO) << "pause 100ms and try audio unit initialization again...";
    907     [NSThread sleepForTimeInterval:0.1f];
    908     result = AudioUnitInitialize(vpio_unit_);
    909   }
    910   LOG(LS_INFO) << "Voice-Processing I/O unit is now initialized";
    911   return true;
    912 }
    913 
    914 bool AudioDeviceIOS::RestartAudioUnitWithNewFormat(float sample_rate) {
    915   LOGI() << "RestartAudioUnitWithNewFormat(sample_rate=" << sample_rate << ")";
    916   // Stop the active audio unit.
    917   LOG_AND_RETURN_IF_ERROR(AudioOutputUnitStop(vpio_unit_),
    918                           "Failed to stop the the Voice-Processing I/O unit");
    919 
    920   // The stream format is about to be changed and it requires that we first
    921   // uninitialize it to deallocate its resources.
    922   LOG_AND_RETURN_IF_ERROR(
    923       AudioUnitUninitialize(vpio_unit_),
    924       "Failed to uninitialize the the Voice-Processing I/O unit");
    925 
    926   // Allocate new buffers given the new stream format.
    927   SetupAudioBuffersForActiveAudioSession();
    928 
    929   // Update the existing application format using the new sample rate.
    930   application_format_.mSampleRate = playout_parameters_.sample_rate();
    931   UInt32 size = sizeof(application_format_);
    932   AudioUnitSetProperty(vpio_unit_, kAudioUnitProperty_StreamFormat,
    933                        kAudioUnitScope_Output, 1, &application_format_, size);
    934   AudioUnitSetProperty(vpio_unit_, kAudioUnitProperty_StreamFormat,
    935                        kAudioUnitScope_Input, 0, &application_format_, size);
    936 
    937   // Prepare the audio unit to render audio again.
    938   LOG_AND_RETURN_IF_ERROR(AudioUnitInitialize(vpio_unit_),
    939                           "Failed to initialize the Voice-Processing I/O unit");
    940   LOG(LS_INFO) << "Voice-Processing I/O unit is now reinitialized";
    941 
    942   // Start rendering audio using the new format.
    943   LOG_AND_RETURN_IF_ERROR(AudioOutputUnitStart(vpio_unit_),
    944                           "Failed to start the Voice-Processing I/O unit");
    945   LOG(LS_INFO) << "Voice-Processing I/O unit is now restarted";
    946   return true;
    947 }
    948 
    949 bool AudioDeviceIOS::InitPlayOrRecord() {
    950   LOGI() << "InitPlayOrRecord";
    951   // Activate the audio session if not already activated.
    952   if (!ActivateAudioSession()) {
    953     return false;
    954   }
    955 
    956   // Ensure that the active audio session has the correct category and mode.
    957   AVAudioSession* session = [AVAudioSession sharedInstance];
    958   if (!VerifyAudioSession(session)) {
    959     DeactivateAudioSession();
    960     LOG(LS_ERROR) << "Failed to verify audio session category and mode";
    961     return false;
    962   }
    963 
    964   // Start observing audio session interruptions and route changes.
    965   RegisterNotificationObservers();
    966 
    967   // Ensure that we got what what we asked for in our active audio session.
    968   SetupAudioBuffersForActiveAudioSession();
    969 
    970   // Create, setup and initialize a new Voice-Processing I/O unit.
    971   if (!SetupAndInitializeVoiceProcessingAudioUnit()) {
    972     // Reduce usage count for the audio session and possibly deactivate it if
    973     // this object is the only user.
    974     DeactivateAudioSession();
    975     return false;
    976   }
    977   return true;
    978 }
    979 
    980 void AudioDeviceIOS::ShutdownPlayOrRecord() {
    981   LOGI() << "ShutdownPlayOrRecord";
    982   // Close and delete the voice-processing I/O unit.
    983   OSStatus result = -1;
    984   if (nullptr != vpio_unit_) {
    985     result = AudioOutputUnitStop(vpio_unit_);
    986     if (result != noErr) {
    987       LOG_F(LS_ERROR) << "AudioOutputUnitStop failed: " << result;
    988     }
    989     result = AudioUnitUninitialize(vpio_unit_);
    990     if (result != noErr) {
    991       LOG_F(LS_ERROR) << "AudioUnitUninitialize failed: " << result;
    992     }
    993     DisposeAudioUnit();
    994   }
    995 
    996   // Remove audio session notification observers.
    997   UnregisterNotificationObservers();
    998 
    999   // All I/O should be stopped or paused prior to deactivating the audio
   1000   // session, hence we deactivate as last action.
   1001   DeactivateAudioSession();
   1002 }
   1003 
   1004 void AudioDeviceIOS::DisposeAudioUnit() {
   1005   if (nullptr == vpio_unit_)
   1006     return;
   1007   OSStatus result = AudioComponentInstanceDispose(vpio_unit_);
   1008   if (result != noErr) {
   1009     LOG(LS_ERROR) << "AudioComponentInstanceDispose failed:" << result;
   1010   }
   1011   vpio_unit_ = nullptr;
   1012 }
   1013 
   1014 OSStatus AudioDeviceIOS::RecordedDataIsAvailable(
   1015     void* in_ref_con,
   1016     AudioUnitRenderActionFlags* io_action_flags,
   1017     const AudioTimeStamp* in_time_stamp,
   1018     UInt32 in_bus_number,
   1019     UInt32 in_number_frames,
   1020     AudioBufferList* io_data) {
   1021   RTC_DCHECK_EQ(1u, in_bus_number);
   1022   RTC_DCHECK(
   1023       !io_data);  // no buffer should be allocated for input at this stage
   1024   AudioDeviceIOS* audio_device_ios = static_cast<AudioDeviceIOS*>(in_ref_con);
   1025   return audio_device_ios->OnRecordedDataIsAvailable(
   1026       io_action_flags, in_time_stamp, in_bus_number, in_number_frames);
   1027 }
   1028 
   1029 OSStatus AudioDeviceIOS::OnRecordedDataIsAvailable(
   1030     AudioUnitRenderActionFlags* io_action_flags,
   1031     const AudioTimeStamp* in_time_stamp,
   1032     UInt32 in_bus_number,
   1033     UInt32 in_number_frames) {
   1034   OSStatus result = noErr;
   1035   // Simply return if recording is not enabled.
   1036   if (!rtc::AtomicOps::AcquireLoad(&recording_))
   1037     return result;
   1038   if (in_number_frames != record_parameters_.frames_per_buffer()) {
   1039     // We have seen short bursts (1-2 frames) where |in_number_frames| changes.
   1040     // Add a log to keep track of longer sequences if that should ever happen.
   1041     // Also return since calling AudioUnitRender in this state will only result
   1042     // in kAudio_ParamError (-50) anyhow.
   1043     LOG(LS_WARNING) << "in_number_frames (" << in_number_frames
   1044                     << ") != " << record_parameters_.frames_per_buffer();
   1045     return noErr;
   1046   }
   1047   // Obtain the recorded audio samples by initiating a rendering cycle.
   1048   // Since it happens on the input bus, the |io_data| parameter is a reference
   1049   // to the preallocated audio buffer list that the audio unit renders into.
   1050   // TODO(henrika): should error handling be improved?
   1051   AudioBufferList* io_data = &audio_record_buffer_list_;
   1052   result = AudioUnitRender(vpio_unit_, io_action_flags, in_time_stamp,
   1053                            in_bus_number, in_number_frames, io_data);
   1054   if (result != noErr) {
   1055     LOG_F(LS_ERROR) << "AudioUnitRender failed: " << result;
   1056     return result;
   1057   }
   1058   // Get a pointer to the recorded audio and send it to the WebRTC ADB.
   1059   // Use the FineAudioBuffer instance to convert between native buffer size
   1060   // and the 10ms buffer size used by WebRTC.
   1061   const UInt32 data_size_in_bytes = io_data->mBuffers[0].mDataByteSize;
   1062   RTC_CHECK_EQ(data_size_in_bytes / kBytesPerSample, in_number_frames);
   1063   SInt8* data = static_cast<SInt8*>(io_data->mBuffers[0].mData);
   1064   fine_audio_buffer_->DeliverRecordedData(data, data_size_in_bytes,
   1065                                           kFixedPlayoutDelayEstimate,
   1066                                           kFixedRecordDelayEstimate);
   1067   return noErr;
   1068 }
   1069 
   1070 OSStatus AudioDeviceIOS::GetPlayoutData(
   1071     void* in_ref_con,
   1072     AudioUnitRenderActionFlags* io_action_flags,
   1073     const AudioTimeStamp* in_time_stamp,
   1074     UInt32 in_bus_number,
   1075     UInt32 in_number_frames,
   1076     AudioBufferList* io_data) {
   1077   RTC_DCHECK_EQ(0u, in_bus_number);
   1078   RTC_DCHECK(io_data);
   1079   AudioDeviceIOS* audio_device_ios = static_cast<AudioDeviceIOS*>(in_ref_con);
   1080   return audio_device_ios->OnGetPlayoutData(io_action_flags, in_number_frames,
   1081                                             io_data);
   1082 }
   1083 
   1084 OSStatus AudioDeviceIOS::OnGetPlayoutData(
   1085     AudioUnitRenderActionFlags* io_action_flags,
   1086     UInt32 in_number_frames,
   1087     AudioBufferList* io_data) {
   1088   // Verify 16-bit, noninterleaved mono PCM signal format.
   1089   RTC_DCHECK_EQ(1u, io_data->mNumberBuffers);
   1090   RTC_DCHECK_EQ(1u, io_data->mBuffers[0].mNumberChannels);
   1091   // Get pointer to internal audio buffer to which new audio data shall be
   1092   // written.
   1093   const UInt32 dataSizeInBytes = io_data->mBuffers[0].mDataByteSize;
   1094   RTC_CHECK_EQ(dataSizeInBytes / kBytesPerSample, in_number_frames);
   1095   SInt8* destination = static_cast<SInt8*>(io_data->mBuffers[0].mData);
   1096   // Produce silence and give audio unit a hint about it if playout is not
   1097   // activated.
   1098   if (!rtc::AtomicOps::AcquireLoad(&playing_)) {
   1099     *io_action_flags |= kAudioUnitRenderAction_OutputIsSilence;
   1100     memset(destination, 0, dataSizeInBytes);
   1101     return noErr;
   1102   }
   1103   // Read decoded 16-bit PCM samples from WebRTC (using a size that matches
   1104   // the native I/O audio unit) to a preallocated intermediate buffer and
   1105   // copy the result to the audio buffer in the |io_data| destination.
   1106   SInt8* source = playout_audio_buffer_.get();
   1107   fine_audio_buffer_->GetPlayoutData(source);
   1108   memcpy(destination, source, dataSizeInBytes);
   1109   return noErr;
   1110 }
   1111 
   1112 }  // namespace webrtc
   1113