| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/mac/audio_auhal_mac.h" | 5 #include "media/audio/mac/audio_auhal_mac.h" |
| 6 | 6 |
| 7 #include <CoreServices/CoreServices.h> | 7 #include <CoreServices/CoreServices.h> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/mac/mac_logging.h" | 14 #include "base/mac/mac_logging.h" |
| 15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 16 #include "media/audio/mac/audio_manager_mac.h" | 16 #include "media/audio/mac/audio_manager_mac.h" |
| 17 #include "media/base/audio_pull_fifo.h" | 17 #include "media/base/audio_pull_fifo.h" |
| 18 | 18 |
| 19 namespace media { | 19 namespace media { |
| 20 | 20 |
| 21 static void ZeroBufferList(AudioBufferList* buffer_list) { | |
| 22 for (size_t i = 0; i < buffer_list->mNumberBuffers; ++i) { | |
| 23 memset(buffer_list->mBuffers[i].mData, | |
| 24 0, | |
| 25 buffer_list->mBuffers[i].mDataByteSize); | |
| 26 } | |
| 27 } | |
| 28 | |
| 29 static void WrapBufferList(AudioBufferList* buffer_list, | 21 static void WrapBufferList(AudioBufferList* buffer_list, |
| 30 AudioBus* bus, | 22 AudioBus* bus, |
| 31 int frames) { | 23 int frames) { |
| 32 DCHECK(buffer_list); | 24 DCHECK(buffer_list); |
| 33 DCHECK(bus); | 25 DCHECK(bus); |
| 34 const int channels = bus->channels(); | 26 const int channels = bus->channels(); |
| 35 const int buffer_list_channels = buffer_list->mNumberBuffers; | 27 const int buffer_list_channels = buffer_list->mNumberBuffers; |
| 36 CHECK_EQ(channels, buffer_list_channels); | 28 CHECK_EQ(channels, buffer_list_channels); |
| 37 | 29 |
| 38 // Copy pointers from AudioBufferList. | 30 // Copy pointers from AudioBufferList. |
| 39 for (int i = 0; i < channels; ++i) { | 31 for (int i = 0; i < channels; ++i) { |
| 40 bus->SetChannelData( | 32 bus->SetChannelData( |
| 41 i, static_cast<float*>(buffer_list->mBuffers[i].mData)); | 33 i, static_cast<float*>(buffer_list->mBuffers[i].mData)); |
| 42 } | 34 } |
| 43 | 35 |
| 44 // Finally set the actual length. | 36 // Finally set the actual length. |
| 45 bus->set_frames(frames); | 37 bus->set_frames(frames); |
| 46 } | 38 } |
| 47 | 39 |
| 48 AUHALStream::AUHALStream( | 40 AUHALStream::AUHALStream( |
| 49 AudioManagerMac* manager, | 41 AudioManagerMac* manager, |
| 50 const AudioParameters& params, | 42 const AudioParameters& params, |
| 51 AudioDeviceID device) | 43 AudioDeviceID device) |
| 52 : manager_(manager), | 44 : manager_(manager), |
| 53 params_(params), | 45 params_(params), |
| 54 input_channels_(params_.input_channels()), | |
| 55 output_channels_(params_.channels()), | 46 output_channels_(params_.channels()), |
| 56 number_of_frames_(params_.frames_per_buffer()), | 47 number_of_frames_(params_.frames_per_buffer()), |
| 57 source_(NULL), | 48 source_(NULL), |
| 58 device_(device), | 49 device_(device), |
| 59 audio_unit_(0), | 50 audio_unit_(0), |
| 60 volume_(1), | 51 volume_(1), |
| 61 hardware_latency_frames_(0), | 52 hardware_latency_frames_(0), |
| 62 stopped_(false), | 53 stopped_(false), |
| 63 input_buffer_list_(NULL), | |
| 64 current_hardware_pending_bytes_(0) { | 54 current_hardware_pending_bytes_(0) { |
| 65 // We must have a manager. | 55 // We must have a manager. |
| 66 DCHECK(manager_); | 56 DCHECK(manager_); |
| 67 | 57 |
| 68 VLOG(1) << "AUHALStream::AUHALStream()"; | 58 VLOG(1) << "AUHALStream::AUHALStream()"; |
| 69 VLOG(1) << "Device: " << device; | 59 VLOG(1) << "Device: " << device; |
| 70 VLOG(1) << "Input channels: " << input_channels_; | |
| 71 VLOG(1) << "Output channels: " << output_channels_; | 60 VLOG(1) << "Output channels: " << output_channels_; |
| 72 VLOG(1) << "Sample rate: " << params_.sample_rate(); | 61 VLOG(1) << "Sample rate: " << params_.sample_rate(); |
| 73 VLOG(1) << "Buffer size: " << number_of_frames_; | 62 VLOG(1) << "Buffer size: " << number_of_frames_; |
| 74 } | 63 } |
| 75 | 64 |
| 76 AUHALStream::~AUHALStream() { | 65 AUHALStream::~AUHALStream() { |
| 77 } | 66 } |
| 78 | 67 |
| 79 bool AUHALStream::Open() { | 68 bool AUHALStream::Open() { |
| 80 // Get the total number of input and output channels that the | 69 // Get the total number of output channels that the |
| 81 // hardware supports. | 70 // hardware supports. |
| 82 int device_input_channels; | |
| 83 bool got_input_channels = AudioManagerMac::GetDeviceChannels( | |
| 84 device_, | |
| 85 kAudioDevicePropertyScopeInput, | |
| 86 &device_input_channels); | |
| 87 | |
| 88 int device_output_channels; | 71 int device_output_channels; |
| 89 bool got_output_channels = AudioManagerMac::GetDeviceChannels( | 72 bool got_output_channels = AudioManagerMac::GetDeviceChannels( |
| 90 device_, | 73 device_, |
| 91 kAudioDevicePropertyScopeOutput, | 74 kAudioDevicePropertyScopeOutput, |
| 92 &device_output_channels); | 75 &device_output_channels); |
| 93 | 76 |
| 94 // Sanity check the requested I/O channels. | 77 // Sanity check the requested output channels. |
| 95 if (!got_input_channels || | |
| 96 input_channels_ < 0 || input_channels_ > device_input_channels) { | |
| 97 LOG(ERROR) << "AudioDevice does not support requested input channels."; | |
| 98 return false; | |
| 99 } | |
| 100 | |
| 101 if (!got_output_channels || | 78 if (!got_output_channels || |
| 102 output_channels_ <= 0 || output_channels_ > device_output_channels) { | 79 output_channels_ <= 0 || output_channels_ > device_output_channels) { |
| 103 LOG(ERROR) << "AudioDevice does not support requested output channels."; | 80 LOG(ERROR) << "AudioDevice does not support requested output channels."; |
| 104 return false; | 81 return false; |
| 105 } | 82 } |
| 106 | 83 |
| 107 // The requested sample-rate must match the hardware sample-rate. | 84 // The requested sample-rate must match the hardware sample-rate. |
| 108 int sample_rate = AudioManagerMac::HardwareSampleRateForDevice(device_); | 85 int sample_rate = AudioManagerMac::HardwareSampleRateForDevice(device_); |
| 109 | 86 |
| 110 if (sample_rate != params_.sample_rate()) { | 87 if (sample_rate != params_.sample_rate()) { |
| 111 LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate() | 88 LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate() |
| 112 << " must match the hardware sample-rate: " << sample_rate; | 89 << " must match the hardware sample-rate: " << sample_rate; |
| 113 return false; | 90 return false; |
| 114 } | 91 } |
| 115 | 92 |
| 116 CreateIOBusses(); | 93 // The output bus will wrap the AudioBufferList given to us in |
| 94 // the Render() callback. |
| 95 DCHECK_GT(output_channels_, 0); |
| 96 output_bus_ = AudioBus::CreateWrapper(output_channels_); |
| 117 | 97 |
| 118 bool configured = ConfigureAUHAL(); | 98 bool configured = ConfigureAUHAL(); |
| 119 if (configured) | 99 if (configured) |
| 120 hardware_latency_frames_ = GetHardwareLatency(); | 100 hardware_latency_frames_ = GetHardwareLatency(); |
| 121 | 101 |
| 122 return configured; | 102 return configured; |
| 123 } | 103 } |
| 124 | 104 |
| 125 void AUHALStream::Close() { | 105 void AUHALStream::Close() { |
| 126 if (input_buffer_list_) { | |
| 127 input_buffer_list_storage_.reset(); | |
| 128 input_buffer_list_ = NULL; | |
| 129 input_bus_.reset(NULL); | |
| 130 output_bus_.reset(NULL); | |
| 131 } | |
| 132 | |
| 133 if (audio_unit_) { | 106 if (audio_unit_) { |
| 134 OSStatus result = AudioUnitUninitialize(audio_unit_); | 107 OSStatus result = AudioUnitUninitialize(audio_unit_); |
| 135 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 108 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) |
| 136 << "AudioUnitUninitialize() failed."; | 109 << "AudioUnitUninitialize() failed."; |
| 137 result = AudioComponentInstanceDispose(audio_unit_); | 110 result = AudioComponentInstanceDispose(audio_unit_); |
| 138 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 111 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) |
| 139 << "AudioComponentInstanceDispose() failed."; | 112 << "AudioComponentInstanceDispose() failed."; |
| 140 } | 113 } |
| 141 | 114 |
| 142 // Inform the audio manager that we have been closed. This will cause our | 115 // Inform the audio manager that we have been closed. This will cause our |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 | 178 |
| 206 // Pulls on our provider to get rendered audio stream. | 179 // Pulls on our provider to get rendered audio stream. |
| 207 // Note to future hackers of this function: Do not add locks which can | 180 // Note to future hackers of this function: Do not add locks which can |
| 208 // be contended in the middle of stream processing here (starting and stopping | 181 // be contended in the middle of stream processing here (starting and stopping |
| 209 // the stream are ok) because this is running on a real-time thread. | 182 // the stream are ok) because this is running on a real-time thread. |
| 210 OSStatus AUHALStream::Render( | 183 OSStatus AUHALStream::Render( |
| 211 AudioUnitRenderActionFlags* flags, | 184 AudioUnitRenderActionFlags* flags, |
| 212 const AudioTimeStamp* output_time_stamp, | 185 const AudioTimeStamp* output_time_stamp, |
| 213 UInt32 bus_number, | 186 UInt32 bus_number, |
| 214 UInt32 number_of_frames, | 187 UInt32 number_of_frames, |
| 215 AudioBufferList* io_data) { | 188 AudioBufferList* data) { |
| 216 TRACE_EVENT0("audio", "AUHALStream::Render"); | 189 TRACE_EVENT0("audio", "AUHALStream::Render"); |
| 217 | 190 |
| 218 // If the stream parameters change for any reason, we need to insert a FIFO | 191 // If the stream parameters change for any reason, we need to insert a FIFO |
| 219 // since the OnMoreData() pipeline can't handle frame size changes. | 192 // since the OnMoreData() pipeline can't handle frame size changes. |
| 220 if (number_of_frames != number_of_frames_) { | 193 if (number_of_frames != number_of_frames_) { |
| 221 // Create a FIFO on the fly to handle any discrepancies in callback rates. | 194 // Create a FIFO on the fly to handle any discrepancies in callback rates. |
| 222 if (!audio_fifo_) { | 195 if (!audio_fifo_) { |
| 223 VLOG(1) << "Audio frame size changed from " << number_of_frames_ << " to " | 196 VLOG(1) << "Audio frame size changed from " << number_of_frames_ << " to " |
| 224 << number_of_frames << "; adding FIFO to compensate."; | 197 << number_of_frames << "; adding FIFO to compensate."; |
| 225 audio_fifo_.reset(new AudioPullFifo( | 198 audio_fifo_.reset(new AudioPullFifo( |
| 226 output_channels_, | 199 output_channels_, |
| 227 number_of_frames_, | 200 number_of_frames_, |
| 228 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); | 201 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); |
| 229 } | 202 } |
| 230 | |
| 231 // Synchronous IO is not supported in this state. | |
| 232 if (input_channels_ > 0) | |
| 233 input_bus_->Zero(); | |
| 234 } else { | |
| 235 if (input_channels_ > 0 && input_buffer_list_) { | |
| 236 // Get the input data. |input_buffer_list_| is wrapped | |
| 237 // to point to the data allocated in |input_bus_|. | |
| 238 OSStatus result = AudioUnitRender(audio_unit_, | |
| 239 flags, | |
| 240 output_time_stamp, | |
| 241 1, | |
| 242 number_of_frames, | |
| 243 input_buffer_list_); | |
| 244 if (result != noErr) | |
| 245 ZeroBufferList(input_buffer_list_); | |
| 246 } | |
| 247 } | 203 } |
| 248 | 204 |
| 249 // Make |output_bus_| wrap the output AudioBufferList. | 205 // Make |output_bus_| wrap the output AudioBufferList. |
| 250 WrapBufferList(io_data, output_bus_.get(), number_of_frames); | 206 WrapBufferList(data, output_bus_.get(), number_of_frames); |
| 251 | 207 |
| 252 // Update the playout latency. | 208 // Update the playout latency. |
| 253 const double playout_latency_frames = GetPlayoutLatency(output_time_stamp); | 209 const double playout_latency_frames = GetPlayoutLatency(output_time_stamp); |
| 254 current_hardware_pending_bytes_ = static_cast<uint32>( | 210 current_hardware_pending_bytes_ = static_cast<uint32>( |
| 255 (playout_latency_frames + 0.5) * params_.GetBytesPerFrame()); | 211 (playout_latency_frames + 0.5) * params_.GetBytesPerFrame()); |
| 256 | 212 |
| 257 if (audio_fifo_) | 213 if (audio_fifo_) |
| 258 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); | 214 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); |
| 259 else | 215 else |
| 260 ProvideInput(0, output_bus_.get()); | 216 ProvideInput(0, output_bus_.get()); |
| 261 | 217 |
| 262 return noErr; | 218 return noErr; |
| 263 } | 219 } |
| 264 | 220 |
| 265 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { | 221 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { |
| 266 base::AutoLock auto_lock(source_lock_); | 222 base::AutoLock auto_lock(source_lock_); |
| 267 if (!source_) { | 223 if (!source_) { |
| 268 dest->Zero(); | 224 dest->Zero(); |
| 269 return; | 225 return; |
| 270 } | 226 } |
| 271 | 227 |
| 272 // Supply the input data and render the output data. | 228 // Supply the input data and render the output data. |
| 273 source_->OnMoreIOData( | 229 source_->OnMoreData( |
| 274 input_bus_.get(), | |
| 275 dest, | 230 dest, |
| 276 AudioBuffersState(0, | 231 AudioBuffersState(0, |
| 277 current_hardware_pending_bytes_ + | 232 current_hardware_pending_bytes_ + |
| 278 frame_delay * params_.GetBytesPerFrame())); | 233 frame_delay * params_.GetBytesPerFrame())); |
| 279 dest->Scale(volume_); | 234 dest->Scale(volume_); |
| 280 } | 235 } |
| 281 | 236 |
| 282 // AUHAL callback. | 237 // AUHAL callback. |
| 283 OSStatus AUHALStream::InputProc( | 238 OSStatus AUHALStream::InputProc( |
| 284 void* user_data, | 239 void* user_data, |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 // the bots, probably less so in the wild. | 318 // the bots, probably less so in the wild. |
| 364 if (now_ns > output_time_ns) | 319 if (now_ns > output_time_ns) |
| 365 return 0; | 320 return 0; |
| 366 | 321 |
| 367 double delay_frames = static_cast<double> | 322 double delay_frames = static_cast<double> |
| 368 (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate); | 323 (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate); |
| 369 | 324 |
| 370 return (delay_frames + hardware_latency_frames_); | 325 return (delay_frames + hardware_latency_frames_); |
| 371 } | 326 } |
| 372 | 327 |
| 373 void AUHALStream::CreateIOBusses() { | |
| 374 if (input_channels_ > 0) { | |
| 375 // Allocate storage for the AudioBufferList used for the | |
| 376 // input data from the input AudioUnit. | |
| 377 // We allocate enough space for with one AudioBuffer per channel. | |
| 378 size_t buffer_list_size = offsetof(AudioBufferList, mBuffers[0]) + | |
| 379 (sizeof(AudioBuffer) * input_channels_); | |
| 380 input_buffer_list_storage_.reset(new uint8[buffer_list_size]); | |
| 381 | |
| 382 input_buffer_list_ = | |
| 383 reinterpret_cast<AudioBufferList*>(input_buffer_list_storage_.get()); | |
| 384 input_buffer_list_->mNumberBuffers = input_channels_; | |
| 385 | |
| 386 // |input_bus_| allocates the storage for the PCM input data. | |
| 387 input_bus_ = AudioBus::Create(input_channels_, number_of_frames_); | |
| 388 | |
| 389 // Make the AudioBufferList point to the memory in |input_bus_|. | |
| 390 UInt32 buffer_size_bytes = input_bus_->frames() * sizeof(Float32); | |
| 391 for (size_t i = 0; i < input_buffer_list_->mNumberBuffers; ++i) { | |
| 392 input_buffer_list_->mBuffers[i].mNumberChannels = 1; | |
| 393 input_buffer_list_->mBuffers[i].mDataByteSize = buffer_size_bytes; | |
| 394 input_buffer_list_->mBuffers[i].mData = input_bus_->channel(i); | |
| 395 } | |
| 396 } | |
| 397 | |
| 398 // The output bus will wrap the AudioBufferList given to us in | |
| 399 // the Render() callback. | |
| 400 DCHECK_GT(output_channels_, 0); | |
| 401 output_bus_ = AudioBus::CreateWrapper(output_channels_); | |
| 402 } | |
| 403 | |
| 404 bool AUHALStream::EnableIO(bool enable, UInt32 scope) { | |
| 405 // See Apple technote for details about the EnableIO property. | |
| 406 // Note that we use bus 1 for input and bus 0 for output: | |
| 407 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html | |
| 408 UInt32 enable_IO = enable ? 1 : 0; | |
| 409 OSStatus result = AudioUnitSetProperty( | |
| 410 audio_unit_, | |
| 411 kAudioOutputUnitProperty_EnableIO, | |
| 412 scope, | |
| 413 (scope == kAudioUnitScope_Input) ? 1 : 0, | |
| 414 &enable_IO, | |
| 415 sizeof(enable_IO)); | |
| 416 return (result == noErr); | |
| 417 } | |
| 418 | |
| 419 bool AUHALStream::SetStreamFormat( | 328 bool AUHALStream::SetStreamFormat( |
| 420 AudioStreamBasicDescription* desc, | 329 AudioStreamBasicDescription* desc, |
| 421 int channels, | 330 int channels, |
| 422 UInt32 scope, | 331 UInt32 scope, |
| 423 UInt32 element) { | 332 UInt32 element) { |
| 424 DCHECK(desc); | 333 DCHECK(desc); |
| 425 AudioStreamBasicDescription& format = *desc; | 334 AudioStreamBasicDescription& format = *desc; |
| 426 | 335 |
| 427 format.mSampleRate = params_.sample_rate(); | 336 format.mSampleRate = params_.sample_rate(); |
| 428 format.mFormatID = kAudioFormatLinearPCM; | 337 format.mFormatID = kAudioFormatLinearPCM; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 439 audio_unit_, | 348 audio_unit_, |
| 440 kAudioUnitProperty_StreamFormat, | 349 kAudioUnitProperty_StreamFormat, |
| 441 scope, | 350 scope, |
| 442 element, | 351 element, |
| 443 &format, | 352 &format, |
| 444 sizeof(format)); | 353 sizeof(format)); |
| 445 return (result == noErr); | 354 return (result == noErr); |
| 446 } | 355 } |
| 447 | 356 |
| 448 bool AUHALStream::ConfigureAUHAL() { | 357 bool AUHALStream::ConfigureAUHAL() { |
| 449 if (device_ == kAudioObjectUnknown || | 358 if (device_ == kAudioObjectUnknown || output_channels_ == 0) |
| 450 (input_channels_ == 0 && output_channels_ == 0)) | |
| 451 return false; | 359 return false; |
| 452 | 360 |
| 453 AudioComponentDescription desc = { | 361 AudioComponentDescription desc = { |
| 454 kAudioUnitType_Output, | 362 kAudioUnitType_Output, |
| 455 kAudioUnitSubType_HALOutput, | 363 kAudioUnitSubType_HALOutput, |
| 456 kAudioUnitManufacturer_Apple, | 364 kAudioUnitManufacturer_Apple, |
| 457 0, | 365 0, |
| 458 0 | 366 0 |
| 459 }; | 367 }; |
| 460 AudioComponent comp = AudioComponentFindNext(0, &desc); | 368 AudioComponent comp = AudioComponentFindNext(0, &desc); |
| 461 if (!comp) | 369 if (!comp) |
| 462 return false; | 370 return false; |
| 463 | 371 |
| 464 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_); | 372 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_); |
| 465 if (result != noErr) { | 373 if (result != noErr) { |
| 466 OSSTATUS_DLOG(ERROR, result) << "AudioComponentInstanceNew() failed."; | 374 OSSTATUS_DLOG(ERROR, result) << "AudioComponentInstanceNew() failed."; |
| 467 return false; | 375 return false; |
| 468 } | 376 } |
| 469 | 377 |
| 470 // Enable input and output as appropriate. | 378 // Enable output as appropriate. |
| 471 if (!EnableIO(input_channels_ > 0, kAudioUnitScope_Input)) | 379 // See Apple technote for details about the EnableIO property. |
| 472 return false; | 380 // Note that we use bus 1 for input and bus 0 for output: |
| 473 if (!EnableIO(output_channels_ > 0, kAudioUnitScope_Output)) | 381 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html |
| 382 UInt32 enable_IO = 1; |
| 383 result = AudioUnitSetProperty( |
| 384 audio_unit_, |
| 385 kAudioOutputUnitProperty_EnableIO, |
| 386 kAudioUnitScope_Output, |
| 387 0, |
| 388 &enable_IO, |
| 389 sizeof(enable_IO)); |
| 390 if (result != noErr) |
| 474 return false; | 391 return false; |
| 475 | 392 |
| 476 // Set the device to be used with the AUHAL AudioUnit. | 393 // Set the device to be used with the AUHAL AudioUnit. |
| 477 result = AudioUnitSetProperty( | 394 result = AudioUnitSetProperty( |
| 478 audio_unit_, | 395 audio_unit_, |
| 479 kAudioOutputUnitProperty_CurrentDevice, | 396 kAudioOutputUnitProperty_CurrentDevice, |
| 480 kAudioUnitScope_Global, | 397 kAudioUnitScope_Global, |
| 481 0, | 398 0, |
| 482 &device_, | 399 &device_, |
| 483 sizeof(AudioDeviceID)); | 400 sizeof(AudioDeviceID)); |
| 484 if (result != noErr) | 401 if (result != noErr) |
| 485 return false; | 402 return false; |
| 486 | 403 |
| 487 // Set stream formats. | 404 // Set stream formats. |
| 488 // See Apple's tech note for details on the peculiar way that | 405 // See Apple's tech note for details on the peculiar way that |
| 489 // inputs and outputs are handled in the AUHAL concerning scope and bus | 406 // inputs and outputs are handled in the AUHAL concerning scope and bus |
| 490 // (element) numbers: | 407 // (element) numbers: |
| 491 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html | 408 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html |
| 492 | 409 |
| 493 if (input_channels_ > 0) { | 410 if (!SetStreamFormat(&output_format_, |
| 494 if (!SetStreamFormat(&input_format_, | 411 output_channels_, |
| 495 input_channels_, | 412 kAudioUnitScope_Input, |
| 496 kAudioUnitScope_Output, | 413 0)) { |
| 497 1)) | 414 return false; |
| 498 return false; | |
| 499 } | |
| 500 | |
| 501 if (output_channels_ > 0) { | |
| 502 if (!SetStreamFormat(&output_format_, | |
| 503 output_channels_, | |
| 504 kAudioUnitScope_Input, | |
| 505 0)) | |
| 506 return false; | |
| 507 } | 415 } |
| 508 | 416 |
| 509 // Set the buffer frame size. | 417 // Set the buffer frame size. |
| 510 // WARNING: Setting this value changes the frame size for all output audio | 418 // WARNING: Setting this value changes the frame size for all output audio |
| 511 // units in the current process. As a result, the AURenderCallback must be | 419 // units in the current process. As a result, the AURenderCallback must be |
| 512 // able to handle arbitrary buffer sizes and FIFO appropriately. | 420 // able to handle arbitrary buffer sizes and FIFO appropriately. |
| 513 UInt32 buffer_size = 0; | 421 UInt32 buffer_size = 0; |
| 514 UInt32 property_size = sizeof(buffer_size); | 422 UInt32 property_size = sizeof(buffer_size); |
| 515 result = AudioUnitGetProperty(audio_unit_, | 423 result = AudioUnitGetProperty(audio_unit_, |
| 516 kAudioDevicePropertyBufferFrameSize, | 424 kAudioDevicePropertyBufferFrameSize, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 result = AudioUnitInitialize(audio_unit_); | 467 result = AudioUnitInitialize(audio_unit_); |
| 560 if (result != noErr) { | 468 if (result != noErr) { |
| 561 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed."; | 469 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed."; |
| 562 return false; | 470 return false; |
| 563 } | 471 } |
| 564 | 472 |
| 565 return true; | 473 return true; |
| 566 } | 474 } |
| 567 | 475 |
| 568 } // namespace media | 476 } // namespace media |
| OLD | NEW |