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 3 // found in the LICENSE file. 4 5 #include "media/audio/mac/audio_low_latency_output_mac.h" 6 7 #include <CoreServices/CoreServices.h> 8 9 #include "base/basictypes.h" 10 #include "base/command_line.h" 11 #include "base/logging.h" 12 #include "base/mac/mac_logging.h" 13 #include "media/audio/mac/audio_manager_mac.h" 14 #include "media/base/media_switches.h" 15 16 namespace media { 17 18 static std::ostream& operator<<(std::ostream& os, 19 const AudioStreamBasicDescription& format) { 20 os << "sample rate : " << format.mSampleRate << std::endl 21 << "format ID : " << format.mFormatID << std::endl 22 << "format flags : " << format.mFormatFlags << std::endl 23 << "bytes per packet : " << format.mBytesPerPacket << std::endl 24 << "frames per packet : " << format.mFramesPerPacket << std::endl 25 << "bytes per frame : " << format.mBytesPerFrame << std::endl 26 << "channels per frame: " << format.mChannelsPerFrame << std::endl 27 << "bits per channel : " << format.mBitsPerChannel; 28 return os; 29 } 30 31 static AudioObjectPropertyAddress kDefaultOutputDeviceAddress = { 32 kAudioHardwarePropertyDefaultOutputDevice, 33 kAudioObjectPropertyScopeGlobal, 34 kAudioObjectPropertyElementMaster 35 }; 36 37 // Overview of operation: 38 // 1) An object of AUAudioOutputStream is created by the AudioManager 39 // factory: audio_man->MakeAudioStream(). 40 // 2) Next some thread will call Open(), at that point the underlying 41 // default output Audio Unit is created and configured. 42 // 3) Then some thread will call Start(source). 43 // Then the Audio Unit is started which creates its own thread which 44 // periodically will call the source for more data as buffers are being 45 // consumed. 46 // 4) At some point some thread will call Stop(), which we handle by directly 47 // stopping the default output Audio Unit. 48 // 6) The same thread that called stop will call Close() where we cleanup 49 // and notify the audio manager, which likely will destroy this object. 50 51 AUAudioOutputStream::AUAudioOutputStream( 52 AudioManagerMac* manager, const AudioParameters& params) 53 : manager_(manager), 54 source_(NULL), 55 output_unit_(0), 56 output_device_id_(kAudioObjectUnknown), 57 volume_(1), 58 hardware_latency_frames_(0), 59 stopped_(false), 60 audio_bus_(AudioBus::Create(params)) { 61 // We must have a manager. 62 DCHECK(manager_); 63 64 // A frame is one sample across all channels. In interleaved audio the per 65 // frame fields identify the set of n |channels|. In uncompressed audio, a 66 // packet is always one frame. 67 format_.mSampleRate = params.sample_rate(); 68 format_.mFormatID = kAudioFormatLinearPCM; 69 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | 70 kLinearPCMFormatFlagIsSignedInteger; 71 format_.mBitsPerChannel = params.bits_per_sample(); 72 format_.mChannelsPerFrame = params.channels(); 73 format_.mFramesPerPacket = 1; 74 format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels()) / 8; 75 format_.mBytesPerFrame = format_.mBytesPerPacket; 76 format_.mReserved = 0; 77 78 DVLOG(1) << "Desired ouput format: " << format_; 79 80 // Calculate the number of sample frames per callback. 81 number_of_frames_ = params.frames_per_buffer(); 82 DVLOG(1) << "Number of frames per callback: " << number_of_frames_; 83 } 84 85 AUAudioOutputStream::~AUAudioOutputStream() { 86 } 87 88 bool AUAudioOutputStream::Open() { 89 // Obtain the current input device selected by the user. 90 UInt32 size = sizeof(output_device_id_); 91 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 92 &kDefaultOutputDeviceAddress, 93 0, 94 0, 95 &size, 96 &output_device_id_); 97 if (result != noErr || output_device_id_ == kAudioObjectUnknown) { 98 OSSTATUS_DLOG(ERROR, result) 99 << "Could not get default audio output device."; 100 return false; 101 } 102 103 // Open and initialize the DefaultOutputUnit. 104 AudioComponent comp; 105 AudioComponentDescription desc; 106 107 desc.componentType = kAudioUnitType_Output; 108 desc.componentSubType = kAudioUnitSubType_DefaultOutput; 109 desc.componentManufacturer = kAudioUnitManufacturer_Apple; 110 desc.componentFlags = 0; 111 desc.componentFlagsMask = 0; 112 comp = AudioComponentFindNext(0, &desc); 113 if (!comp) 114 return false; 115 116 result = AudioComponentInstanceNew(comp, &output_unit_); 117 if (result != noErr) { 118 OSSTATUS_DLOG(ERROR, result) << "AudioComponentInstanceNew() failed."; 119 return false; 120 } 121 122 result = AudioUnitInitialize(output_unit_); 123 if (result != noErr) { 124 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed."; 125 return false; 126 } 127 128 hardware_latency_frames_ = GetHardwareLatency(); 129 130 return Configure(); 131 } 132 133 bool AUAudioOutputStream::Configure() { 134 // Set the render callback. 135 AURenderCallbackStruct input; 136 input.inputProc = InputProc; 137 input.inputProcRefCon = this; 138 OSStatus result = AudioUnitSetProperty( 139 output_unit_, 140 kAudioUnitProperty_SetRenderCallback, 141 kAudioUnitScope_Global, 142 0, 143 &input, 144 sizeof(input)); 145 if (result != noErr) { 146 OSSTATUS_DLOG(ERROR, result) 147 << "AudioUnitSetProperty(kAudioUnitProperty_SetRenderCallback) failed."; 148 return false; 149 } 150 151 // Set the stream format. 152 result = AudioUnitSetProperty( 153 output_unit_, 154 kAudioUnitProperty_StreamFormat, 155 kAudioUnitScope_Input, 156 0, 157 &format_, 158 sizeof(format_)); 159 if (result != noErr) { 160 OSSTATUS_DLOG(ERROR, result) 161 << "AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed."; 162 return false; 163 } 164 165 // Set the buffer frame size. 166 // WARNING: Setting this value changes the frame size for all audio units in 167 // the current process. It's imperative that the input and output frame sizes 168 // be the same as the frames_per_buffer() returned by 169 // GetDefaultOutputStreamParameters. 170 // See http://crbug.com/154352 for details. 171 const AudioParameters hw_params = 172 manager_->GetDefaultOutputStreamParameters(); 173 if (number_of_frames_ != static_cast<size_t>(hw_params.frames_per_buffer())) { 174 DLOG(ERROR) << "Audio buffer size does not match hardware buffer size."; 175 return false; 176 } 177 178 UInt32 buffer_size = number_of_frames_; 179 result = AudioUnitSetProperty( 180 output_unit_, 181 kAudioDevicePropertyBufferFrameSize, 182 kAudioUnitScope_Output, 183 0, 184 &buffer_size, 185 sizeof(buffer_size)); 186 if (result != noErr) { 187 OSSTATUS_DLOG(ERROR, result) 188 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed."; 189 return false; 190 } 191 192 return true; 193 } 194 195 void AUAudioOutputStream::Close() { 196 if (output_unit_) 197 AudioComponentInstanceDispose(output_unit_); 198 199 // Inform the audio manager that we have been closed. This can cause our 200 // destruction. 201 manager_->ReleaseOutputStream(this); 202 } 203 204 void AUAudioOutputStream::Start(AudioSourceCallback* callback) { 205 DCHECK(callback); 206 if (!output_unit_) { 207 DLOG(ERROR) << "Open() has not been called successfully"; 208 return; 209 } 210 211 stopped_ = false; 212 { 213 base::AutoLock auto_lock(source_lock_); 214 source_ = callback; 215 } 216 217 AudioOutputUnitStart(output_unit_); 218 } 219 220 void AUAudioOutputStream::Stop() { 221 if (stopped_) 222 return; 223 224 AudioOutputUnitStop(output_unit_); 225 226 base::AutoLock auto_lock(source_lock_); 227 source_ = NULL; 228 stopped_ = true; 229 } 230 231 void AUAudioOutputStream::SetVolume(double volume) { 232 if (!output_unit_) 233 return; 234 volume_ = static_cast<float>(volume); 235 236 // TODO(crogers): set volume property 237 } 238 239 void AUAudioOutputStream::GetVolume(double* volume) { 240 if (!output_unit_) 241 return; 242 *volume = volume_; 243 } 244 245 // Pulls on our provider to get rendered audio stream. 246 // Note to future hackers of this function: Do not add locks here because this 247 // is running on a real-time thread (for low-latency). 248 OSStatus AUAudioOutputStream::Render(UInt32 number_of_frames, 249 AudioBufferList* io_data, 250 const AudioTimeStamp* output_time_stamp) { 251 // Update the playout latency. 252 double playout_latency_frames = GetPlayoutLatency(output_time_stamp); 253 254 AudioBuffer& buffer = io_data->mBuffers[0]; 255 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); 256 uint32 hardware_pending_bytes = static_cast<uint32> 257 ((playout_latency_frames + 0.5) * format_.mBytesPerFrame); 258 259 // Unfortunately AUAudioInputStream and AUAudioOutputStream share the frame 260 // size set by kAudioDevicePropertyBufferFrameSize above on a per process 261 // basis. What this means is that the |number_of_frames| value may be larger 262 // or smaller than the value set during Configure(). In this case either 263 // audio input or audio output will be broken, so just output silence. 264 // TODO(crogers): Figure out what can trigger a change in |number_of_frames|. 265 // See http://crbug.com/154352 for details. 266 if (number_of_frames != static_cast<UInt32>(audio_bus_->frames())) { 267 memset(audio_data, 0, number_of_frames * format_.mBytesPerFrame); 268 return noErr; 269 } 270 271 int frames_filled = 0; 272 { 273 // Render() shouldn't be called except between AudioOutputUnitStart() and 274 // AudioOutputUnitStop() calls, but crash reports have shown otherwise: 275 // http://crbug.com/178765. We use |source_lock_| to prevent races and 276 // crashes in Render() when |source_| is cleared. 277 base::AutoLock auto_lock(source_lock_); 278 if (!source_) { 279 memset(audio_data, 0, number_of_frames * format_.mBytesPerFrame); 280 return noErr; 281 } 282 283 frames_filled = source_->OnMoreData( 284 audio_bus_.get(), AudioBuffersState(0, hardware_pending_bytes)); 285 } 286 287 // Note: If this ever changes to output raw float the data must be clipped and 288 // sanitized since it may come from an untrusted source such as NaCl. 289 audio_bus_->Scale(volume_); 290 audio_bus_->ToInterleaved( 291 frames_filled, format_.mBitsPerChannel / 8, audio_data); 292 293 return noErr; 294 } 295 296 // DefaultOutputUnit callback 297 OSStatus AUAudioOutputStream::InputProc(void* user_data, 298 AudioUnitRenderActionFlags*, 299 const AudioTimeStamp* output_time_stamp, 300 UInt32, 301 UInt32 number_of_frames, 302 AudioBufferList* io_data) { 303 AUAudioOutputStream* audio_output = 304 static_cast<AUAudioOutputStream*>(user_data); 305 if (!audio_output) 306 return -1; 307 308 return audio_output->Render(number_of_frames, io_data, output_time_stamp); 309 } 310 311 int AUAudioOutputStream::HardwareSampleRate() { 312 // Determine the default output device's sample-rate. 313 AudioDeviceID device_id = kAudioObjectUnknown; 314 UInt32 info_size = sizeof(device_id); 315 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, 316 &kDefaultOutputDeviceAddress, 317 0, 318 0, 319 &info_size, 320 &device_id); 321 if (result != noErr || device_id == kAudioObjectUnknown) { 322 OSSTATUS_DLOG(WARNING, result) 323 << "Could not get default audio output device."; 324 return 0; 325 } 326 327 Float64 nominal_sample_rate; 328 info_size = sizeof(nominal_sample_rate); 329 330 AudioObjectPropertyAddress nominal_sample_rate_address = { 331 kAudioDevicePropertyNominalSampleRate, 332 kAudioObjectPropertyScopeGlobal, 333 kAudioObjectPropertyElementMaster 334 }; 335 result = AudioObjectGetPropertyData(device_id, 336 &nominal_sample_rate_address, 337 0, 338 0, 339 &info_size, 340 &nominal_sample_rate); 341 if (result != noErr) { 342 OSSTATUS_DLOG(WARNING, result) 343 << "Could not get default sample rate for device: " << device_id; 344 return 0; 345 } 346 347 return static_cast<int>(nominal_sample_rate); 348 } 349 350 double AUAudioOutputStream::GetHardwareLatency() { 351 if (!output_unit_ || output_device_id_ == kAudioObjectUnknown) { 352 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown"; 353 return 0.0; 354 } 355 356 // Get audio unit latency. 357 Float64 audio_unit_latency_sec = 0.0; 358 UInt32 size = sizeof(audio_unit_latency_sec); 359 OSStatus result = AudioUnitGetProperty(output_unit_, 360 kAudioUnitProperty_Latency, 361 kAudioUnitScope_Global, 362 0, 363 &audio_unit_latency_sec, 364 &size); 365 if (result != noErr) { 366 OSSTATUS_DLOG(WARNING, result) << "Could not get audio unit latency"; 367 return 0.0; 368 } 369 370 // Get output audio device latency. 371 AudioObjectPropertyAddress property_address = { 372 kAudioDevicePropertyLatency, 373 kAudioDevicePropertyScopeOutput, 374 kAudioObjectPropertyElementMaster 375 }; 376 UInt32 device_latency_frames = 0; 377 size = sizeof(device_latency_frames); 378 result = AudioObjectGetPropertyData(output_device_id_, 379 &property_address, 380 0, 381 NULL, 382 &size, 383 &device_latency_frames); 384 if (result != noErr) { 385 OSSTATUS_DLOG(WARNING, result) << "Could not get audio unit latency"; 386 return 0.0; 387 } 388 389 return static_cast<double>((audio_unit_latency_sec * 390 format_.mSampleRate) + device_latency_frames); 391 } 392 393 double AUAudioOutputStream::GetPlayoutLatency( 394 const AudioTimeStamp* output_time_stamp) { 395 // Ensure mHostTime is valid. 396 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) 397 return 0; 398 399 // Get the delay between the moment getting the callback and the scheduled 400 // time stamp that tells when the data is going to be played out. 401 UInt64 output_time_ns = AudioConvertHostTimeToNanos( 402 output_time_stamp->mHostTime); 403 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 404 405 // Prevent overflow leading to huge delay information; occurs regularly on 406 // the bots, probably less so in the wild. 407 if (now_ns > output_time_ns) 408 return 0; 409 410 double delay_frames = static_cast<double> 411 (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate); 412 413 return (delay_frames + hardware_latency_frames_); 414 } 415 416 } // namespace media 417