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