Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: media/audio/mac/audio_low_latency_output_mac.cc

Issue 8234009: Adding input and output delay estimation for mac. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: remove the deprecated AudioHardwareGetProperty and update comments Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698