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

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: increase the delay precision 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_(kAudioDeviceUnknown),
51 volume_(1),
52 hardware_latency_frames_(0),
53 playout_latency_frames_(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 // Gets the playout device hardware latency and stores the value.
112 StoreHardwareLatency();
scherkus (not reviewing) 2011/10/19 16:35:15 ditto
no longer working on chromium 2011/10/19 18:19:05 Done.
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
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);
scherkus (not reviewing) 2011/10/19 16:35:15 ditto
no longer working on chromium 2011/10/19 18:19:05 Done.
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 = static_cast<uint32>
212 (playout_latency_frames_ * format_.mBytesPerFrame + 0.5);
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(0, 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
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::StoreHardwareLatency() {
289 // Get audio unit latency.
290 Float64 audio_unit_latency_sec = 0.0;
291 UInt32 size = sizeof(audio_unit_latency_sec);
292 OSStatus result = AudioUnitGetProperty(output_unit_,
293 kAudioUnitProperty_Latency,
294 kAudioUnitScope_Global,
295 0,
296 &audio_unit_latency_sec,
297 &size);
298 if (result)
299 DLOG(WARNING) << "StoreHardwareLatency: Could not get audio unit latency.";
300
301 // Get audio device latency.
302 UInt32 device_latency_frames = 0;
303 size = sizeof(device_latency_frames);
304 result = AudioDeviceGetProperty(output_device_id_,
305 0,
306 false,
307 kAudioDevicePropertyLatency,
308 &size,
309 &device_latency_frames);
310 if (result)
311 DLOG(WARNING) << "StoreHardwareLatency: Could not get device latency.";
312
313 // Get the stream latency.
314 UInt32 stream_latency_frames = 0;
315 result = AudioDeviceGetPropertyInfo(output_device_id_,
316 0,
317 false,
318 kAudioDevicePropertyStreams,
319 &size,
320 NULL);
321 if (!result) {
322 scoped_ptr_malloc<AudioStreamID>
323 streams(reinterpret_cast<AudioStreamID*>(malloc(size)));
324 AudioStreamID* stream_ids = streams.get();
325 result = AudioDeviceGetProperty(output_device_id_,
326 0,
327 false,
328 kAudioDevicePropertyStreams,
329 &size,
330 stream_ids);
331 if (!result)
332 result = AudioStreamGetProperty(stream_ids[0],
333 0,
334 kAudioStreamPropertyLatency,
335 &size,
336 &stream_latency_frames);
337 }
338 // Log the warning if it fails to get stream latency.
339 if (result)
340 DLOG(WARNING) << "StoreHardwareLatency: Could not get stream latency.";
341
342 // Store the hardware latency value in freams.
343 hardware_latency_frames_ = static_cast<double>(audio_unit_latency_sec *
344 format_.mSampleRate + device_latency_frames + stream_latency_frames);
345 }
346
347 void AUAudioOutputStream::UpdatePlayoutLatency(
348 const AudioTimeStamp* output_time_stamp) {
349 // Get the delay between now and when the data is going to reach the hardware.
350 UInt64 output_time_ns = AudioConvertHostTimeToNanos(
351 output_time_stamp->mHostTime);
352 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
353 double delay_frames = static_cast<double>
354 (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate);
355
356 playout_latency_frames_ = delay_frames + hardware_latency_frames_;
357 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698