Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 // 4) At some point some thread will call Stop(), which we handle by directly | 40 // 4) At some point some thread will call Stop(), which we handle by directly |
| 41 // stopping the default output Audio Unit. | 41 // stopping the default output Audio Unit. |
| 42 // 6) The same thread that called stop will call Close() where we cleanup | 42 // 6) The same thread that called stop will call Close() where we cleanup |
| 43 // and notify the audio manager, which likely will destroy this object. | 43 // and notify the audio manager, which likely will destroy this object. |
| 44 | 44 |
| 45 AUAudioOutputStream::AUAudioOutputStream( | 45 AUAudioOutputStream::AUAudioOutputStream( |
| 46 AudioManagerMac* manager, const AudioParameters& params) | 46 AudioManagerMac* manager, const AudioParameters& params) |
| 47 : manager_(manager), | 47 : manager_(manager), |
| 48 source_(NULL), | 48 source_(NULL), |
| 49 output_unit_(0), | 49 output_unit_(0), |
| 50 volume_(1) { | 50 output_device_id_(kAudioDeviceUnknown), |
| 51 volume_(1), | |
| 52 hardware_latency_frames_(0) { | |
| 51 // We must have a manager. | 53 // We must have a manager. |
| 52 DCHECK(manager_); | 54 DCHECK(manager_); |
| 53 // A frame is one sample across all channels. In interleaved audio the per | 55 // A frame is one sample across all channels. In interleaved audio the per |
| 54 // frame fields identify the set of n |channels|. In uncompressed audio, a | 56 // frame fields identify the set of n |channels|. In uncompressed audio, a |
| 55 // packet is always one frame. | 57 // packet is always one frame. |
| 56 format_.mSampleRate = params.sample_rate; | 58 format_.mSampleRate = params.sample_rate; |
| 57 format_.mFormatID = kAudioFormatLinearPCM; | 59 format_.mFormatID = kAudioFormatLinearPCM; |
| 58 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | | 60 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | |
| 59 kLinearPCMFormatFlagIsSignedInteger; | 61 kLinearPCMFormatFlagIsSignedInteger; |
| 60 format_.mBitsPerChannel = params.bits_per_sample; | 62 format_.mBitsPerChannel = params.bits_per_sample; |
| 61 format_.mChannelsPerFrame = params.channels; | 63 format_.mChannelsPerFrame = params.channels; |
| 62 format_.mFramesPerPacket = 1; | 64 format_.mFramesPerPacket = 1; |
| 63 format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels) / 8; | 65 format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels) / 8; |
| 64 format_.mBytesPerFrame = format_.mBytesPerPacket; | 66 format_.mBytesPerFrame = format_.mBytesPerPacket; |
| 65 format_.mReserved = 0; | 67 format_.mReserved = 0; |
| 66 | 68 |
| 67 // Calculate the number of sample frames per callback. | 69 // Calculate the number of sample frames per callback. |
| 68 number_of_frames_ = params.GetPacketSize() / format_.mBytesPerPacket; | 70 number_of_frames_ = params.GetPacketSize() / format_.mBytesPerPacket; |
| 69 } | 71 } |
| 70 | 72 |
| 71 AUAudioOutputStream::~AUAudioOutputStream() { | 73 AUAudioOutputStream::~AUAudioOutputStream() { |
| 72 } | 74 } |
| 73 | 75 |
| 74 bool AUAudioOutputStream::Open() { | 76 bool AUAudioOutputStream::Open() { |
| 77 // Obtain the current input device selected by the user. | |
| 78 UInt32 size = sizeof(output_device_id_); | |
| 79 OSStatus result = AudioHardwareGetProperty( | |
| 80 kAudioHardwarePropertyDefaultOutputDevice, | |
| 81 &size, | |
| 82 &output_device_id_); | |
| 83 DCHECK_EQ(result, 0); | |
| 84 if (result) | |
| 85 return false; | |
| 86 | |
| 75 // Open and initialize the DefaultOutputUnit. | 87 // Open and initialize the DefaultOutputUnit. |
| 76 Component comp; | 88 Component comp; |
| 77 ComponentDescription desc; | 89 ComponentDescription desc; |
| 78 | 90 |
| 79 desc.componentType = kAudioUnitType_Output; | 91 desc.componentType = kAudioUnitType_Output; |
| 80 desc.componentSubType = kAudioUnitSubType_DefaultOutput; | 92 desc.componentSubType = kAudioUnitSubType_DefaultOutput; |
| 81 desc.componentManufacturer = kAudioUnitManufacturer_Apple; | 93 desc.componentManufacturer = kAudioUnitManufacturer_Apple; |
| 82 desc.componentFlags = 0; | 94 desc.componentFlags = 0; |
| 83 desc.componentFlagsMask = 0; | 95 desc.componentFlagsMask = 0; |
| 84 comp = FindNextComponent(0, &desc); | 96 comp = FindNextComponent(0, &desc); |
| 85 DCHECK(comp); | 97 DCHECK(comp); |
| 86 | 98 |
| 87 OSStatus result = OpenAComponent(comp, &output_unit_); | 99 result = OpenAComponent(comp, &output_unit_); |
| 88 DCHECK_EQ(result, 0); | 100 DCHECK_EQ(result, 0); |
| 89 if (result) | 101 if (result) |
| 90 return false; | 102 return false; |
| 91 | 103 |
| 92 result = AudioUnitInitialize(output_unit_); | 104 result = AudioUnitInitialize(output_unit_); |
| 93 | 105 |
| 94 DCHECK_EQ(result, 0); | 106 DCHECK_EQ(result, 0); |
| 95 if (result) | 107 if (result) |
| 96 return false; | 108 return false; |
| 97 | 109 |
| 110 // Gets the playout device hardware latency and stores the value. | |
| 111 hardware_latency_frames_ = GetHardwareLatency(); | |
| 112 | |
| 98 return Configure(); | 113 return Configure(); |
| 99 } | 114 } |
| 100 | 115 |
| 101 bool AUAudioOutputStream::Configure() { | 116 bool AUAudioOutputStream::Configure() { |
| 102 // Set the render callback. | 117 // Set the render callback. |
| 103 AURenderCallbackStruct input; | 118 AURenderCallbackStruct input; |
| 104 input.inputProc = InputProc; | 119 input.inputProc = InputProc; |
| 105 input.inputProcRefCon = this; | 120 input.inputProcRefCon = this; |
| 106 OSStatus result = AudioUnitSetProperty( | 121 OSStatus result = AudioUnitSetProperty( |
| 107 output_unit_, | 122 output_unit_, |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 void AUAudioOutputStream::GetVolume(double* volume) { | 193 void AUAudioOutputStream::GetVolume(double* volume) { |
| 179 if (!output_unit_) | 194 if (!output_unit_) |
| 180 return; | 195 return; |
| 181 *volume = volume_; | 196 *volume = volume_; |
| 182 } | 197 } |
| 183 | 198 |
| 184 // Pulls on our provider to get rendered audio stream. | 199 // Pulls on our provider to get rendered audio stream. |
| 185 // Note to future hackers of this function: Do not add locks here because this | 200 // Note to future hackers of this function: Do not add locks here because this |
| 186 // is running on a real-time thread (for low-latency). | 201 // is running on a real-time thread (for low-latency). |
| 187 OSStatus AUAudioOutputStream::Render(UInt32 number_of_frames, | 202 OSStatus AUAudioOutputStream::Render(UInt32 number_of_frames, |
| 188 AudioBufferList* io_data) { | 203 AudioBufferList* io_data, |
| 204 const AudioTimeStamp* output_time_stamp) { | |
| 205 // Update the playout latency. | |
| 206 double playout_latency_frames = GetPlayoutLatency(output_time_stamp); | |
| 207 | |
| 189 AudioBuffer& buffer = io_data->mBuffers[0]; | 208 AudioBuffer& buffer = io_data->mBuffers[0]; |
| 190 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); | 209 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); |
| 210 uint32 hardware_pending_bytes = static_cast<uint32> | |
| 211 (playout_latency_frames * format_.mBytesPerFrame + 0.5); | |
| 191 uint32 filled = source_->OnMoreData( | 212 uint32 filled = source_->OnMoreData( |
| 192 this, audio_data, buffer.mDataByteSize, AudioBuffersState(0, 0)); | 213 this, audio_data, buffer.mDataByteSize, |
| 214 AudioBuffersState(0, hardware_pending_bytes)); | |
| 193 | 215 |
| 194 // Handle channel order for 5.1 audio. | 216 // Handle channel order for 5.1 audio. |
| 195 if (format_.mChannelsPerFrame == 6) { | 217 if (format_.mChannelsPerFrame == 6) { |
| 196 if (format_.mBitsPerChannel == 8) { | 218 if (format_.mBitsPerChannel == 8) { |
| 197 SwizzleCoreAudioLayout5_1(reinterpret_cast<uint8*>(audio_data), filled); | 219 SwizzleCoreAudioLayout5_1(reinterpret_cast<uint8*>(audio_data), filled); |
| 198 } else if (format_.mBitsPerChannel == 16) { | 220 } else if (format_.mBitsPerChannel == 16) { |
| 199 SwizzleCoreAudioLayout5_1(reinterpret_cast<int16*>(audio_data), filled); | 221 SwizzleCoreAudioLayout5_1(reinterpret_cast<int16*>(audio_data), filled); |
| 200 } else if (format_.mBitsPerChannel == 32) { | 222 } else if (format_.mBitsPerChannel == 32) { |
| 201 SwizzleCoreAudioLayout5_1(reinterpret_cast<int32*>(audio_data), filled); | 223 SwizzleCoreAudioLayout5_1(reinterpret_cast<int32*>(audio_data), filled); |
| 202 } | 224 } |
| 203 } | 225 } |
| 204 | 226 |
| 205 return noErr; | 227 return noErr; |
| 206 } | 228 } |
| 207 | 229 |
| 208 // DefaultOutputUnit callback | 230 // DefaultOutputUnit callback |
| 209 OSStatus AUAudioOutputStream::InputProc(void* user_data, | 231 OSStatus AUAudioOutputStream::InputProc(void* user_data, |
| 210 AudioUnitRenderActionFlags*, | 232 AudioUnitRenderActionFlags*, |
| 211 const AudioTimeStamp*, | 233 const AudioTimeStamp* output_time_stamp, |
| 212 UInt32, | 234 UInt32, |
| 213 UInt32 number_of_frames, | 235 UInt32 number_of_frames, |
| 214 AudioBufferList* io_data) { | 236 AudioBufferList* io_data) { |
| 215 AUAudioOutputStream* audio_output = | 237 AUAudioOutputStream* audio_output = |
| 216 static_cast<AUAudioOutputStream*>(user_data); | 238 static_cast<AUAudioOutputStream*>(user_data); |
| 217 DCHECK(audio_output); | 239 DCHECK(audio_output); |
| 218 if (!audio_output) | 240 if (!audio_output) |
| 219 return -1; | 241 return -1; |
| 220 | 242 |
| 221 return audio_output->Render(number_of_frames, io_data); | 243 return audio_output->Render(number_of_frames, io_data, output_time_stamp); |
| 222 } | 244 } |
| 223 | 245 |
| 224 double AUAudioOutputStream::HardwareSampleRate() { | 246 double AUAudioOutputStream::HardwareSampleRate() { |
| 225 // Determine the default output device's sample-rate. | 247 // Determine the default output device's sample-rate. |
| 226 AudioDeviceID device_id = kAudioDeviceUnknown; | 248 AudioDeviceID device_id = kAudioDeviceUnknown; |
| 227 UInt32 info_size = sizeof(device_id); | 249 UInt32 info_size = sizeof(device_id); |
| 228 | 250 |
| 229 AudioObjectPropertyAddress default_output_device_address = { | 251 AudioObjectPropertyAddress default_output_device_address = { |
| 230 kAudioHardwarePropertyDefaultOutputDevice, | 252 kAudioHardwarePropertyDefaultOutputDevice, |
| 231 kAudioObjectPropertyScopeGlobal, | 253 kAudioObjectPropertyScopeGlobal, |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 254 0, | 276 0, |
| 255 0, | 277 0, |
| 256 &info_size, | 278 &info_size, |
| 257 &nominal_sample_rate); | 279 &nominal_sample_rate); |
| 258 DCHECK_EQ(result, 0); | 280 DCHECK_EQ(result, 0); |
| 259 if (result) | 281 if (result) |
| 260 return 0.0; // error | 282 return 0.0; // error |
| 261 | 283 |
| 262 return nominal_sample_rate; | 284 return nominal_sample_rate; |
| 263 } | 285 } |
| 286 | |
| 287 double AUAudioOutputStream::GetHardwareLatency() { | |
| 288 // Get audio unit latency. | |
| 289 Float64 audio_unit_latency_sec = 0.0; | |
| 290 UInt32 size = sizeof(audio_unit_latency_sec); | |
| 291 OSStatus result = AudioUnitGetProperty(output_unit_, | |
| 292 kAudioUnitProperty_Latency, | |
| 293 kAudioUnitScope_Global, | |
| 294 0, | |
| 295 &audio_unit_latency_sec, | |
| 296 &size); | |
| 297 if (result) | |
|
scherkus (not reviewing)
2011/10/19 18:23:57
ditto on using {} and returning 0
no longer working on chromium
2011/10/20 11:25:51
Done.
| |
| 298 DLOG(WARNING) << "GetHardwareLatency: Could not get audio unit latency."; | |
| 299 | |
| 300 // Get audio device latency. | |
| 301 UInt32 device_latency_frames = 0; | |
| 302 size = sizeof(device_latency_frames); | |
| 303 result = AudioDeviceGetProperty(output_device_id_, | |
| 304 0, | |
| 305 false, | |
| 306 kAudioDevicePropertyLatency, | |
| 307 &size, | |
| 308 &device_latency_frames); | |
| 309 if (result) | |
| 310 DLOG(WARNING) << "GetHardwareLatency: Could not get device latency."; | |
| 311 | |
| 312 // Get the stream latency. | |
| 313 UInt32 stream_latency_frames = 0; | |
| 314 result = AudioDeviceGetPropertyInfo(output_device_id_, | |
| 315 0, | |
| 316 false, | |
| 317 kAudioDevicePropertyStreams, | |
| 318 &size, | |
| 319 NULL); | |
| 320 if (!result) { | |
| 321 scoped_ptr_malloc<AudioStreamID> | |
| 322 streams(reinterpret_cast<AudioStreamID*>(malloc(size))); | |
| 323 AudioStreamID* stream_ids = streams.get(); | |
| 324 result = AudioDeviceGetProperty(output_device_id_, | |
| 325 0, | |
| 326 false, | |
| 327 kAudioDevicePropertyStreams, | |
| 328 &size, | |
| 329 stream_ids); | |
| 330 if (!result) | |
| 331 result = AudioStreamGetProperty(stream_ids[0], | |
| 332 0, | |
| 333 kAudioStreamPropertyLatency, | |
| 334 &size, | |
| 335 &stream_latency_frames); | |
| 336 } | |
| 337 // Log the warning if it fails to get stream latency. | |
| 338 if (result) | |
| 339 DLOG(WARNING) << "GetHardwareLatency: Could not get stream latency."; | |
| 340 | |
| 341 // Returns the hardware latency value in freams. | |
| 342 return static_cast<double>(audio_unit_latency_sec * | |
| 343 format_.mSampleRate + device_latency_frames + stream_latency_frames); | |
| 344 } | |
| 345 | |
| 346 double AUAudioOutputStream::GetPlayoutLatency( | |
| 347 const AudioTimeStamp* output_time_stamp) { | |
| 348 // Get the delay between now and when the data is going to reach the hardware. | |
| 349 UInt64 output_time_ns = AudioConvertHostTimeToNanos( | |
| 350 output_time_stamp->mHostTime); | |
| 351 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | |
| 352 double delay_frames = static_cast<double> | |
| 353 (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate); | |
| 354 | |
| 355 return (delay_frames + hardware_latency_frames_); | |
| 356 } | |
| OLD | NEW |