Home | History | Annotate | Download | only in mac
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/audio/mac/audio_low_latency_input_mac.h"
      6 
      7 #include <CoreServices/CoreServices.h>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/logging.h"
     11 #include "base/mac/mac_logging.h"
     12 #include "media/audio/audio_util.h"
     13 #include "media/audio/mac/audio_manager_mac.h"
     14 #include "media/base/data_buffer.h"
     15 
     16 namespace media {
     17 
     18 static const int kMinIntervalBetweenVolumeUpdatesMs = 1000;
     19 
     20 static std::ostream& operator<<(std::ostream& os,
     21                                 const AudioStreamBasicDescription& format) {
     22   os << "sample rate       : " << format.mSampleRate << std::endl
     23      << "format ID         : " << format.mFormatID << std::endl
     24      << "format flags      : " << format.mFormatFlags << std::endl
     25      << "bytes per packet  : " << format.mBytesPerPacket << std::endl
     26      << "frames per packet : " << format.mFramesPerPacket << std::endl
     27      << "bytes per frame   : " << format.mBytesPerFrame << std::endl
     28      << "channels per frame: " << format.mChannelsPerFrame << std::endl
     29      << "bits per channel  : " << format.mBitsPerChannel;
     30   return os;
     31 }
     32 
     33 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit"
     34 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
     35 // for more details and background regarding this implementation.
     36 
     37 AUAudioInputStream::AUAudioInputStream(
     38     AudioManagerMac* manager, const AudioParameters& params,
     39     AudioDeviceID audio_device_id)
     40     : manager_(manager),
     41       sink_(NULL),
     42       audio_unit_(0),
     43       input_device_id_(audio_device_id),
     44       started_(false),
     45       hardware_latency_frames_(0),
     46       fifo_delay_bytes_(0),
     47       number_of_channels_in_frame_(0) {
     48   DCHECK(manager_);
     49 
     50   // Set up the desired (output) format specified by the client.
     51   format_.mSampleRate = params.sample_rate();
     52   format_.mFormatID = kAudioFormatLinearPCM;
     53   format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
     54                          kLinearPCMFormatFlagIsSignedInteger;
     55   format_.mBitsPerChannel = params.bits_per_sample();
     56   format_.mChannelsPerFrame = params.channels();
     57   format_.mFramesPerPacket = 1;  // uncompressed audio
     58   format_.mBytesPerPacket = (format_.mBitsPerChannel *
     59                              params.channels()) / 8;
     60   format_.mBytesPerFrame = format_.mBytesPerPacket;
     61   format_.mReserved = 0;
     62 
     63   DVLOG(1) << "Desired ouput format: " << format_;
     64 
     65   // Set number of sample frames per callback used by the internal audio layer.
     66   // An internal FIFO is then utilized to adapt the internal size to the size
     67   // requested by the client.
     68   // Note that we use the same native buffer size as for the output side here
     69   // since the AUHAL implementation requires that both capture and render side
     70   // use the same buffer size. See http://crbug.com/154352 for more details.
     71   // TODO(xians): Get the audio parameters from the right device.
     72   const AudioParameters parameters =
     73       manager_->GetInputStreamParameters(AudioManagerBase::kDefaultDeviceId);
     74   number_of_frames_ = parameters.frames_per_buffer();
     75   DVLOG(1) << "Size of data buffer in frames : " << number_of_frames_;
     76 
     77   // Derive size (in bytes) of the buffers that we will render to.
     78   UInt32 data_byte_size = number_of_frames_ * format_.mBytesPerFrame;
     79   DVLOG(1) << "Size of data buffer in bytes : " << data_byte_size;
     80 
     81   // Allocate AudioBuffers to be used as storage for the received audio.
     82   // The AudioBufferList structure works as a placeholder for the
     83   // AudioBuffer structure, which holds a pointer to the actual data buffer.
     84   audio_data_buffer_.reset(new uint8[data_byte_size]);
     85   audio_buffer_list_.mNumberBuffers = 1;
     86 
     87   AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
     88   audio_buffer->mNumberChannels = params.channels();
     89   audio_buffer->mDataByteSize = data_byte_size;
     90   audio_buffer->mData = audio_data_buffer_.get();
     91 
     92   // Set up an internal FIFO buffer that will accumulate recorded audio frames
     93   // until a requested size is ready to be sent to the client.
     94   // It is not possible to ask for less than |kAudioFramesPerCallback| number of
     95   // audio frames.
     96   const size_t requested_size_frames =
     97       params.GetBytesPerBuffer() / format_.mBytesPerPacket;
     98   DCHECK_GE(requested_size_frames, number_of_frames_);
     99   requested_size_bytes_ = requested_size_frames * format_.mBytesPerFrame;
    100   DVLOG(1) << "Requested buffer size in bytes : " << requested_size_bytes_;
    101   DLOG_IF(INFO, requested_size_frames > number_of_frames_) << "FIFO is used";
    102 
    103   const int number_of_bytes = number_of_frames_ * format_.mBytesPerFrame;
    104   fifo_delay_bytes_ = requested_size_bytes_ - number_of_bytes;
    105 
    106   // Allocate some extra memory to avoid memory reallocations.
    107   // Ensure that the size is an even multiple of |number_of_frames_ and
    108   // larger than |requested_size_frames|.
    109   // Example: number_of_frames_=128, requested_size_frames=480 =>
    110   // allocated space equals 4*128=512 audio frames
    111   const int max_forward_capacity = number_of_bytes *
    112       ((requested_size_frames / number_of_frames_) + 1);
    113   fifo_.reset(new media::SeekableBuffer(0, max_forward_capacity));
    114 
    115   data_ = new media::DataBuffer(requested_size_bytes_);
    116 }
    117 
    118 AUAudioInputStream::~AUAudioInputStream() {}
    119 
    120 // Obtain and open the AUHAL AudioOutputUnit for recording.
    121 bool AUAudioInputStream::Open() {
    122   // Verify that we are not already opened.
    123   if (audio_unit_)
    124     return false;
    125 
    126   // Verify that we have a valid device.
    127   if (input_device_id_ == kAudioObjectUnknown) {
    128     NOTREACHED() << "Device ID is unknown";
    129     return false;
    130   }
    131 
    132   // Start by obtaining an AudioOuputUnit using an AUHAL component description.
    133 
    134   Component comp;
    135   ComponentDescription desc;
    136 
    137   // Description for the Audio Unit we want to use (AUHAL in this case).
    138   desc.componentType = kAudioUnitType_Output;
    139   desc.componentSubType = kAudioUnitSubType_HALOutput;
    140   desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    141   desc.componentFlags = 0;
    142   desc.componentFlagsMask = 0;
    143   comp = FindNextComponent(0, &desc);
    144   DCHECK(comp);
    145 
    146   // Get access to the service provided by the specified Audio Unit.
    147   OSStatus result = OpenAComponent(comp, &audio_unit_);
    148   if (result) {
    149     HandleError(result);
    150     return false;
    151   }
    152 
    153   // Enable IO on the input scope of the Audio Unit.
    154 
    155   // After creating the AUHAL object, we must enable IO on the input scope
    156   // of the Audio Unit to obtain the device input. Input must be explicitly
    157   // enabled with the kAudioOutputUnitProperty_EnableIO property on Element 1
    158   // of the AUHAL. Beacause the AUHAL can be used for both input and output,
    159   // we must also disable IO on the output scope.
    160 
    161   UInt32 enableIO = 1;
    162 
    163   // Enable input on the AUHAL.
    164   result = AudioUnitSetProperty(audio_unit_,
    165                                 kAudioOutputUnitProperty_EnableIO,
    166                                 kAudioUnitScope_Input,
    167                                 1,          // input element 1
    168                                 &enableIO,  // enable
    169                                 sizeof(enableIO));
    170   if (result) {
    171     HandleError(result);
    172     return false;
    173   }
    174 
    175   // Disable output on the AUHAL.
    176   enableIO = 0;
    177   result = AudioUnitSetProperty(audio_unit_,
    178                                 kAudioOutputUnitProperty_EnableIO,
    179                                 kAudioUnitScope_Output,
    180                                 0,          // output element 0
    181                                 &enableIO,  // disable
    182                                 sizeof(enableIO));
    183   if (result) {
    184     HandleError(result);
    185     return false;
    186   }
    187 
    188   // Next, set the audio device to be the Audio Unit's current device.
    189   // Note that, devices can only be set to the AUHAL after enabling IO.
    190   result = AudioUnitSetProperty(audio_unit_,
    191                                 kAudioOutputUnitProperty_CurrentDevice,
    192                                 kAudioUnitScope_Global,
    193                                 0,
    194                                 &input_device_id_,
    195                                 sizeof(input_device_id_));
    196   if (result) {
    197     HandleError(result);
    198     return false;
    199   }
    200 
    201   // Register the input procedure for the AUHAL.
    202   // This procedure will be called when the AUHAL has received new data
    203   // from the input device.
    204   AURenderCallbackStruct callback;
    205   callback.inputProc = InputProc;
    206   callback.inputProcRefCon = this;
    207   result = AudioUnitSetProperty(audio_unit_,
    208                                 kAudioOutputUnitProperty_SetInputCallback,
    209                                 kAudioUnitScope_Global,
    210                                 0,
    211                                 &callback,
    212                                 sizeof(callback));
    213   if (result) {
    214     HandleError(result);
    215     return false;
    216   }
    217 
    218   // Set up the the desired (output) format.
    219   // For obtaining input from a device, the device format is always expressed
    220   // on the output scope of the AUHAL's Element 1.
    221   result = AudioUnitSetProperty(audio_unit_,
    222                                 kAudioUnitProperty_StreamFormat,
    223                                 kAudioUnitScope_Output,
    224                                 1,
    225                                 &format_,
    226                                 sizeof(format_));
    227   if (result) {
    228     HandleError(result);
    229     return false;
    230   }
    231 
    232   // Set the desired number of frames in the IO buffer (output scope).
    233   // WARNING: Setting this value changes the frame size for all audio units in
    234   // the current process.  It's imperative that the input and output frame sizes
    235   // be the same as the frames_per_buffer() returned by
    236   // GetInputStreamParameters().
    237   // TODO(henrika): Due to http://crrev.com/159666 this is currently not true
    238   // and should be fixed, a CHECK() should be added at that time.
    239   result = AudioUnitSetProperty(audio_unit_,
    240                                 kAudioDevicePropertyBufferFrameSize,
    241                                 kAudioUnitScope_Output,
    242                                 1,
    243                                 &number_of_frames_,  // size is set in the ctor
    244                                 sizeof(number_of_frames_));
    245   if (result) {
    246     HandleError(result);
    247     return false;
    248   }
    249 
    250   // Finally, initialize the audio unit and ensure that it is ready to render.
    251   // Allocates memory according to the maximum number of audio frames
    252   // it can produce in response to a single render call.
    253   result = AudioUnitInitialize(audio_unit_);
    254   if (result) {
    255     HandleError(result);
    256     return false;
    257   }
    258 
    259   // The hardware latency is fixed and will not change during the call.
    260   hardware_latency_frames_ = GetHardwareLatency();
    261 
    262   // The master channel is 0, Left and right are channels 1 and 2.
    263   // And the master channel is not counted in |number_of_channels_in_frame_|.
    264   number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
    265 
    266   return true;
    267 }
    268 
    269 void AUAudioInputStream::Start(AudioInputCallback* callback) {
    270   DCHECK(callback);
    271   DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully";
    272   if (started_ || !audio_unit_)
    273     return;
    274   sink_ = callback;
    275   StartAgc();
    276   OSStatus result = AudioOutputUnitStart(audio_unit_);
    277   if (result == noErr) {
    278     started_ = true;
    279   }
    280   OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
    281       << "Failed to start acquiring data";
    282 }
    283 
    284 void AUAudioInputStream::Stop() {
    285   if (!started_)
    286     return;
    287   StopAgc();
    288   OSStatus result = AudioOutputUnitStop(audio_unit_);
    289   if (result == noErr) {
    290     started_ = false;
    291   }
    292   OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
    293       << "Failed to stop acquiring data";
    294 }
    295 
    296 void AUAudioInputStream::Close() {
    297   // It is valid to call Close() before calling open or Start().
    298   // It is also valid to call Close() after Start() has been called.
    299   if (started_) {
    300     Stop();
    301   }
    302   if (audio_unit_) {
    303     // Deallocate the audio units resources.
    304     AudioUnitUninitialize(audio_unit_);
    305 
    306     // Terminates our connection to the AUHAL component.
    307     CloseComponent(audio_unit_);
    308     audio_unit_ = 0;
    309   }
    310   if (sink_) {
    311     sink_->OnClose(this);
    312     sink_ = NULL;
    313   }
    314 
    315   // Inform the audio manager that we have been closed. This can cause our
    316   // destruction.
    317   manager_->ReleaseInputStream(this);
    318 }
    319 
    320 double AUAudioInputStream::GetMaxVolume() {
    321   // Verify that we have a valid device.
    322   if (input_device_id_ == kAudioObjectUnknown) {
    323     NOTREACHED() << "Device ID is unknown";
    324     return 0.0;
    325   }
    326 
    327   // Query if any of the master, left or right channels has volume control.
    328   for (int i = 0; i <= number_of_channels_in_frame_; ++i) {
    329     // If the volume is settable, the  valid volume range is [0.0, 1.0].
    330     if (IsVolumeSettableOnChannel(i))
    331       return 1.0;
    332   }
    333 
    334   // Volume control is not available for the audio stream.
    335   return 0.0;
    336 }
    337 
    338 void AUAudioInputStream::SetVolume(double volume) {
    339   DVLOG(1) << "SetVolume(volume=" << volume << ")";
    340   DCHECK_GE(volume, 0.0);
    341   DCHECK_LE(volume, 1.0);
    342 
    343   // Verify that we have a valid device.
    344   if (input_device_id_ == kAudioObjectUnknown) {
    345     NOTREACHED() << "Device ID is unknown";
    346     return;
    347   }
    348 
    349   Float32 volume_float32 = static_cast<Float32>(volume);
    350   AudioObjectPropertyAddress property_address = {
    351     kAudioDevicePropertyVolumeScalar,
    352     kAudioDevicePropertyScopeInput,
    353     kAudioObjectPropertyElementMaster
    354   };
    355 
    356   // Try to set the volume for master volume channel.
    357   if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
    358     OSStatus result = AudioObjectSetPropertyData(input_device_id_,
    359                                                  &property_address,
    360                                                  0,
    361                                                  NULL,
    362                                                  sizeof(volume_float32),
    363                                                  &volume_float32);
    364     if (result != noErr) {
    365       DLOG(WARNING) << "Failed to set volume to " << volume_float32;
    366     }
    367     return;
    368   }
    369 
    370   // There is no master volume control, try to set volume for each channel.
    371   int successful_channels = 0;
    372   for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
    373     property_address.mElement = static_cast<UInt32>(i);
    374     if (IsVolumeSettableOnChannel(i)) {
    375       OSStatus result = AudioObjectSetPropertyData(input_device_id_,
    376                                                    &property_address,
    377                                                    0,
    378                                                    NULL,
    379                                                    sizeof(volume_float32),
    380                                                    &volume_float32);
    381       if (result == noErr)
    382         ++successful_channels;
    383     }
    384   }
    385 
    386   DLOG_IF(WARNING, successful_channels == 0)
    387       << "Failed to set volume to " << volume_float32;
    388 
    389   // Update the AGC volume level based on the last setting above. Note that,
    390   // the volume-level resolution is not infinite and it is therefore not
    391   // possible to assume that the volume provided as input parameter can be
    392   // used directly. Instead, a new query to the audio hardware is required.
    393   // This method does nothing if AGC is disabled.
    394   UpdateAgcVolume();
    395 }
    396 
    397 double AUAudioInputStream::GetVolume() {
    398   // Verify that we have a valid device.
    399   if (input_device_id_ == kAudioObjectUnknown){
    400     NOTREACHED() << "Device ID is unknown";
    401     return 0.0;
    402   }
    403 
    404   AudioObjectPropertyAddress property_address = {
    405     kAudioDevicePropertyVolumeScalar,
    406     kAudioDevicePropertyScopeInput,
    407     kAudioObjectPropertyElementMaster
    408   };
    409 
    410   if (AudioObjectHasProperty(input_device_id_, &property_address)) {
    411     // The device supports master volume control, get the volume from the
    412     // master channel.
    413     Float32 volume_float32 = 0.0;
    414     UInt32 size = sizeof(volume_float32);
    415     OSStatus result = AudioObjectGetPropertyData(input_device_id_,
    416                                                  &property_address,
    417                                                  0,
    418                                                  NULL,
    419                                                  &size,
    420                                                  &volume_float32);
    421     if (result == noErr)
    422       return static_cast<double>(volume_float32);
    423   } else {
    424     // There is no master volume control, try to get the average volume of
    425     // all the channels.
    426     Float32 volume_float32 = 0.0;
    427     int successful_channels = 0;
    428     for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
    429       property_address.mElement = static_cast<UInt32>(i);
    430       if (AudioObjectHasProperty(input_device_id_, &property_address)) {
    431         Float32 channel_volume = 0;
    432         UInt32 size = sizeof(channel_volume);
    433         OSStatus result = AudioObjectGetPropertyData(input_device_id_,
    434                                                      &property_address,
    435                                                      0,
    436                                                      NULL,
    437                                                      &size,
    438                                                      &channel_volume);
    439         if (result == noErr) {
    440           volume_float32 += channel_volume;
    441           ++successful_channels;
    442         }
    443       }
    444     }
    445 
    446     // Get the average volume of the channels.
    447     if (successful_channels != 0)
    448       return static_cast<double>(volume_float32 / successful_channels);
    449   }
    450 
    451   DLOG(WARNING) << "Failed to get volume";
    452   return 0.0;
    453 }
    454 
    455 // AUHAL AudioDeviceOutput unit callback
    456 OSStatus AUAudioInputStream::InputProc(void* user_data,
    457                                        AudioUnitRenderActionFlags* flags,
    458                                        const AudioTimeStamp* time_stamp,
    459                                        UInt32 bus_number,
    460                                        UInt32 number_of_frames,
    461                                        AudioBufferList* io_data) {
    462   // Verify that the correct bus is used (Input bus/Element 1)
    463   DCHECK_EQ(bus_number, static_cast<UInt32>(1));
    464   AUAudioInputStream* audio_input =
    465       reinterpret_cast<AUAudioInputStream*>(user_data);
    466   DCHECK(audio_input);
    467   if (!audio_input)
    468     return kAudioUnitErr_InvalidElement;
    469 
    470   // Receive audio from the AUHAL from the output scope of the Audio Unit.
    471   OSStatus result = AudioUnitRender(audio_input->audio_unit(),
    472                                     flags,
    473                                     time_stamp,
    474                                     bus_number,
    475                                     number_of_frames,
    476                                     audio_input->audio_buffer_list());
    477   if (result)
    478     return result;
    479 
    480   // Deliver recorded data to the consumer as a callback.
    481   return audio_input->Provide(number_of_frames,
    482                               audio_input->audio_buffer_list(),
    483                               time_stamp);
    484 }
    485 
    486 OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
    487                                      AudioBufferList* io_data,
    488                                      const AudioTimeStamp* time_stamp) {
    489   // Update the capture latency.
    490   double capture_latency_frames = GetCaptureLatency(time_stamp);
    491 
    492   // The AGC volume level is updated once every second on a separate thread.
    493   // Note that, |volume| is also updated each time SetVolume() is called
    494   // through IPC by the render-side AGC.
    495   double normalized_volume = 0.0;
    496   GetAgcVolume(&normalized_volume);
    497 
    498   AudioBuffer& buffer = io_data->mBuffers[0];
    499   uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
    500   uint32 capture_delay_bytes = static_cast<uint32>
    501       ((capture_latency_frames + 0.5) * format_.mBytesPerFrame);
    502   // Account for the extra delay added by the FIFO.
    503   capture_delay_bytes += fifo_delay_bytes_;
    504   DCHECK(audio_data);
    505   if (!audio_data)
    506     return kAudioUnitErr_InvalidElement;
    507 
    508   // Accumulate captured audio in FIFO until we can match the output size
    509   // requested by the client.
    510   fifo_->Append(audio_data, buffer.mDataByteSize);
    511 
    512   // Deliver recorded data to the client as soon as the FIFO contains a
    513   // sufficient amount.
    514   if (fifo_->forward_bytes() >= requested_size_bytes_) {
    515     // Read from FIFO into temporary data buffer.
    516     fifo_->Read(data_->writable_data(), requested_size_bytes_);
    517 
    518     // Deliver data packet, delay estimation and volume level to the user.
    519     sink_->OnData(this,
    520                   data_->data(),
    521                   requested_size_bytes_,
    522                   capture_delay_bytes,
    523                   normalized_volume);
    524   }
    525 
    526   return noErr;
    527 }
    528 
    529 int AUAudioInputStream::HardwareSampleRate() {
    530   // Determine the default input device's sample-rate.
    531   AudioDeviceID device_id = kAudioObjectUnknown;
    532   UInt32 info_size = sizeof(device_id);
    533 
    534   AudioObjectPropertyAddress default_input_device_address = {
    535     kAudioHardwarePropertyDefaultInputDevice,
    536     kAudioObjectPropertyScopeGlobal,
    537     kAudioObjectPropertyElementMaster
    538   };
    539   OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
    540                                                &default_input_device_address,
    541                                                0,
    542                                                0,
    543                                                &info_size,
    544                                                &device_id);
    545   if (result != noErr)
    546     return 0.0;
    547 
    548   Float64 nominal_sample_rate;
    549   info_size = sizeof(nominal_sample_rate);
    550 
    551   AudioObjectPropertyAddress nominal_sample_rate_address = {
    552     kAudioDevicePropertyNominalSampleRate,
    553     kAudioObjectPropertyScopeGlobal,
    554     kAudioObjectPropertyElementMaster
    555   };
    556   result = AudioObjectGetPropertyData(device_id,
    557                                       &nominal_sample_rate_address,
    558                                       0,
    559                                       0,
    560                                       &info_size,
    561                                       &nominal_sample_rate);
    562   if (result != noErr)
    563     return 0.0;
    564 
    565   return static_cast<int>(nominal_sample_rate);
    566 }
    567 
    568 double AUAudioInputStream::GetHardwareLatency() {
    569   if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
    570     DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
    571     return 0.0;
    572   }
    573 
    574   // Get audio unit latency.
    575   Float64 audio_unit_latency_sec = 0.0;
    576   UInt32 size = sizeof(audio_unit_latency_sec);
    577   OSStatus result = AudioUnitGetProperty(audio_unit_,
    578                                          kAudioUnitProperty_Latency,
    579                                          kAudioUnitScope_Global,
    580                                          0,
    581                                          &audio_unit_latency_sec,
    582                                          &size);
    583   OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
    584       << "Could not get audio unit latency";
    585 
    586   // Get input audio device latency.
    587   AudioObjectPropertyAddress property_address = {
    588     kAudioDevicePropertyLatency,
    589     kAudioDevicePropertyScopeInput,
    590     kAudioObjectPropertyElementMaster
    591   };
    592   UInt32 device_latency_frames = 0;
    593   size = sizeof(device_latency_frames);
    594   result = AudioObjectGetPropertyData(input_device_id_,
    595                                       &property_address,
    596                                       0,
    597                                       NULL,
    598                                       &size,
    599                                       &device_latency_frames);
    600   DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
    601 
    602   return static_cast<double>((audio_unit_latency_sec *
    603       format_.mSampleRate) + device_latency_frames);
    604 }
    605 
    606 double AUAudioInputStream::GetCaptureLatency(
    607     const AudioTimeStamp* input_time_stamp) {
    608   // Get the delay between between the actual recording instant and the time
    609   // when the data packet is provided as a callback.
    610   UInt64 capture_time_ns = AudioConvertHostTimeToNanos(
    611       input_time_stamp->mHostTime);
    612   UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
    613   double delay_frames = static_cast<double>
    614       (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
    615 
    616   // Total latency is composed by the dynamic latency and the fixed
    617   // hardware latency.
    618   return (delay_frames + hardware_latency_frames_);
    619 }
    620 
    621 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
    622   // Get the stream format, to be able to read the number of channels.
    623   AudioObjectPropertyAddress property_address = {
    624     kAudioDevicePropertyStreamFormat,
    625     kAudioDevicePropertyScopeInput,
    626     kAudioObjectPropertyElementMaster
    627   };
    628   AudioStreamBasicDescription stream_format;
    629   UInt32 size = sizeof(stream_format);
    630   OSStatus result = AudioObjectGetPropertyData(input_device_id_,
    631                                                &property_address,
    632                                                0,
    633                                                NULL,
    634                                                &size,
    635                                                &stream_format);
    636   if (result != noErr) {
    637     DLOG(WARNING) << "Could not get stream format";
    638     return 0;
    639   }
    640 
    641   return static_cast<int>(stream_format.mChannelsPerFrame);
    642 }
    643 
    644 void AUAudioInputStream::HandleError(OSStatus err) {
    645   NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
    646                << " (" << err << ")";
    647   if (sink_)
    648     sink_->OnError(this);
    649 }
    650 
    651 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
    652   Boolean is_settable = false;
    653   AudioObjectPropertyAddress property_address = {
    654     kAudioDevicePropertyVolumeScalar,
    655     kAudioDevicePropertyScopeInput,
    656     static_cast<UInt32>(channel)
    657   };
    658   OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
    659                                                   &property_address,
    660                                                   &is_settable);
    661   return (result == noErr) ? is_settable : false;
    662 }
    663 
    664 }  // namespace media
    665