| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_low_latency_output_mac.h" | 5 #include "media/audio/mac/audio_low_latency_output_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/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/mac/mac_logging.h" |
| 11 #include "media/audio/audio_util.h" | 12 #include "media/audio/audio_util.h" |
| 12 #include "media/audio/mac/audio_manager_mac.h" | 13 #include "media/audio/mac/audio_manager_mac.h" |
| 13 | 14 |
| 14 // Reorder PCM from AAC layout to Core Audio 5.1 layout. | 15 // Reorder PCM from AAC layout to Core Audio 5.1 layout. |
| 15 // TODO(fbarchard): Switch layout when ffmpeg is updated. | 16 // TODO(fbarchard): Switch layout when ffmpeg is updated. |
| 16 template<class Format> | 17 template<class Format> |
| 17 static void SwizzleCoreAudioLayout5_1(Format* b, uint32 filled) { | 18 static void SwizzleCoreAudioLayout5_1(Format* b, uint32 filled) { |
| 18 static const int kNumSurroundChannels = 6; | 19 static const int kNumSurroundChannels = 6; |
| 19 Format aac[kNumSurroundChannels]; | 20 Format aac[kNumSurroundChannels]; |
| 20 for (uint32 i = 0; i < filled; i += sizeof(aac), b += kNumSurroundChannels) { | 21 for (uint32 i = 0; i < filled; i += sizeof(aac), b += kNumSurroundChannels) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 kAudioHardwarePropertyDefaultOutputDevice, | 81 kAudioHardwarePropertyDefaultOutputDevice, |
| 81 kAudioObjectPropertyScopeGlobal, | 82 kAudioObjectPropertyScopeGlobal, |
| 82 kAudioObjectPropertyElementMaster | 83 kAudioObjectPropertyElementMaster |
| 83 }; | 84 }; |
| 84 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 85 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
| 85 &default_output_device_address, | 86 &default_output_device_address, |
| 86 0, | 87 0, |
| 87 0, | 88 0, |
| 88 &size, | 89 &size, |
| 89 &output_device_id_); | 90 &output_device_id_); |
| 90 DCHECK_EQ(result, 0); | 91 OSSTATUS_DCHECK(result == noErr, result); |
| 91 if (result) | 92 if (result) |
| 92 return false; | 93 return false; |
| 93 | 94 |
| 94 // Open and initialize the DefaultOutputUnit. | 95 // Open and initialize the DefaultOutputUnit. |
| 95 Component comp; | 96 Component comp; |
| 96 ComponentDescription desc; | 97 ComponentDescription desc; |
| 97 | 98 |
| 98 desc.componentType = kAudioUnitType_Output; | 99 desc.componentType = kAudioUnitType_Output; |
| 99 desc.componentSubType = kAudioUnitSubType_DefaultOutput; | 100 desc.componentSubType = kAudioUnitSubType_DefaultOutput; |
| 100 desc.componentManufacturer = kAudioUnitManufacturer_Apple; | 101 desc.componentManufacturer = kAudioUnitManufacturer_Apple; |
| 101 desc.componentFlags = 0; | 102 desc.componentFlags = 0; |
| 102 desc.componentFlagsMask = 0; | 103 desc.componentFlagsMask = 0; |
| 103 comp = FindNextComponent(0, &desc); | 104 comp = FindNextComponent(0, &desc); |
| 104 DCHECK(comp); | 105 DCHECK(comp); |
| 105 | 106 |
| 106 result = OpenAComponent(comp, &output_unit_); | 107 result = OpenAComponent(comp, &output_unit_); |
| 107 DCHECK_EQ(result, 0); | 108 OSSTATUS_DCHECK(result == noErr, result); |
| 108 if (result) | 109 if (result) |
| 109 return false; | 110 return false; |
| 110 | 111 |
| 111 result = AudioUnitInitialize(output_unit_); | 112 result = AudioUnitInitialize(output_unit_); |
| 112 | 113 OSSTATUS_DCHECK(result == noErr, result); |
| 113 DCHECK_EQ(result, 0); | |
| 114 if (result) | 114 if (result) |
| 115 return false; | 115 return false; |
| 116 | 116 |
| 117 hardware_latency_frames_ = GetHardwareLatency(); | 117 hardware_latency_frames_ = GetHardwareLatency(); |
| 118 | 118 |
| 119 return Configure(); | 119 return Configure(); |
| 120 } | 120 } |
| 121 | 121 |
| 122 bool AUAudioOutputStream::Configure() { | 122 bool AUAudioOutputStream::Configure() { |
| 123 // Set the render callback. | 123 // Set the render callback. |
| 124 AURenderCallbackStruct input; | 124 AURenderCallbackStruct input; |
| 125 input.inputProc = InputProc; | 125 input.inputProc = InputProc; |
| 126 input.inputProcRefCon = this; | 126 input.inputProcRefCon = this; |
| 127 OSStatus result = AudioUnitSetProperty( | 127 OSStatus result = AudioUnitSetProperty( |
| 128 output_unit_, | 128 output_unit_, |
| 129 kAudioUnitProperty_SetRenderCallback, | 129 kAudioUnitProperty_SetRenderCallback, |
| 130 kAudioUnitScope_Global, | 130 kAudioUnitScope_Global, |
| 131 0, | 131 0, |
| 132 &input, | 132 &input, |
| 133 sizeof(input)); | 133 sizeof(input)); |
| 134 | 134 OSSTATUS_DCHECK(result == noErr, result); |
| 135 DCHECK_EQ(result, 0); | |
| 136 if (result) | 135 if (result) |
| 137 return false; | 136 return false; |
| 138 | 137 |
| 139 // Set the stream format. | 138 // Set the stream format. |
| 140 result = AudioUnitSetProperty( | 139 result = AudioUnitSetProperty( |
| 141 output_unit_, | 140 output_unit_, |
| 142 kAudioUnitProperty_StreamFormat, | 141 kAudioUnitProperty_StreamFormat, |
| 143 kAudioUnitScope_Input, | 142 kAudioUnitScope_Input, |
| 144 0, | 143 0, |
| 145 &format_, | 144 &format_, |
| 146 sizeof(format_)); | 145 sizeof(format_)); |
| 147 DCHECK_EQ(result, 0); | 146 OSSTATUS_DCHECK(result == noErr, result); |
| 148 if (result) | 147 if (result) |
| 149 return false; | 148 return false; |
| 150 | 149 |
| 151 // Set the buffer frame size. | 150 // Set the buffer frame size. |
| 152 UInt32 buffer_size = number_of_frames_; | 151 UInt32 buffer_size = number_of_frames_; |
| 153 result = AudioUnitSetProperty( | 152 result = AudioUnitSetProperty( |
| 154 output_unit_, | 153 output_unit_, |
| 155 kAudioDevicePropertyBufferFrameSize, | 154 kAudioDevicePropertyBufferFrameSize, |
| 156 kAudioUnitScope_Output, | 155 kAudioUnitScope_Output, |
| 157 0, | 156 0, |
| 158 &buffer_size, | 157 &buffer_size, |
| 159 sizeof(buffer_size)); | 158 sizeof(buffer_size)); |
| 160 DCHECK_EQ(result, 0); | 159 OSSTATUS_DCHECK(result == noErr, result); |
| 161 if (result) | 160 if (result) |
| 162 return false; | 161 return false; |
| 163 | 162 |
| 164 return true; | 163 return true; |
| 165 } | 164 } |
| 166 | 165 |
| 167 void AUAudioOutputStream::Close() { | 166 void AUAudioOutputStream::Close() { |
| 168 if (output_unit_) | 167 if (output_unit_) |
| 169 CloseComponent(output_unit_); | 168 CloseComponent(output_unit_); |
| 170 | 169 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 kAudioHardwarePropertyDefaultOutputDevice, | 261 kAudioHardwarePropertyDefaultOutputDevice, |
| 263 kAudioObjectPropertyScopeGlobal, | 262 kAudioObjectPropertyScopeGlobal, |
| 264 kAudioObjectPropertyElementMaster | 263 kAudioObjectPropertyElementMaster |
| 265 }; | 264 }; |
| 266 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 265 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
| 267 &default_output_device_address, | 266 &default_output_device_address, |
| 268 0, | 267 0, |
| 269 0, | 268 0, |
| 270 &info_size, | 269 &info_size, |
| 271 &device_id); | 270 &device_id); |
| 272 DCHECK_EQ(result, 0); | 271 OSSTATUS_DCHECK(result == noErr, result); |
| 273 if (result) | 272 if (result) |
| 274 return 0.0; // error | 273 return 0.0; // error |
| 275 | 274 |
| 276 Float64 nominal_sample_rate; | 275 Float64 nominal_sample_rate; |
| 277 info_size = sizeof(nominal_sample_rate); | 276 info_size = sizeof(nominal_sample_rate); |
| 278 | 277 |
| 279 AudioObjectPropertyAddress nominal_sample_rate_address = { | 278 AudioObjectPropertyAddress nominal_sample_rate_address = { |
| 280 kAudioDevicePropertyNominalSampleRate, | 279 kAudioDevicePropertyNominalSampleRate, |
| 281 kAudioObjectPropertyScopeGlobal, | 280 kAudioObjectPropertyScopeGlobal, |
| 282 kAudioObjectPropertyElementMaster | 281 kAudioObjectPropertyElementMaster |
| 283 }; | 282 }; |
| 284 result = AudioObjectGetPropertyData(device_id, | 283 result = AudioObjectGetPropertyData(device_id, |
| 285 &nominal_sample_rate_address, | 284 &nominal_sample_rate_address, |
| 286 0, | 285 0, |
| 287 0, | 286 0, |
| 288 &info_size, | 287 &info_size, |
| 289 &nominal_sample_rate); | 288 &nominal_sample_rate); |
| 290 DCHECK_EQ(result, 0); | 289 OSSTATUS_DCHECK(result == noErr, result); |
| 291 if (result) | 290 if (result) |
| 292 return 0.0; // error | 291 return 0.0; // error |
| 293 | 292 |
| 294 return nominal_sample_rate; | 293 return nominal_sample_rate; |
| 295 } | 294 } |
| 296 | 295 |
| 297 double AUAudioOutputStream::GetHardwareLatency() { | 296 double AUAudioOutputStream::GetHardwareLatency() { |
| 298 if (!output_unit_ || output_device_id_ == kAudioObjectUnknown) { | 297 if (!output_unit_ || output_device_id_ == kAudioObjectUnknown) { |
| 299 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; | 298 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; |
| 300 return 0.0; | 299 return 0.0; |
| 301 } | 300 } |
| 302 | 301 |
| 303 // Get audio unit latency. | 302 // Get audio unit latency. |
| 304 Float64 audio_unit_latency_sec = 0.0; | 303 Float64 audio_unit_latency_sec = 0.0; |
| 305 UInt32 size = sizeof(audio_unit_latency_sec); | 304 UInt32 size = sizeof(audio_unit_latency_sec); |
| 306 OSStatus result = AudioUnitGetProperty(output_unit_, | 305 OSStatus result = AudioUnitGetProperty(output_unit_, |
| 307 kAudioUnitProperty_Latency, | 306 kAudioUnitProperty_Latency, |
| 308 kAudioUnitScope_Global, | 307 kAudioUnitScope_Global, |
| 309 0, | 308 0, |
| 310 &audio_unit_latency_sec, | 309 &audio_unit_latency_sec, |
| 311 &size); | 310 &size); |
| 312 DLOG_IF(WARNING, result != noErr) << "Could not get audio unit latency."; | 311 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) |
| 312 << "Could not get audio unit latency"; |
| 313 | 313 |
| 314 // Get output audio device latency. | 314 // Get output audio device latency. |
| 315 AudioObjectPropertyAddress property_address = { | 315 AudioObjectPropertyAddress property_address = { |
| 316 kAudioDevicePropertyLatency, | 316 kAudioDevicePropertyLatency, |
| 317 kAudioDevicePropertyScopeOutput, | 317 kAudioDevicePropertyScopeOutput, |
| 318 kAudioObjectPropertyElementMaster | 318 kAudioObjectPropertyElementMaster |
| 319 }; | 319 }; |
| 320 UInt32 device_latency_frames = 0; | 320 UInt32 device_latency_frames = 0; |
| 321 size = sizeof(device_latency_frames); | 321 size = sizeof(device_latency_frames); |
| 322 result = AudioObjectGetPropertyData(output_device_id_, | 322 result = AudioObjectGetPropertyData(output_device_id_, |
| 323 &property_address, | 323 &property_address, |
| 324 0, | 324 0, |
| 325 NULL, | 325 NULL, |
| 326 &size, | 326 &size, |
| 327 &device_latency_frames); | 327 &device_latency_frames); |
| 328 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; | 328 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) |
| 329 << "Could not get audio device latency"; |
| 329 | 330 |
| 330 // Get the stream latency. | 331 // Get the stream latency. |
| 331 property_address.mSelector = kAudioDevicePropertyStreams; | 332 property_address.mSelector = kAudioDevicePropertyStreams; |
| 332 UInt32 stream_latency_frames = 0; | 333 UInt32 stream_latency_frames = 0; |
| 333 result = AudioObjectGetPropertyDataSize(output_device_id_, | 334 result = AudioObjectGetPropertyDataSize(output_device_id_, |
| 334 &property_address, | 335 &property_address, |
| 335 0, | 336 0, |
| 336 NULL, | 337 NULL, |
| 337 &size); | 338 &size); |
| 338 if (!result) { | 339 if (!result) { |
| 339 scoped_ptr_malloc<AudioStreamID> | 340 scoped_ptr_malloc<AudioStreamID> |
| 340 streams(reinterpret_cast<AudioStreamID*>(malloc(size))); | 341 streams(reinterpret_cast<AudioStreamID*>(malloc(size))); |
| 341 AudioStreamID* stream_ids = streams.get(); | 342 AudioStreamID* stream_ids = streams.get(); |
| 342 result = AudioObjectGetPropertyData(output_device_id_, | 343 result = AudioObjectGetPropertyData(output_device_id_, |
| 343 &property_address, | 344 &property_address, |
| 344 0, | 345 0, |
| 345 NULL, | 346 NULL, |
| 346 &size, | 347 &size, |
| 347 stream_ids); | 348 stream_ids); |
| 348 if (!result) { | 349 if (!result) { |
| 349 property_address.mSelector = kAudioStreamPropertyLatency; | 350 property_address.mSelector = kAudioStreamPropertyLatency; |
| 350 result = AudioObjectGetPropertyData(stream_ids[0], | 351 result = AudioObjectGetPropertyData(stream_ids[0], |
| 351 &property_address, | 352 &property_address, |
| 352 0, | 353 0, |
| 353 NULL, | 354 NULL, |
| 354 &size, | 355 &size, |
| 355 &stream_latency_frames); | 356 &stream_latency_frames); |
| 356 } | 357 } |
| 357 } | 358 } |
| 358 DLOG_IF(WARNING, result != noErr) << "Could not get audio stream latency."; | 359 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) |
| 360 << "Could not get audio stream latency"; |
| 359 | 361 |
| 360 return static_cast<double>((audio_unit_latency_sec * | 362 return static_cast<double>((audio_unit_latency_sec * |
| 361 format_.mSampleRate) + device_latency_frames + stream_latency_frames); | 363 format_.mSampleRate) + device_latency_frames + stream_latency_frames); |
| 362 } | 364 } |
| 363 | 365 |
| 364 double AUAudioOutputStream::GetPlayoutLatency( | 366 double AUAudioOutputStream::GetPlayoutLatency( |
| 365 const AudioTimeStamp* output_time_stamp) { | 367 const AudioTimeStamp* output_time_stamp) { |
| 366 // Get the delay between the moment getting the callback and the scheduled | 368 // Get the delay between the moment getting the callback and the scheduled |
| 367 // time stamp that tells when the data is going to be played out. | 369 // time stamp that tells when the data is going to be played out. |
| 368 UInt64 output_time_ns = AudioConvertHostTimeToNanos( | 370 UInt64 output_time_ns = AudioConvertHostTimeToNanos( |
| 369 output_time_stamp->mHostTime); | 371 output_time_stamp->mHostTime); |
| 370 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | 372 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
| 371 double delay_frames = static_cast<double> | 373 double delay_frames = static_cast<double> |
| 372 (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate); | 374 (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate); |
| 373 | 375 |
| 374 return (delay_frames + hardware_latency_frames_); | 376 return (delay_frames + hardware_latency_frames_); |
| 375 } | 377 } |
| OLD | NEW |