audio_low_latency_input_mac.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/mac/audio_low_latency_input_mac.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <CoreServices/CoreServices.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/mac/audio_manager_mac.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/data_buffer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::ostream& operator<<(std::ostream& os,
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const AudioStreamBasicDescription& format) {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  os << "sample rate       : " << format.mSampleRate << std::endl
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "format ID         : " << format.mFormatID << std::endl
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "format flags      : " << format.mFormatFlags << std::endl
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "bytes per packet  : " << format.mBytesPerPacket << std::endl
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "frames per packet : " << format.mFramesPerPacket << std::endl
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "bytes per frame   : " << format.mBytesPerFrame << std::endl
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "channels per frame: " << format.mChannelsPerFrame << std::endl
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "bits per channel  : " << format.mBitsPerChannel;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return os;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See "Technical Note TN2091 - Device input using the HAL Output Audio Unit"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for more details and background regarding this implementation.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AUAudioInputStream::AUAudioInputStream(
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AudioManagerMac* manager,
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const AudioParameters& input_params,
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const AudioParameters& output_params,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AudioDeviceID audio_device_id)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : manager_(manager),
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sink_(NULL),
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      audio_unit_(0),
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_device_id_(audio_device_id),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      started_(false),
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hardware_latency_frames_(0),
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      fifo_delay_bytes_(0),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      number_of_channels_in_frame_(0) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(manager_);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up the desired (output) format specified by the client.
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  format_.mSampleRate = input_params.sample_rate();
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mFormatID = kAudioFormatLinearPCM;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         kLinearPCMFormatFlagIsSignedInteger;
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  format_.mBitsPerChannel = input_params.bits_per_sample();
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  format_.mChannelsPerFrame = input_params.channels();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mFramesPerPacket = 1;  // uncompressed audio
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mBytesPerPacket = (format_.mBitsPerChannel *
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             input_params.channels()) / 8;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mBytesPerFrame = format_.mBytesPerPacket;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mReserved = 0;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Desired ouput format: " << format_;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set number of sample frames per callback used by the internal audio layer.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An internal FIFO is then utilized to adapt the internal size to the size
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // requested by the client.
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Note that we use the same native buffer size as for the output side here
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since the AUHAL implementation requires that both capture and render side
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use the same buffer size. See http://crbug.com/154352 for more details.
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  number_of_frames_ = output_params.frames_per_buffer();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Size of data buffer in frames : " << number_of_frames_;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Derive size (in bytes) of the buffers that we will render to.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 data_byte_size = number_of_frames_ * format_.mBytesPerFrame;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Size of data buffer in bytes : " << data_byte_size;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate AudioBuffers to be used as storage for the received audio.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The AudioBufferList structure works as a placeholder for the
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AudioBuffer structure, which holds a pointer to the actual data buffer.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_data_buffer_.reset(new uint8[data_byte_size]);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_buffer_list_.mNumberBuffers = 1;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  audio_buffer->mNumberChannels = input_params.channels();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_buffer->mDataByteSize = data_byte_size;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_buffer->mData = audio_data_buffer_.get();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up an internal FIFO buffer that will accumulate recorded audio frames
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // until a requested size is ready to be sent to the client.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is not possible to ask for less than |kAudioFramesPerCallback| number of
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // audio frames.
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  size_t requested_size_frames =
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      input_params.GetBytesPerBuffer() / format_.mBytesPerPacket;
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (requested_size_frames < number_of_frames_) {
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // For devices that only support a low sample rate like 8kHz, we adjust the
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // buffer size to match number_of_frames_.  The value of number_of_frames_
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // in this case has not been calculated based on hardware settings but
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // rather our hardcoded defaults (see ChooseBufferSize).
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    requested_size_frames = number_of_frames_;
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  requested_size_bytes_ = requested_size_frames * format_.mBytesPerFrame;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Requested buffer size in bytes : " << requested_size_bytes_;
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DVLOG_IF(0, requested_size_frames > number_of_frames_) << "FIFO is used";
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const int number_of_bytes = number_of_frames_ * format_.mBytesPerFrame;
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  fifo_delay_bytes_ = requested_size_bytes_ - number_of_bytes;
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate some extra memory to avoid memory reallocations.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure that the size is an even multiple of |number_of_frames_ and
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // larger than |requested_size_frames|.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Example: number_of_frames_=128, requested_size_frames=480 =>
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allocated space equals 4*128=512 audio frames
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const int max_forward_capacity = number_of_bytes *
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((requested_size_frames / number_of_frames_) + 1);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fifo_.reset(new media::SeekableBuffer(0, max_forward_capacity));
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_ = new media::DataBuffer(requested_size_bytes_);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AUAudioInputStream::~AUAudioInputStream() {}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Obtain and open the AUHAL AudioOutputUnit for recording.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AUAudioInputStream::Open() {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we are not already opened.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (audio_unit_)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start by obtaining an AudioOuputUnit using an AUHAL component description.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Component comp;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ComponentDescription desc;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Description for the Audio Unit we want to use (AUHAL in this case).
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desc.componentType = kAudioUnitType_Output;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desc.componentSubType = kAudioUnitSubType_HALOutput;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desc.componentFlags = 0;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desc.componentFlagsMask = 0;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  comp = FindNextComponent(0, &desc);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(comp);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get access to the service provided by the specified Audio Unit.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = OpenAComponent(comp, &audio_unit_);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enable IO on the input scope of the Audio Unit.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After creating the AUHAL object, we must enable IO on the input scope
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the Audio Unit to obtain the device input. Input must be explicitly
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // enabled with the kAudioOutputUnitProperty_EnableIO property on Element 1
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the AUHAL. Beacause the AUHAL can be used for both input and output,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we must also disable IO on the output scope.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 enableIO = 1;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enable input on the AUHAL.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioOutputUnitProperty_EnableIO,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Input,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                1,          // input element 1
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &enableIO,  // enable
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(enableIO));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disable output on the AUHAL.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enableIO = 0;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioOutputUnitProperty_EnableIO,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Output,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                0,          // output element 0
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &enableIO,  // disable
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(enableIO));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Next, set the audio device to be the Audio Unit's current device.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that, devices can only be set to the AUHAL after enabling IO.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioOutputUnitProperty_CurrentDevice,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Global,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                0,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &input_device_id_,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(input_device_id_));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register the input procedure for the AUHAL.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This procedure will be called when the AUHAL has received new data
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from the input device.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AURenderCallbackStruct callback;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.inputProc = InputProc;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.inputProcRefCon = this;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioOutputUnitProperty_SetInputCallback,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Global,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                0,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &callback,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(callback));
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up the the desired (output) format.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For obtaining input from a device, the device format is always expressed
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on the output scope of the AUHAL's Element 1.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitProperty_StreamFormat,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Output,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                1,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &format_,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(format_));
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the desired number of frames in the IO buffer (output scope).
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WARNING: Setting this value changes the frame size for all audio units in
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the current process.  It's imperative that the input and output frame sizes
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // be the same as the frames_per_buffer() returned by
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // GetInputStreamParameters().
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(henrika): Due to http://crrev.com/159666 this is currently not true
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and should be fixed, a CHECK() should be added at that time.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioDevicePropertyBufferFrameSize,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Output,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                1,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &number_of_frames_,  // size is set in the ctor
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(number_of_frames_));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, initialize the audio unit and ensure that it is ready to render.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocates memory according to the maximum number of audio frames
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it can produce in response to a single render call.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitInitialize(audio_unit_);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The hardware latency is fixed and will not change during the call.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hardware_latency_frames_ = GetHardwareLatency();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The master channel is 0, Left and right are channels 1 and 2.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And the master channel is not counted in |number_of_channels_in_frame_|.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::Start(AudioInputCallback* callback) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully";
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_ || !audio_unit_)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sink_ = callback;
27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  StartAgc();
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioOutputUnitStart(audio_unit_);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == noErr) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    started_ = true;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Failed to start acquiring data";
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::Stop() {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!started_)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  StopAgc();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioOutputUnitStop(audio_unit_);
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(result, noErr);
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  started_ = false;
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sink_ = NULL;
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Failed to stop acquiring data";
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::Close() {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is valid to call Close() before calling open or Start().
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is also valid to call Close() after Start() has been called.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stop();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (audio_unit_) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Deallocate the audio unit’s resources.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AudioUnitUninitialize(audio_unit_);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Terminates our connection to the AUHAL component.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseComponent(audio_unit_);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    audio_unit_ = 0;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inform the audio manager that we have been closed. This can cause our
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // destruction.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manager_->ReleaseInputStream(this);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetMaxVolume() {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Query if any of the master, left or right channels has volume control.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i <= number_of_channels_in_frame_; ++i) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the volume is settable, the  valid volume range is [0.0, 1.0].
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsVolumeSettableOnChannel(i))
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1.0;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Volume control is not available for the audio stream.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0.0;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::SetVolume(double volume) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "SetVolume(volume=" << volume << ")";
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(volume, 0.0);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(volume, 1.0);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Float32 volume_float32 = static_cast<Float32>(volume);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyVolumeScalar,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to set the volume for master volume channel.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSStatus result = AudioObjectSetPropertyData(input_device_id_,
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &property_address,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 0,
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 NULL,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 sizeof(volume_float32),
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &volume_float32);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result != noErr) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(WARNING) << "Failed to set volume to " << volume_float32;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There is no master volume control, try to set volume for each channel.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int successful_channels = 0;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    property_address.mElement = static_cast<UInt32>(i);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsVolumeSettableOnChannel(i)) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OSStatus result = AudioObjectSetPropertyData(input_device_id_,
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &property_address,
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   0,
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   NULL,
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   sizeof(volume_float32),
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &volume_float32);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (result == noErr)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++successful_channels;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG_IF(WARNING, successful_channels == 0)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Failed to set volume to " << volume_float32;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the AGC volume level based on the last setting above. Note that,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the volume-level resolution is not infinite and it is therefore not
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // possible to assume that the volume provided as input parameter can be
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // used directly. Instead, a new query to the audio hardware is required.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method does nothing if AGC is disabled.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateAgcVolume();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetVolume() {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown){
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyVolumeScalar,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AudioObjectHasProperty(input_device_id_, &property_address)) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The device supports master volume control, get the volume from the
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // master channel.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Float32 volume_float32 = 0.0;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UInt32 size = sizeof(volume_float32);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSStatus result = AudioObjectGetPropertyData(input_device_id_,
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &property_address,
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 0,
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 NULL,
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &size,
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &volume_float32);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result == noErr)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return static_cast<double>(volume_float32);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is no master volume control, try to get the average volume of
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // all the channels.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Float32 volume_float32 = 0.0;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int successful_channels = 0;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      property_address.mElement = static_cast<UInt32>(i);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (AudioObjectHasProperty(input_device_id_, &property_address)) {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Float32 channel_volume = 0;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UInt32 size = sizeof(channel_volume);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OSStatus result = AudioObjectGetPropertyData(input_device_id_,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     &property_address,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     0,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     NULL,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     &size,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     &channel_volume);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (result == noErr) {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          volume_float32 += channel_volume;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ++successful_channels;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the average volume of the channels.
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (successful_channels != 0)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return static_cast<double>(volume_float32 / successful_channels);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG(WARNING) << "Failed to get volume";
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0.0;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AUHAL AudioDeviceOutput unit callback
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OSStatus AUAudioInputStream::InputProc(void* user_data,
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       AudioUnitRenderActionFlags* flags,
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const AudioTimeStamp* time_stamp,
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       UInt32 bus_number,
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       UInt32 number_of_frames,
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       AudioBufferList* io_data) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that the correct bus is used (Input bus/Element 1)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(bus_number, static_cast<UInt32>(1));
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUAudioInputStream* audio_input =
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<AUAudioInputStream*>(user_data);
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_input);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!audio_input)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kAudioUnitErr_InvalidElement;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Receive audio from the AUHAL from the output scope of the Audio Unit.
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioUnitRender(audio_input->audio_unit(),
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    flags,
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    time_stamp,
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    bus_number,
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    number_of_frames,
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    audio_input->audio_buffer_list());
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deliver recorded data to the consumer as a callback.
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return audio_input->Provide(number_of_frames,
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              audio_input->audio_buffer_list(),
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              time_stamp);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     AudioBufferList* io_data,
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const AudioTimeStamp* time_stamp) {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the capture latency.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double capture_latency_frames = GetCaptureLatency(time_stamp);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The AGC volume level is updated once every second on a separate thread.
49390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Note that, |volume| is also updated each time SetVolume() is called
49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // through IPC by the render-side AGC.
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double normalized_volume = 0.0;
49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GetAgcVolume(&normalized_volume);
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioBuffer& buffer = io_data->mBuffers[0];
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 capture_delay_bytes = static_cast<uint32>
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((capture_latency_frames + 0.5) * format_.mBytesPerFrame);
502868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Account for the extra delay added by the FIFO.
503868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  capture_delay_bytes += fifo_delay_bytes_;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_data);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!audio_data)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kAudioUnitErr_InvalidElement;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Accumulate captured audio in FIFO until we can match the output size
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // requested by the client.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fifo_->Append(audio_data, buffer.mDataByteSize);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deliver recorded data to the client as soon as the FIFO contains a
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sufficient amount.
51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (fifo_->forward_bytes() >= requested_size_bytes_) {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Read from FIFO into temporary data buffer.
516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    fifo_->Read(data_->writable_data(), requested_size_bytes_);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Deliver data packet, delay estimation and volume level to the user.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sink_->OnData(this,
520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  data_->data(),
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  requested_size_bytes_,
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  capture_delay_bytes,
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  normalized_volume);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return noErr;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AUAudioInputStream::HardwareSampleRate() {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine the default input device's sample-rate.
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioDeviceID device_id = kAudioObjectUnknown;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 info_size = sizeof(device_id);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress default_input_device_address = {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioHardwarePropertyDefaultInputDevice,
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyScopeGlobal,
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &default_input_device_address,
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               0,
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               0,
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &info_size,
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &device_id);
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result != noErr)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Float64 nominal_sample_rate;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info_size = sizeof(nominal_sample_rate);
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress nominal_sample_rate_address = {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyNominalSampleRate,
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyScopeGlobal,
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioObjectGetPropertyData(device_id,
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &nominal_sample_rate_address,
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      0,
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      0,
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &info_size,
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &nominal_sample_rate);
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result != noErr)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(nominal_sample_rate);
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetHardwareLatency() {
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get audio unit latency.
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Float64 audio_unit_latency_sec = 0.0;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 size = sizeof(audio_unit_latency_sec);
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioUnitGetProperty(audio_unit_,
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         kAudioUnitProperty_Latency,
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         kAudioUnitScope_Global,
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         0,
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &audio_unit_latency_sec,
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &size);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Could not get audio unit latency";
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get input audio device latency.
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyLatency,
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 device_latency_frames = 0;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size = sizeof(device_latency_frames);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioObjectGetPropertyData(input_device_id_,
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &property_address,
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      0,
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      NULL,
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &size,
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &device_latency_frames);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<double>((audio_unit_latency_sec *
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      format_.mSampleRate) + device_latency_frames);
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetCaptureLatency(
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioTimeStamp* input_time_stamp) {
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the delay between between the actual recording instant and the time
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when the data packet is provided as a callback.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt64 capture_time_ns = AudioConvertHostTimeToNanos(
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_time_stamp->mHostTime);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double delay_frames = static_cast<double>
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Total latency is composed by the dynamic latency and the fixed
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // hardware latency.
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (delay_frames + hardware_latency_frames_);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AUAudioInputStream::GetNumberOfChannelsFromStream() {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the stream format, to be able to read the number of channels.
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyStreamFormat,
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioStreamBasicDescription stream_format;
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 size = sizeof(stream_format);
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioObjectGetPropertyData(input_device_id_,
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &property_address,
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               0,
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               NULL,
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &size,
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &stream_format);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != noErr) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Could not get stream format";
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(stream_format.mChannelsPerFrame);
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::HandleError(OSStatus err) {
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " (" << err << ")";
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sink_)
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->OnError(this);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Boolean is_settable = false;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyVolumeScalar,
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<UInt32>(channel)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  &property_address,
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  &is_settable);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (result == noErr) ? is_settable : false;
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
665