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