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_(kAudioObjectUnknown), |
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 AudioObjectPropertyAddress default_output_device_address = { | |
80 kAudioHardwarePropertyDefaultOutputDevice, | |
81 kAudioObjectPropertyScopeGlobal, | |
82 kAudioObjectPropertyElementMaster | |
83 }; | |
84 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, | |
85 &default_output_device_address, | |
86 0, | |
87 0, | |
88 &size, | |
89 &output_device_id_); | |
90 DCHECK_EQ(result, 0); | |
91 if (result) | |
92 return false; | |
93 | |
75 // Open and initialize the DefaultOutputUnit. | 94 // Open and initialize the DefaultOutputUnit. |
76 Component comp; | 95 Component comp; |
77 ComponentDescription desc; | 96 ComponentDescription desc; |
78 | 97 |
79 desc.componentType = kAudioUnitType_Output; | 98 desc.componentType = kAudioUnitType_Output; |
80 desc.componentSubType = kAudioUnitSubType_DefaultOutput; | 99 desc.componentSubType = kAudioUnitSubType_DefaultOutput; |
81 desc.componentManufacturer = kAudioUnitManufacturer_Apple; | 100 desc.componentManufacturer = kAudioUnitManufacturer_Apple; |
82 desc.componentFlags = 0; | 101 desc.componentFlags = 0; |
83 desc.componentFlagsMask = 0; | 102 desc.componentFlagsMask = 0; |
84 comp = FindNextComponent(0, &desc); | 103 comp = FindNextComponent(0, &desc); |
85 DCHECK(comp); | 104 DCHECK(comp); |
86 | 105 |
87 OSStatus result = OpenAComponent(comp, &output_unit_); | 106 result = OpenAComponent(comp, &output_unit_); |
88 DCHECK_EQ(result, 0); | 107 DCHECK_EQ(result, 0); |
89 if (result) | 108 if (result) |
90 return false; | 109 return false; |
91 | 110 |
92 result = AudioUnitInitialize(output_unit_); | 111 result = AudioUnitInitialize(output_unit_); |
93 | 112 |
94 DCHECK_EQ(result, 0); | 113 DCHECK_EQ(result, 0); |
95 if (result) | 114 if (result) |
96 return false; | 115 return false; |
97 | 116 |
117 // Gets the playout device hardware latency and stores the value. | |
118 hardware_latency_frames_ = GetHardwareLatency(); | |
119 | |
98 return Configure(); | 120 return Configure(); |
99 } | 121 } |
100 | 122 |
101 bool AUAudioOutputStream::Configure() { | 123 bool AUAudioOutputStream::Configure() { |
102 // Set the render callback. | 124 // Set the render callback. |
103 AURenderCallbackStruct input; | 125 AURenderCallbackStruct input; |
104 input.inputProc = InputProc; | 126 input.inputProc = InputProc; |
105 input.inputProcRefCon = this; | 127 input.inputProcRefCon = this; |
106 OSStatus result = AudioUnitSetProperty( | 128 OSStatus result = AudioUnitSetProperty( |
107 output_unit_, | 129 output_unit_, |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 void AUAudioOutputStream::GetVolume(double* volume) { | 200 void AUAudioOutputStream::GetVolume(double* volume) { |
179 if (!output_unit_) | 201 if (!output_unit_) |
180 return; | 202 return; |
181 *volume = volume_; | 203 *volume = volume_; |
182 } | 204 } |
183 | 205 |
184 // Pulls on our provider to get rendered audio stream. | 206 // Pulls on our provider to get rendered audio stream. |
185 // Note to future hackers of this function: Do not add locks here because this | 207 // 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). | 208 // is running on a real-time thread (for low-latency). |
187 OSStatus AUAudioOutputStream::Render(UInt32 number_of_frames, | 209 OSStatus AUAudioOutputStream::Render(UInt32 number_of_frames, |
188 AudioBufferList* io_data) { | 210 AudioBufferList* io_data, |
211 const AudioTimeStamp* output_time_stamp) { | |
212 // Update the playout latency. | |
213 double playout_latency_frames = GetPlayoutLatency(output_time_stamp); | |
214 | |
189 AudioBuffer& buffer = io_data->mBuffers[0]; | 215 AudioBuffer& buffer = io_data->mBuffers[0]; |
190 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); | 216 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); |
217 uint32 hardware_pending_bytes = static_cast<uint32> | |
218 (playout_latency_frames * format_.mBytesPerFrame + 0.5); | |
191 uint32 filled = source_->OnMoreData( | 219 uint32 filled = source_->OnMoreData( |
192 this, audio_data, buffer.mDataByteSize, AudioBuffersState(0, 0)); | 220 this, audio_data, buffer.mDataByteSize, |
221 AudioBuffersState(0, hardware_pending_bytes)); | |
193 | 222 |
194 // Handle channel order for 5.1 audio. | 223 // Handle channel order for 5.1 audio. |
195 if (format_.mChannelsPerFrame == 6) { | 224 if (format_.mChannelsPerFrame == 6) { |
196 if (format_.mBitsPerChannel == 8) { | 225 if (format_.mBitsPerChannel == 8) { |
197 SwizzleCoreAudioLayout5_1(reinterpret_cast<uint8*>(audio_data), filled); | 226 SwizzleCoreAudioLayout5_1(reinterpret_cast<uint8*>(audio_data), filled); |
198 } else if (format_.mBitsPerChannel == 16) { | 227 } else if (format_.mBitsPerChannel == 16) { |
199 SwizzleCoreAudioLayout5_1(reinterpret_cast<int16*>(audio_data), filled); | 228 SwizzleCoreAudioLayout5_1(reinterpret_cast<int16*>(audio_data), filled); |
200 } else if (format_.mBitsPerChannel == 32) { | 229 } else if (format_.mBitsPerChannel == 32) { |
201 SwizzleCoreAudioLayout5_1(reinterpret_cast<int32*>(audio_data), filled); | 230 SwizzleCoreAudioLayout5_1(reinterpret_cast<int32*>(audio_data), filled); |
202 } | 231 } |
203 } | 232 } |
204 | 233 |
205 return noErr; | 234 return noErr; |
206 } | 235 } |
207 | 236 |
208 // DefaultOutputUnit callback | 237 // DefaultOutputUnit callback |
209 OSStatus AUAudioOutputStream::InputProc(void* user_data, | 238 OSStatus AUAudioOutputStream::InputProc(void* user_data, |
210 AudioUnitRenderActionFlags*, | 239 AudioUnitRenderActionFlags*, |
211 const AudioTimeStamp*, | 240 const AudioTimeStamp* output_time_stamp, |
212 UInt32, | 241 UInt32, |
213 UInt32 number_of_frames, | 242 UInt32 number_of_frames, |
214 AudioBufferList* io_data) { | 243 AudioBufferList* io_data) { |
215 AUAudioOutputStream* audio_output = | 244 AUAudioOutputStream* audio_output = |
216 static_cast<AUAudioOutputStream*>(user_data); | 245 static_cast<AUAudioOutputStream*>(user_data); |
217 DCHECK(audio_output); | 246 DCHECK(audio_output); |
218 if (!audio_output) | 247 if (!audio_output) |
219 return -1; | 248 return -1; |
220 | 249 |
221 return audio_output->Render(number_of_frames, io_data); | 250 return audio_output->Render(number_of_frames, io_data, output_time_stamp); |
222 } | 251 } |
223 | 252 |
224 double AUAudioOutputStream::HardwareSampleRate() { | 253 double AUAudioOutputStream::HardwareSampleRate() { |
225 // Determine the default output device's sample-rate. | 254 // Determine the default output device's sample-rate. |
226 AudioDeviceID device_id = kAudioDeviceUnknown; | 255 AudioDeviceID device_id = kAudioObjectUnknown; |
227 UInt32 info_size = sizeof(device_id); | 256 UInt32 info_size = sizeof(device_id); |
228 | 257 |
229 AudioObjectPropertyAddress default_output_device_address = { | 258 AudioObjectPropertyAddress default_output_device_address = { |
230 kAudioHardwarePropertyDefaultOutputDevice, | 259 kAudioHardwarePropertyDefaultOutputDevice, |
231 kAudioObjectPropertyScopeGlobal, | 260 kAudioObjectPropertyScopeGlobal, |
232 kAudioObjectPropertyElementMaster | 261 kAudioObjectPropertyElementMaster |
233 }; | 262 }; |
234 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 263 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
235 &default_output_device_address, | 264 &default_output_device_address, |
236 0, | 265 0, |
(...skipping 17 matching lines...) Expand all Loading... | |
254 0, | 283 0, |
255 0, | 284 0, |
256 &info_size, | 285 &info_size, |
257 &nominal_sample_rate); | 286 &nominal_sample_rate); |
258 DCHECK_EQ(result, 0); | 287 DCHECK_EQ(result, 0); |
259 if (result) | 288 if (result) |
260 return 0.0; // error | 289 return 0.0; // error |
261 | 290 |
262 return nominal_sample_rate; | 291 return nominal_sample_rate; |
263 } | 292 } |
293 | |
294 double AUAudioOutputStream::GetHardwareLatency() { | |
295 if (!output_unit_ || output_device_id_ == kAudioObjectUnknown) | |
296 return 0.0; | |
297 | |
298 // Get audio unit latency. | |
299 Float64 audio_unit_latency_sec = 0.0; | |
300 UInt32 size = sizeof(audio_unit_latency_sec); | |
301 OSStatus result = AudioUnitGetProperty(output_unit_, | |
302 kAudioUnitProperty_Latency, | |
303 kAudioUnitScope_Global, | |
304 0, | |
305 &audio_unit_latency_sec, | |
306 &size); | |
307 if (result) { | |
308 DLOG(WARNING) << "GetHardwareLatency: Could not get audio unit latency."; | |
309 } | |
310 | |
311 // Get audio device latency. | |
312 UInt32 device_latency_frames = 0; | |
313 size = sizeof(device_latency_frames); | |
314 result = AudioDeviceGetProperty(output_device_id_, | |
315 0, | |
316 false, | |
317 kAudioDevicePropertyLatency, | |
318 &size, | |
319 &device_latency_frames); | |
320 if (result) { | |
321 DLOG(WARNING) << "GetHardwareLatency: Could not get device latency."; | |
322 } | |
323 | |
324 // Get the stream latency. | |
325 UInt32 stream_latency_frames = 0; | |
326 result = AudioDeviceGetPropertyInfo(output_device_id_, | |
327 0, | |
328 false, | |
329 kAudioDevicePropertyStreams, | |
330 &size, | |
331 NULL); | |
332 if (!result) { | |
333 scoped_ptr_malloc<AudioStreamID> | |
334 streams(reinterpret_cast<AudioStreamID*>(malloc(size))); | |
335 AudioStreamID* stream_ids = streams.get(); | |
336 result = AudioDeviceGetProperty(output_device_id_, | |
337 0, | |
338 false, | |
339 kAudioDevicePropertyStreams, | |
340 &size, | |
341 stream_ids); | |
342 if (!result) | |
343 result = AudioStreamGetProperty(stream_ids[0], | |
344 0, | |
345 kAudioStreamPropertyLatency, | |
346 &size, | |
347 &stream_latency_frames); | |
348 } | |
349 // Log the warning if it fails to get stream latency. | |
scherkus (not reviewing)
2011/10/21 00:20:58
ditto
no longer working on chromium
2011/10/21 12:21:46
Done.
| |
350 if (result) { | |
351 DLOG(WARNING) << "GetHardwareLatency: Could not get stream latency."; | |
352 } | |
353 | |
354 // Returns the hardware latency value in freams. | |
scherkus (not reviewing)
2011/10/21 00:20:58
ditto
no longer working on chromium
2011/10/21 12:21:46
Done.
| |
355 return static_cast<double>(audio_unit_latency_sec * | |
356 format_.mSampleRate + device_latency_frames + stream_latency_frames); | |
357 } | |
358 | |
359 double AUAudioOutputStream::GetPlayoutLatency( | |
360 const AudioTimeStamp* output_time_stamp) { | |
361 // Get the delay between now and when the data is going to reach the hardware. | |
362 UInt64 output_time_ns = AudioConvertHostTimeToNanos( | |
363 output_time_stamp->mHostTime); | |
364 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | |
365 double delay_frames = static_cast<double> | |
366 (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate); | |
367 | |
368 return (delay_frames + hardware_latency_frames_); | |
369 } | |
OLD | NEW |