audio_auhal_mac.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Copyright 2013 The Chromium Authors. All rights reserved. 247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Use of this source code is governed by a BSD-style license that can be 347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// found in the LICENSE file. 447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "media/audio/mac/audio_auhal_mac.h" 647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <CoreServices/CoreServices.h> 847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "base/basictypes.h" 1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "base/command_line.h" 1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "base/debug/trace_event.h" 1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "base/logging.h" 1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "base/mac/mac_logging.h" 1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "media/audio/audio_util.h" 1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "media/audio/mac/audio_manager_mac.h" 1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "media/base/media_switches.h" 1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace media { 1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic std::ostream& operator<<(std::ostream& os, 2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const AudioStreamBasicDescription& format) { 2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org os << "sample rate : " << format.mSampleRate << std::endl 2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "format ID : " << format.mFormatID << std::endl 2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "format flags : " << format.mFormatFlags << std::endl 2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "bytes per packet : " << format.mBytesPerPacket << std::endl 2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "frames per packet : " << format.mFramesPerPacket << std::endl 2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "bytes per frame : " << format.mBytesPerFrame << std::endl 2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "channels per frame: " << format.mChannelsPerFrame << std::endl 2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "bits per channel : " << format.mBitsPerChannel; 3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return os; 3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic void ZeroBufferList(AudioBufferList* buffer_list) { 3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (size_t i = 0; i < buffer_list->mNumberBuffers; ++i) { 3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org memset(buffer_list->mBuffers[i].mData, 3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org buffer_list->mBuffers[i].mDataByteSize); 3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic void WrapBufferList(AudioBufferList* buffer_list, 4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioBus* bus, 4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int frames) { 4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DCHECK(buffer_list); 4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DCHECK(bus); 4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const int channels = bus->channels(); 4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const int buffer_list_channels = buffer_list->mNumberBuffers; 4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DCHECK_EQ(channels, buffer_list_channels); 4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Copy pointers from AudioBufferList. 5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (int i = 0; i < channels; ++i) { 5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bus->SetChannelData( 5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org i, static_cast<float*>(buffer_list->mBuffers[i].mData)); 5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Finally set the actual length. 5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bus->set_frames(frames); 5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAUHALStream::AUHALStream( 6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioManagerMac* manager, 6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const AudioParameters& params, 6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioDeviceID device) 6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org : manager_(manager), 6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org params_(params), 6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_channels_(params_.input_channels()), 6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_channels_(params_.channels()), 6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org number_of_frames_(params_.frames_per_buffer()), 6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org source_(NULL), 7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org device_(device), 7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org audio_unit_(0), 7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org volume_(1), 7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org hardware_latency_frames_(0), 7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org stopped_(false), 7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_(NULL) { 7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // We must have a manager. 7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DCHECK(manager_); 7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org VLOG(1) << "AUHALStream::AUHALStream()"; 8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org VLOG(1) << "Device: " << device; 8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org VLOG(1) << "Input channels: " << input_channels_; 8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org VLOG(1) << "Output channels: " << output_channels_; 8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org VLOG(1) << "Sample rate: " << params_.sample_rate(); 8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org VLOG(1) << "Buffer size: " << number_of_frames_; 8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAUHALStream::~AUHALStream() { 8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool AUHALStream::Open() { 9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Get the total number of input and output channels that the 9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // hardware supports. 9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int device_input_channels; 9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool got_input_channels = AudioManagerMac::GetDeviceChannels( 9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org device_, 9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org kAudioDevicePropertyScopeInput, 9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &device_input_channels); 9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int device_output_channels; 10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool got_output_channels = AudioManagerMac::GetDeviceChannels( 10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org device_, 10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org kAudioDevicePropertyScopeOutput, 10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &device_output_channels); 10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Sanity check the requested I/O channels. 10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!got_input_channels || 10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_channels_ < 0 || input_channels_ > device_input_channels) { 10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(ERROR) << "AudioDevice does not support requested input channels."; 10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!got_output_channels || 11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_channels_ <= 0 || output_channels_ > device_output_channels) { 11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(ERROR) << "AudioDevice does not support requested output channels."; 11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // The requested sample-rate must match the hardware sample-rate. 11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int sample_rate = AudioManagerMac::HardwareSampleRateForDevice(device_); 12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (sample_rate != params_.sample_rate()) { 12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate() 12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << " must match the hardware sample-rate: " << sample_rate; 12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org CreateIOBusses(); 12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool configured = ConfigureAUHAL(); 13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (configured) 13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org hardware_latency_frames_ = GetHardwareLatency(); 13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return configured; 13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AUHALStream::Close() { 13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (input_buffer_list_) { 13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_storage_.reset(); 13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_ = NULL; 14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_bus_.reset(NULL); 14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_bus_.reset(NULL); 14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (audio_unit_) { 14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioUnitUninitialize(audio_unit_); 14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioComponentInstanceDispose(audio_unit_); 14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Inform the audio manager that we have been closed. This will cause our 15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // destruction. 15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org manager_->ReleaseOutputStream(this); 15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AUHALStream::Start(AudioSourceCallback* callback) { 15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DCHECK(callback); 15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!audio_unit_) { 15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DLOG(ERROR) << "Open() has not been called successfully"; 15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return; 15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org stopped_ = false; 16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org { 16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org base::AutoLock auto_lock(source_lock_); 16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org source_ = callback; 16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioOutputUnitStart(audio_unit_); 16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AUHALStream::Stop() { 17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (stopped_) 17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return; 17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioOutputUnitStop(audio_unit_); 17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org base::AutoLock auto_lock(source_lock_); 17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org source_ = NULL; 17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org stopped_ = true; 17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AUHALStream::SetVolume(double volume) { 18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org volume_ = static_cast<float>(volume); 18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AUHALStream::GetVolume(double* volume) { 18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *volume = volume_; 18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Pulls on our provider to get rendered audio stream. 19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Note to future hackers of this function: Do not add locks which can 19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// be contended in the middle of stream processing here (starting and stopping 19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// the stream are ok) because this is running on a real-time thread. 19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgOSStatus AUHALStream::Render( 19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioUnitRenderActionFlags* flags, 19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const AudioTimeStamp* output_time_stamp, 19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 bus_number, 19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 number_of_frames, 19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioBufferList* io_data) { 19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org TRACE_EVENT0("audio", "AUHALStream::Render"); 20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (number_of_frames != number_of_frames_) { 20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // This can happen if we've suddenly changed sample-rates. 20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // The stream should be stopping very soon. 20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // 20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Unfortunately AUAudioInputStream and AUHALStream share the frame 20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // size set by kAudioDevicePropertyBufferFrameSize above on a per process 20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // basis. What this means is that the |number_of_frames| value may be 20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // larger or smaller than the value set during ConfigureAUHAL(). 20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // In this case either audio input or audio output will be broken, 21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // so just output silence. 21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ZeroBufferList(io_data); 21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return noErr; 21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (input_channels_ > 0 && input_buffer_list_) { 21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Get the input data. |input_buffer_list_| is wrapped 21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // to point to the data allocated in |input_bus_|. 21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org OSStatus result = AudioUnitRender( 21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org audio_unit_, 22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org flags, 22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_time_stamp, 22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1, 22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org number_of_frames, 22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_); 22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (result != noErr) 22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ZeroBufferList(input_buffer_list_); 22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Make |output_bus_| wrap the output AudioBufferList. 23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org WrapBufferList(io_data, output_bus_.get(), number_of_frames); 23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Update the playout latency. 23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org double playout_latency_frames = GetPlayoutLatency(output_time_stamp); 23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint32 hardware_pending_bytes = static_cast<uint32> 23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ((playout_latency_frames + 0.5) * output_format_.mBytesPerFrame); 23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org { 23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Render() shouldn't be called except between AudioOutputUnitStart() and 24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // AudioOutputUnitStop() calls, but crash reports have shown otherwise: 24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // http://crbug.com/178765. We use |source_lock_| to prevent races and 24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // crashes in Render() when |source_| is cleared. 24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org base::AutoLock auto_lock(source_lock_); 24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!source_) { 24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ZeroBufferList(io_data); 24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return noErr; 24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Supply the input data and render the output data. 25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org source_->OnMoreIOData( 25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_bus_.get(), 25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_bus_.get(), 25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioBuffersState(0, hardware_pending_bytes)); 25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_bus_->Scale(volume_); 25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return noErr; 25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// AUHAL callback. 26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgOSStatus AUHALStream::InputProc( 26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org void* user_data, 26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioUnitRenderActionFlags* flags, 26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const AudioTimeStamp* output_time_stamp, 26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 bus_number, 26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 number_of_frames, 26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AudioBufferList* io_data) { 26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Dispatch to our class method. 26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AUHALStream* audio_output = 27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org static_cast<AUHALStream*>(user_data); 27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!audio_output) 27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return -1; 27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return audio_output->Render( 27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org flags, 27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_time_stamp, 27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bus_number, 27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org number_of_frames, 27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org io_data); 28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgdouble AUHALStream::GetHardwareLatency() { 28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!audio_unit_ || device_ == kAudioObjectUnknown) { 28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DLOG(WARNING) << "AudioUnit is NULL or device ID is unknown"; 28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0.0; 28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Get audio unit latency. 28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Float64 audio_unit_latency_sec = 0.0; 29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 size = sizeof(audio_unit_latency_sec); 29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org OSStatus result = AudioUnitGetProperty( 29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org audio_unit_, 29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org kAudioUnitProperty_Latency, 29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org kAudioUnitScope_Global, 29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &audio_unit_latency_sec, 29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &size); 29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (result != noErr) { 29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org OSSTATUS_DLOG(WARNING, result) << "Could not get AudioUnit latency"; 30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0.0; 30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Get output audio device latency. 30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org static const AudioObjectPropertyAddress property_address = { 30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org kAudioDevicePropertyLatency, 30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org kAudioDevicePropertyScopeOutput, 30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org kAudioObjectPropertyElementMaster 30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org }; 30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 device_latency_frames = 0; 31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size = sizeof(device_latency_frames); 31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org result = AudioObjectGetPropertyData( 31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org device_, 31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &property_address, 31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org NULL, 31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &size, 31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &device_latency_frames); 31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (result != noErr) { 32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; 32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0.0; 32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return static_cast<double>((audio_unit_latency_sec * 32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_format_.mSampleRate) + device_latency_frames); 32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgdouble AUHALStream::GetPlayoutLatency( 32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const AudioTimeStamp* output_time_stamp) { 33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Ensure mHostTime is valid. 33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) 33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0; 33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Get the delay between the moment getting the callback and the scheduled 33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // time stamp that tells when the data is going to be played out. 33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt64 output_time_ns = AudioConvertHostTimeToNanos( 33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_time_stamp->mHostTime); 33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Prevent overflow leading to huge delay information; occurs regularly on 34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // the bots, probably less so in the wild. 34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (now_ns > output_time_ns) 34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0; 34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org double delay_frames = static_cast<double> 34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate); 34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 34847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return (delay_frames + hardware_latency_frames_); 34947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 35047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 35147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AUHALStream::CreateIOBusses() { 35247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (input_channels_ > 0) { 35347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Allocate storage for the AudioBufferList used for the 35447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // input data from the input AudioUnit. 35547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // We allocate enough space for with one AudioBuffer per channel. 35647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t buffer_list_size = offsetof(AudioBufferList, mBuffers[0]) + 35747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org (sizeof(AudioBuffer) * input_channels_); 35847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_storage_.reset(new uint8[buffer_list_size]); 35947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 36047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_ = 36147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org reinterpret_cast<AudioBufferList*>(input_buffer_list_storage_.get()); 36247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_->mNumberBuffers = input_channels_; 36347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 36447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // |input_bus_| allocates the storage for the PCM input data. 36547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_bus_ = AudioBus::Create(input_channels_, number_of_frames_); 36647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 36747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Make the AudioBufferList point to the memory in |input_bus_|. 36847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 buffer_size_bytes = input_bus_->frames() * sizeof(Float32); 36947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (size_t i = 0; i < input_buffer_list_->mNumberBuffers; ++i) { 37047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_->mBuffers[i].mNumberChannels = 1; 37147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_->mBuffers[i].mDataByteSize = buffer_size_bytes; 37247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org input_buffer_list_->mBuffers[i].mData = input_bus_->channel(i); 37347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 37447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 37547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 37647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // The output bus will wrap the AudioBufferList given to us in 37747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // the Render() callback. 37847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DCHECK_GT(output_channels_, 0); 37947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org output_bus_ = AudioBus::CreateWrapper(output_channels_); 38047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 38147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 38247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool AUHALStream::EnableIO(bool enable, UInt32 scope) { 38347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // See Apple technote for details about the EnableIO property. 38447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Note that we use bus 1 for input and bus 0 for output: 38547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html 38647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UInt32 enable_IO = enable ? 1 : 0; 38747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org OSStatus result = AudioUnitSetProperty( 38847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org audio_unit_, 389 kAudioOutputUnitProperty_EnableIO, 390 scope, 391 (scope == kAudioUnitScope_Input) ? 1 : 0, 392 &enable_IO, 393 sizeof(enable_IO)); 394 return (result == noErr); 395} 396 397bool AUHALStream::SetStreamFormat( 398 AudioStreamBasicDescription* desc, 399 int channels, 400 UInt32 scope, 401 UInt32 element) { 402 DCHECK(desc); 403 AudioStreamBasicDescription& format = *desc; 404 405 format.mSampleRate = params_.sample_rate(); 406 format.mFormatID = kAudioFormatLinearPCM; 407 format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | 408 kLinearPCMFormatFlagIsNonInterleaved; 409 format.mBytesPerPacket = sizeof(Float32); 410 format.mFramesPerPacket = 1; 411 format.mBytesPerFrame = sizeof(Float32); 412 format.mChannelsPerFrame = channels; 413 format.mBitsPerChannel = 32; 414 format.mReserved = 0; 415 416 OSStatus result = AudioUnitSetProperty( 417 audio_unit_, 418 kAudioUnitProperty_StreamFormat, 419 scope, 420 element, 421 &format, 422 sizeof(format)); 423 return (result == noErr); 424} 425 426bool AUHALStream::ConfigureAUHAL() { 427 if (device_ == kAudioObjectUnknown || 428 (input_channels_ == 0 && output_channels_ == 0)) 429 return false; 430 431 AudioComponentDescription desc = { 432 kAudioUnitType_Output, 433 kAudioUnitSubType_HALOutput, 434 kAudioUnitManufacturer_Apple, 435 0, 436 0 437 }; 438 AudioComponent comp = AudioComponentFindNext(0, &desc); 439 if (!comp) 440 return false; 441 442 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_); 443 if (result != noErr) { 444 OSSTATUS_DLOG(WARNING, result) << "AudioComponentInstanceNew() failed."; 445 return false; 446 } 447 448 result = AudioUnitInitialize(audio_unit_); 449 if (result != noErr) { 450 OSSTATUS_DLOG(WARNING, result) << "AudioUnitInitialize() failed."; 451 return false; 452 } 453 454 // Enable input and output as appropriate. 455 if (!EnableIO(input_channels_ > 0, kAudioUnitScope_Input)) 456 return false; 457 if (!EnableIO(output_channels_ > 0, kAudioUnitScope_Output)) 458 return false; 459 460 // Set the device to be used with the AUHAL AudioUnit. 461 result = AudioUnitSetProperty( 462 audio_unit_, 463 kAudioOutputUnitProperty_CurrentDevice, 464 kAudioUnitScope_Global, 465 0, 466 &device_, 467 sizeof(AudioDeviceID)); 468 if (result != noErr) 469 return false; 470 471 // Set stream formats. 472 // See Apple's tech note for details on the peculiar way that 473 // inputs and outputs are handled in the AUHAL concerning scope and bus 474 // (element) numbers: 475 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html 476 477 if (input_channels_ > 0) { 478 if (!SetStreamFormat(&input_format_, 479 input_channels_, 480 kAudioUnitScope_Output, 481 1)) 482 return false; 483 } 484 485 if (output_channels_ > 0) { 486 if (!SetStreamFormat(&output_format_, 487 output_channels_, 488 kAudioUnitScope_Input, 489 0)) 490 return false; 491 } 492 493 // Set the buffer frame size. 494 // WARNING: Setting this value changes the frame size for all audio units in 495 // the current process. It's imperative that the input and output frame sizes 496 // be the same as the frames_per_buffer() returned by 497 // GetDefaultOutputStreamParameters(). 498 // See http://crbug.com/154352 for details. 499 UInt32 buffer_size = number_of_frames_; 500 result = AudioUnitSetProperty( 501 audio_unit_, 502 kAudioDevicePropertyBufferFrameSize, 503 kAudioUnitScope_Output, 504 0, 505 &buffer_size, 506 sizeof(buffer_size)); 507 if (result != noErr) { 508 OSSTATUS_DLOG(WARNING, result) 509 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed."; 510 return false; 511 } 512 513 // Setup callback. 514 AURenderCallbackStruct callback; 515 callback.inputProc = InputProc; 516 callback.inputProcRefCon = this; 517 result = AudioUnitSetProperty( 518 audio_unit_, 519 kAudioUnitProperty_SetRenderCallback, 520 kAudioUnitScope_Input, 521 0, 522 &callback, 523 sizeof(callback)); 524 if (result != noErr) 525 return false; 526 527 return true; 528} 529 530} // namespace media 531