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

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

Powered by Google App Engine
This is Rietveld 408576698