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"
136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "media/base/audio_bus.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/data_buffer.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Number of blocks of buffers used in the |fifo_|.
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kNumberOfBlocksBufferInFifo = 2;
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static std::ostream& operator<<(std::ostream& os,
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const AudioStreamBasicDescription& format) {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  os << "sample rate       : " << format.mSampleRate << std::endl
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "format ID         : " << format.mFormatID << std::endl
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "format flags      : " << format.mFormatFlags << std::endl
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "bytes per packet  : " << format.mBytesPerPacket << std::endl
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "frames per packet : " << format.mFramesPerPacket << std::endl
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "bytes per frame   : " << format.mBytesPerFrame << std::endl
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "channels per frame: " << format.mChannelsPerFrame << std::endl
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     << "bits per channel  : " << format.mBitsPerChannel;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return os;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See "Technical Note TN2091 - Device input using the HAL Output Audio Unit"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for more details and background regarding this implementation.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager,
396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                       const AudioParameters& input_params,
406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                       AudioDeviceID audio_device_id)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : manager_(manager),
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      number_of_frames_(input_params.frames_per_buffer()),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sink_(NULL),
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      audio_unit_(0),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_device_id_(audio_device_id),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      started_(false),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hardware_latency_frames_(0),
486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      number_of_channels_in_frame_(0),
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      fifo_(input_params.channels(),
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            number_of_frames_,
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            kNumberOfBlocksBufferInFifo) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(manager_);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up the desired (output) format specified by the client.
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  format_.mSampleRate = input_params.sample_rate();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mFormatID = kAudioFormatLinearPCM;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         kLinearPCMFormatFlagIsSignedInteger;
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  format_.mBitsPerChannel = input_params.bits_per_sample();
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  format_.mChannelsPerFrame = input_params.channels();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mFramesPerPacket = 1;  // uncompressed audio
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mBytesPerPacket = (format_.mBitsPerChannel *
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             input_params.channels()) / 8;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mBytesPerFrame = format_.mBytesPerPacket;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  format_.mReserved = 0;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Desired ouput format: " << format_;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Derive size (in bytes) of the buffers that we will render to.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 data_byte_size = number_of_frames_ * format_.mBytesPerFrame;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Size of data buffer in bytes : " << data_byte_size;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate AudioBuffers to be used as storage for the received audio.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The AudioBufferList structure works as a placeholder for the
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // AudioBuffer structure, which holds a pointer to the actual data buffer.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_data_buffer_.reset(new uint8[data_byte_size]);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_buffer_list_.mNumberBuffers = 1;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  audio_buffer->mNumberChannels = input_params.channels();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_buffer->mDataByteSize = data_byte_size;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_buffer->mData = audio_data_buffer_.get();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AUAudioInputStream::~AUAudioInputStream() {}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Obtain and open the AUHAL AudioOutputUnit for recording.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AUAudioInputStream::Open() {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we are not already opened.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (audio_unit_)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start by obtaining an AudioOuputUnit using an AUHAL component description.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Description for the Audio Unit we want to use (AUHAL in this case).
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AudioComponentDescription desc = {
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kAudioUnitType_Output,
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kAudioUnitSubType_HALOutput,
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kAudioUnitManufacturer_Apple,
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      0,
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      0
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  };
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AudioComponent comp = AudioComponentFindNext(0, &desc);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(comp);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get access to the service provided by the specified Audio Unit.
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enable IO on the input scope of the Audio Unit.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After creating the AUHAL object, we must enable IO on the input scope
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the Audio Unit to obtain the device input. Input must be explicitly
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // enabled with the kAudioOutputUnitProperty_EnableIO property on Element 1
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the AUHAL. Beacause the AUHAL can be used for both input and output,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we must also disable IO on the output scope.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 enableIO = 1;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enable input on the AUHAL.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioOutputUnitProperty_EnableIO,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Input,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                1,          // input element 1
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &enableIO,  // enable
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(enableIO));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disable output on the AUHAL.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enableIO = 0;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioOutputUnitProperty_EnableIO,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Output,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                0,          // output element 0
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &enableIO,  // disable
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(enableIO));
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Next, set the audio device to be the Audio Unit's current device.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that, devices can only be set to the AUHAL after enabling IO.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioOutputUnitProperty_CurrentDevice,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Global,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                0,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &input_device_id_,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(input_device_id_));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up the the desired (output) format.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For obtaining input from a device, the device format is always expressed
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on the output scope of the AUHAL's Element 1.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitSetProperty(audio_unit_,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitProperty_StreamFormat,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Output,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                1,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &format_,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                sizeof(format_));
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the desired number of frames in the IO buffer (output scope).
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // WARNING: Setting this value changes the frame size for all input audio
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // units in the current process.  As a result, the AURenderCallback must be
1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // able to handle arbitrary buffer sizes and FIFO appropriately.
1860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  UInt32 buffer_size = 0;
1870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  UInt32 property_size = sizeof(buffer_size);
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  result = AudioUnitGetProperty(audio_unit_,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioDevicePropertyBufferFrameSize,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                kAudioUnitScope_Output,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                1,
1920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                &buffer_size,
1930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                &property_size);
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (result != noErr) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Only set the buffer size if we're the only active stream or the buffer size
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // is lower than the current buffer size.
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (manager_->input_stream_count() == 1 || number_of_frames_ < buffer_size) {
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    buffer_size = number_of_frames_;
2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    result = AudioUnitSetProperty(audio_unit_,
2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  kAudioDevicePropertyBufferFrameSize,
2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  kAudioUnitScope_Output,
2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  1,
2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  &buffer_size,
2080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                  sizeof(buffer_size));
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (result != noErr) {
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      HandleError(result);
2110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      return false;
2120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Register the input procedure for the AUHAL.
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // This procedure will be called when the AUHAL has received new data
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // from the input device.
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AURenderCallbackStruct callback;
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback.inputProc = InputProc;
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback.inputProcRefCon = this;
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  result = AudioUnitSetProperty(audio_unit_,
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                kAudioOutputUnitProperty_SetInputCallback,
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                kAudioUnitScope_Global,
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                0,
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                &callback,
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                sizeof(callback));
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result) {
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    HandleError(result);
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finally, initialize the audio unit and ensure that it is ready to render.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocates memory according to the maximum number of audio frames
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it can produce in response to a single render call.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioUnitInitialize(audio_unit_);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleError(result);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The hardware latency is fixed and will not change during the call.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hardware_latency_frames_ = GetHardwareLatency();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The master channel is 0, Left and right are channels 1 and 2.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And the master channel is not counted in |number_of_channels_in_frame_|.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::Start(AudioInputCallback* callback) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully";
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_ || !audio_unit_)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Check if we should defer Start() for http://crbug.com/160920.
2580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (manager_->ShouldDeferStreamStart()) {
2590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Use a cancellable closure so that if Stop() is called before Start()
2600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // actually runs, we can cancel the pending start.
2610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    deferred_start_cb_.Reset(base::Bind(
2620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        &AUAudioInputStream::Start, base::Unretained(this), callback));
2630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    manager_->GetTaskRunner()->PostDelayedTask(
2640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        FROM_HERE,
2650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        deferred_start_cb_.callback(),
2660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        base::TimeDelta::FromSeconds(
2670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            AudioManagerMac::kStartDelayInSecsForPowerEvents));
2680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sink_ = callback;
27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  StartAgc();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioOutputUnitStart(audio_unit_);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == noErr) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    started_ = true;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Failed to start acquiring data";
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::Stop() {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!started_)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  StopAgc();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioOutputUnitStop(audio_unit_);
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(result, noErr);
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  started_ = false;
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sink_ = NULL;
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Failed to stop acquiring data";
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::Close() {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is valid to call Close() before calling open or Start().
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is also valid to call Close() after Start() has been called.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stop();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (audio_unit_) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Deallocate the audio unit’s resources.
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    OSStatus result = AudioUnitUninitialize(audio_unit_);
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        << "AudioUnitUninitialize() failed.";
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    result = AudioComponentInstanceDispose(audio_unit_);
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        << "AudioComponentInstanceDispose() failed.";
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    audio_unit_ = 0;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Inform the audio manager that we have been closed. This can cause our
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // destruction.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  manager_->ReleaseInputStream(this);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetMaxVolume() {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Query if any of the master, left or right channels has volume control.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i <= number_of_channels_in_frame_; ++i) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the volume is settable, the  valid volume range is [0.0, 1.0].
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsVolumeSettableOnChannel(i))
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1.0;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Volume control is not available for the audio stream.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0.0;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::SetVolume(double volume) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "SetVolume(volume=" << volume << ")";
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(volume, 0.0);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(volume, 1.0);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Float32 volume_float32 = static_cast<Float32>(volume);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyVolumeScalar,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to set the volume for master volume channel.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSStatus result = AudioObjectSetPropertyData(input_device_id_,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &property_address,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 0,
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 NULL,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 sizeof(volume_float32),
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &volume_float32);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result != noErr) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(WARNING) << "Failed to set volume to " << volume_float32;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There is no master volume control, try to set volume for each channel.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int successful_channels = 0;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    property_address.mElement = static_cast<UInt32>(i);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsVolumeSettableOnChannel(i)) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OSStatus result = AudioObjectSetPropertyData(input_device_id_,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &property_address,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   0,
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   NULL,
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   sizeof(volume_float32),
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &volume_float32);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (result == noErr)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++successful_channels;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG_IF(WARNING, successful_channels == 0)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Failed to set volume to " << volume_float32;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the AGC volume level based on the last setting above. Note that,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the volume-level resolution is not infinite and it is therefore not
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // possible to assume that the volume provided as input parameter can be
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // used directly. Instead, a new query to the audio hardware is required.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This method does nothing if AGC is disabled.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateAgcVolume();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetVolume() {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that we have a valid device.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_device_id_ == kAudioObjectUnknown){
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Device ID is unknown";
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyVolumeScalar,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AudioObjectHasProperty(input_device_id_, &property_address)) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The device supports master volume control, get the volume from the
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // master channel.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Float32 volume_float32 = 0.0;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UInt32 size = sizeof(volume_float32);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OSStatus result = AudioObjectGetPropertyData(input_device_id_,
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &property_address,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 0,
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 NULL,
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &size,
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &volume_float32);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result == noErr)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return static_cast<double>(volume_float32);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There is no master volume control, try to get the average volume of
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // all the channels.
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Float32 volume_float32 = 0.0;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int successful_channels = 0;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      property_address.mElement = static_cast<UInt32>(i);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (AudioObjectHasProperty(input_device_id_, &property_address)) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Float32 channel_volume = 0;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UInt32 size = sizeof(channel_volume);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OSStatus result = AudioObjectGetPropertyData(input_device_id_,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     &property_address,
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     0,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     NULL,
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     &size,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     &channel_volume);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (result == noErr) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          volume_float32 += channel_volume;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ++successful_channels;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the average volume of the channels.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (successful_channels != 0)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return static_cast<double>(volume_float32 / successful_channels);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG(WARNING) << "Failed to get volume";
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0.0;
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
453ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdochbool AUAudioInputStream::IsMuted() {
454ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  // Verify that we have a valid device.
455ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  DCHECK_NE(input_device_id_, kAudioObjectUnknown) << "Device ID is unknown";
456ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
457ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  AudioObjectPropertyAddress property_address = {
458ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    kAudioDevicePropertyMute,
459ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    kAudioDevicePropertyScopeInput,
460ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    kAudioObjectPropertyElementMaster
461ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  };
462ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
463ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  if (!AudioObjectHasProperty(input_device_id_, &property_address)) {
464ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    DLOG(ERROR) << "Device does not support checking master mute state";
465ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch    return false;
466ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  }
467ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
468ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  UInt32 muted = 0;
469ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  UInt32 size = sizeof(muted);
470ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  OSStatus result = AudioObjectGetPropertyData(
471ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch      input_device_id_, &property_address, 0, NULL, &size, &muted);
472ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  DLOG_IF(WARNING, result != noErr) << "Failed to get mute state";
473ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch  return result == noErr && muted != 0;
474ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch}
475ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AUHAL AudioDeviceOutput unit callback
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OSStatus AUAudioInputStream::InputProc(void* user_data,
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       AudioUnitRenderActionFlags* flags,
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const AudioTimeStamp* time_stamp,
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       UInt32 bus_number,
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       UInt32 number_of_frames,
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       AudioBufferList* io_data) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that the correct bus is used (Input bus/Element 1)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(bus_number, static_cast<UInt32>(1));
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AUAudioInputStream* audio_input =
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<AUAudioInputStream*>(user_data);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_input);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!audio_input)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kAudioUnitErr_InvalidElement;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Receive audio from the AUHAL from the output scope of the Audio Unit.
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioUnitRender(audio_input->audio_unit(),
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    flags,
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    time_stamp,
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    bus_number,
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    number_of_frames,
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    audio_input->audio_buffer_list());
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deliver recorded data to the consumer as a callback.
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return audio_input->Provide(number_of_frames,
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              audio_input->audio_buffer_list(),
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              time_stamp);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     AudioBufferList* io_data,
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const AudioTimeStamp* time_stamp) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the capture latency.
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double capture_latency_frames = GetCaptureLatency(time_stamp);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The AGC volume level is updated once every second on a separate thread.
51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Note that, |volume| is also updated each time SetVolume() is called
51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // through IPC by the render-side AGC.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double normalized_volume = 0.0;
51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GetAgcVolume(&normalized_volume);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioBuffer& buffer = io_data->mBuffers[0];
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 capture_delay_bytes = static_cast<uint32>
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((capture_latency_frames + 0.5) * format_.mBytesPerFrame);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_data);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!audio_data)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kAudioUnitErr_InvalidElement;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Copy captured (and interleaved) data into FIFO.
5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Consume and deliver the data when the FIFO has a block of available data.
5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (fifo_.available_blocks()) {
5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const AudioBus* audio_bus = fifo_.Consume();
5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_));
5346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Compensate the audio delay caused by the FIFO.
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame;
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return noErr;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AUAudioInputStream::HardwareSampleRate() {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine the default input device's sample-rate.
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioDeviceID device_id = kAudioObjectUnknown;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 info_size = sizeof(device_id);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress default_input_device_address = {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioHardwarePropertyDefaultInputDevice,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyScopeGlobal,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &default_input_device_address,
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               0,
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               0,
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &info_size,
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &device_id);
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result != noErr)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Float64 nominal_sample_rate;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info_size = sizeof(nominal_sample_rate);
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress nominal_sample_rate_address = {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyNominalSampleRate,
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyScopeGlobal,
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioObjectGetPropertyData(device_id,
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &nominal_sample_rate_address,
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      0,
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      0,
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &info_size,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &nominal_sample_rate);
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result != noErr)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(nominal_sample_rate);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetHardwareLatency() {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0.0;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get audio unit latency.
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Float64 audio_unit_latency_sec = 0.0;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 size = sizeof(audio_unit_latency_sec);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioUnitGetProperty(audio_unit_,
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         kAudioUnitProperty_Latency,
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         kAudioUnitScope_Global,
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         0,
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &audio_unit_latency_sec,
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &size);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << "Could not get audio unit latency";
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get input audio device latency.
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyLatency,
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 device_latency_frames = 0;
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size = sizeof(device_latency_frames);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = AudioObjectGetPropertyData(input_device_id_,
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &property_address,
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      0,
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      NULL,
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &size,
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &device_latency_frames);
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<double>((audio_unit_latency_sec *
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      format_.mSampleRate) + device_latency_frames);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double AUAudioInputStream::GetCaptureLatency(
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const AudioTimeStamp* input_time_stamp) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the delay between between the actual recording instant and the time
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when the data packet is provided as a callback.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt64 capture_time_ns = AudioConvertHostTimeToNanos(
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_time_stamp->mHostTime);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double delay_frames = static_cast<double>
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Total latency is composed by the dynamic latency and the fixed
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // hardware latency.
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (delay_frames + hardware_latency_frames_);
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AUAudioInputStream::GetNumberOfChannelsFromStream() {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the stream format, to be able to read the number of channels.
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyStreamFormat,
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioObjectPropertyElementMaster
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioStreamBasicDescription stream_format;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt32 size = sizeof(stream_format);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioObjectGetPropertyData(input_device_id_,
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &property_address,
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               0,
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               NULL,
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &size,
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &stream_format);
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != noErr) {
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Could not get stream format";
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(stream_format.mChannelsPerFrame);
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AUAudioInputStream::HandleError(OSStatus err) {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " (" << err << ")";
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sink_)
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->OnError(this);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Boolean is_settable = false;
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioObjectPropertyAddress property_address = {
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyVolumeScalar,
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kAudioDevicePropertyScopeInput,
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<UInt32>(channel)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  &property_address,
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  &is_settable);
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (result == noErr) ? is_settable : false;
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
679