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