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