1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/audio/mac/audio_low_latency_output_mac.h"
6
7 #include <CoreServices/CoreServices.h>
8
9 #include "base/basictypes.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/mac/mac_logging.h"
13 #include "media/audio/mac/audio_manager_mac.h"
14 #include "media/base/media_switches.h"
15
16 namespace media {
17
operator <<(std::ostream & os,const AudioStreamBasicDescription & format)18 static std::ostream& operator<<(std::ostream& os,
19 const AudioStreamBasicDescription& format) {
20 os << "sample rate : " << format.mSampleRate << std::endl
21 << "format ID : " << format.mFormatID << std::endl
22 << "format flags : " << format.mFormatFlags << std::endl
23 << "bytes per packet : " << format.mBytesPerPacket << std::endl
24 << "frames per packet : " << format.mFramesPerPacket << std::endl
25 << "bytes per frame : " << format.mBytesPerFrame << std::endl
26 << "channels per frame: " << format.mChannelsPerFrame << std::endl
27 << "bits per channel : " << format.mBitsPerChannel;
28 return os;
29 }
30
31 static AudioObjectPropertyAddress kDefaultOutputDeviceAddress = {
32 kAudioHardwarePropertyDefaultOutputDevice,
33 kAudioObjectPropertyScopeGlobal,
34 kAudioObjectPropertyElementMaster
35 };
36
37 // Overview of operation:
38 // 1) An object of AUAudioOutputStream is created by the AudioManager
39 // factory: audio_man->MakeAudioStream().
40 // 2) Next some thread will call Open(), at that point the underlying
41 // default output Audio Unit is created and configured.
42 // 3) Then some thread will call Start(source).
43 // Then the Audio Unit is started which creates its own thread which
44 // periodically will call the source for more data as buffers are being
45 // consumed.
46 // 4) At some point some thread will call Stop(), which we handle by directly
47 // stopping the default output Audio Unit.
48 // 6) The same thread that called stop will call Close() where we cleanup
49 // and notify the audio manager, which likely will destroy this object.
50
AUAudioOutputStream(AudioManagerMac * manager,const AudioParameters & params)51 AUAudioOutputStream::AUAudioOutputStream(
52 AudioManagerMac* manager, const AudioParameters& params)
53 : manager_(manager),
54 source_(NULL),
55 output_unit_(0),
56 output_device_id_(kAudioObjectUnknown),
57 volume_(1),
58 hardware_latency_frames_(0),
59 stopped_(false),
60 audio_bus_(AudioBus::Create(params)) {
61 // We must have a manager.
62 DCHECK(manager_);
63
64 // A frame is one sample across all channels. In interleaved audio the per
65 // frame fields identify the set of n |channels|. In uncompressed audio, a
66 // packet is always one frame.
67 format_.mSampleRate = params.sample_rate();
68 format_.mFormatID = kAudioFormatLinearPCM;
69 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
70 kLinearPCMFormatFlagIsSignedInteger;
71 format_.mBitsPerChannel = params.bits_per_sample();
72 format_.mChannelsPerFrame = params.channels();
73 format_.mFramesPerPacket = 1;
74 format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels()) / 8;
75 format_.mBytesPerFrame = format_.mBytesPerPacket;
76 format_.mReserved = 0;
77
78 DVLOG(1) << "Desired ouput format: " << format_;
79
80 // Calculate the number of sample frames per callback.
81 number_of_frames_ = params.frames_per_buffer();
82 DVLOG(1) << "Number of frames per callback: " << number_of_frames_;
83 }
84
~AUAudioOutputStream()85 AUAudioOutputStream::~AUAudioOutputStream() {
86 }
87
Open()88 bool AUAudioOutputStream::Open() {
89 // Obtain the current input device selected by the user.
90 UInt32 size = sizeof(output_device_id_);
91 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
92 &kDefaultOutputDeviceAddress,
93 0,
94 0,
95 &size,
96 &output_device_id_);
97 if (result != noErr || output_device_id_ == kAudioObjectUnknown) {
98 OSSTATUS_DLOG(ERROR, result)
99 << "Could not get default audio output device.";
100 return false;
101 }
102
103 // Open and initialize the DefaultOutputUnit.
104 AudioComponent comp;
105 AudioComponentDescription desc;
106
107 desc.componentType = kAudioUnitType_Output;
108 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
109 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
110 desc.componentFlags = 0;
111 desc.componentFlagsMask = 0;
112 comp = AudioComponentFindNext(0, &desc);
113 if (!comp)
114 return false;
115
116 result = AudioComponentInstanceNew(comp, &output_unit_);
117 if (result != noErr) {
118 OSSTATUS_DLOG(ERROR, result) << "AudioComponentInstanceNew() failed.";
119 return false;
120 }
121
122 result = AudioUnitInitialize(output_unit_);
123 if (result != noErr) {
124 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed.";
125 return false;
126 }
127
128 hardware_latency_frames_ = GetHardwareLatency();
129
130 return Configure();
131 }
132
Configure()133 bool AUAudioOutputStream::Configure() {
134 // Set the render callback.
135 AURenderCallbackStruct input;
136 input.inputProc = InputProc;
137 input.inputProcRefCon = this;
138 OSStatus result = AudioUnitSetProperty(
139 output_unit_,
140 kAudioUnitProperty_SetRenderCallback,
141 kAudioUnitScope_Global,
142 0,
143 &input,
144 sizeof(input));
145 if (result != noErr) {
146 OSSTATUS_DLOG(ERROR, result)
147 << "AudioUnitSetProperty(kAudioUnitProperty_SetRenderCallback) failed.";
148 return false;
149 }
150
151 // Set the stream format.
152 result = AudioUnitSetProperty(
153 output_unit_,
154 kAudioUnitProperty_StreamFormat,
155 kAudioUnitScope_Input,
156 0,
157 &format_,
158 sizeof(format_));
159 if (result != noErr) {
160 OSSTATUS_DLOG(ERROR, result)
161 << "AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed.";
162 return false;
163 }
164
165 // Set the buffer frame size.
166 // WARNING: Setting this value changes the frame size for all audio units in
167 // the current process. It's imperative that the input and output frame sizes
168 // be the same as the frames_per_buffer() returned by
169 // GetDefaultOutputStreamParameters.
170 // See http://crbug.com/154352 for details.
171 const AudioParameters hw_params =
172 manager_->GetDefaultOutputStreamParameters();
173 if (number_of_frames_ != static_cast<size_t>(hw_params.frames_per_buffer())) {
174 DLOG(ERROR) << "Audio buffer size does not match hardware buffer size.";
175 return false;
176 }
177
178 UInt32 buffer_size = number_of_frames_;
179 result = AudioUnitSetProperty(
180 output_unit_,
181 kAudioDevicePropertyBufferFrameSize,
182 kAudioUnitScope_Output,
183 0,
184 &buffer_size,
185 sizeof(buffer_size));
186 if (result != noErr) {
187 OSSTATUS_DLOG(ERROR, result)
188 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed.";
189 return false;
190 }
191
192 return true;
193 }
194
Close()195 void AUAudioOutputStream::Close() {
196 if (output_unit_)
197 AudioComponentInstanceDispose(output_unit_);
198
199 // Inform the audio manager that we have been closed. This can cause our
200 // destruction.
201 manager_->ReleaseOutputStream(this);
202 }
203
Start(AudioSourceCallback * callback)204 void AUAudioOutputStream::Start(AudioSourceCallback* callback) {
205 DCHECK(callback);
206 if (!output_unit_) {
207 DLOG(ERROR) << "Open() has not been called successfully";
208 return;
209 }
210
211 stopped_ = false;
212 {
213 base::AutoLock auto_lock(source_lock_);
214 source_ = callback;
215 }
216
217 AudioOutputUnitStart(output_unit_);
218 }
219
Stop()220 void AUAudioOutputStream::Stop() {
221 if (stopped_)
222 return;
223
224 AudioOutputUnitStop(output_unit_);
225
226 base::AutoLock auto_lock(source_lock_);
227 source_ = NULL;
228 stopped_ = true;
229 }
230
SetVolume(double volume)231 void AUAudioOutputStream::SetVolume(double volume) {
232 if (!output_unit_)
233 return;
234 volume_ = static_cast<float>(volume);
235
236 // TODO(crogers): set volume property
237 }
238
GetVolume(double * volume)239 void AUAudioOutputStream::GetVolume(double* volume) {
240 if (!output_unit_)
241 return;
242 *volume = volume_;
243 }
244
245 // Pulls on our provider to get rendered audio stream.
246 // Note to future hackers of this function: Do not add locks here because this
247 // is running on a real-time thread (for low-latency).
Render(UInt32 number_of_frames,AudioBufferList * io_data,const AudioTimeStamp * output_time_stamp)248 OSStatus AUAudioOutputStream::Render(UInt32 number_of_frames,
249 AudioBufferList* io_data,
250 const AudioTimeStamp* output_time_stamp) {
251 // Update the playout latency.
252 double playout_latency_frames = GetPlayoutLatency(output_time_stamp);
253
254 AudioBuffer& buffer = io_data->mBuffers[0];
255 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
256 uint32 hardware_pending_bytes = static_cast<uint32>
257 ((playout_latency_frames + 0.5) * format_.mBytesPerFrame);
258
259 // Unfortunately AUAudioInputStream and AUAudioOutputStream share the frame
260 // size set by kAudioDevicePropertyBufferFrameSize above on a per process
261 // basis. What this means is that the |number_of_frames| value may be larger
262 // or smaller than the value set during Configure(). In this case either
263 // audio input or audio output will be broken, so just output silence.
264 // TODO(crogers): Figure out what can trigger a change in |number_of_frames|.
265 // See http://crbug.com/154352 for details.
266 if (number_of_frames != static_cast<UInt32>(audio_bus_->frames())) {
267 memset(audio_data, 0, number_of_frames * format_.mBytesPerFrame);
268 return noErr;
269 }
270
271 int frames_filled = 0;
272 {
273 // Render() shouldn't be called except between AudioOutputUnitStart() and
274 // AudioOutputUnitStop() calls, but crash reports have shown otherwise:
275 // http://crbug.com/178765. We use |source_lock_| to prevent races and
276 // crashes in Render() when |source_| is cleared.
277 base::AutoLock auto_lock(source_lock_);
278 if (!source_) {
279 memset(audio_data, 0, number_of_frames * format_.mBytesPerFrame);
280 return noErr;
281 }
282
283 frames_filled = source_->OnMoreData(
284 audio_bus_.get(), AudioBuffersState(0, hardware_pending_bytes));
285 }
286
287 // Note: If this ever changes to output raw float the data must be clipped and
288 // sanitized since it may come from an untrusted source such as NaCl.
289 audio_bus_->Scale(volume_);
290 audio_bus_->ToInterleaved(
291 frames_filled, format_.mBitsPerChannel / 8, audio_data);
292
293 return noErr;
294 }
295
296 // DefaultOutputUnit callback
InputProc(void * user_data,AudioUnitRenderActionFlags *,const AudioTimeStamp * output_time_stamp,UInt32,UInt32 number_of_frames,AudioBufferList * io_data)297 OSStatus AUAudioOutputStream::InputProc(void* user_data,
298 AudioUnitRenderActionFlags*,
299 const AudioTimeStamp* output_time_stamp,
300 UInt32,
301 UInt32 number_of_frames,
302 AudioBufferList* io_data) {
303 AUAudioOutputStream* audio_output =
304 static_cast<AUAudioOutputStream*>(user_data);
305 if (!audio_output)
306 return -1;
307
308 return audio_output->Render(number_of_frames, io_data, output_time_stamp);
309 }
310
HardwareSampleRate()311 int AUAudioOutputStream::HardwareSampleRate() {
312 // Determine the default output device's sample-rate.
313 AudioDeviceID device_id = kAudioObjectUnknown;
314 UInt32 info_size = sizeof(device_id);
315 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
316 &kDefaultOutputDeviceAddress,
317 0,
318 0,
319 &info_size,
320 &device_id);
321 if (result != noErr || device_id == kAudioObjectUnknown) {
322 OSSTATUS_DLOG(WARNING, result)
323 << "Could not get default audio output device.";
324 return 0;
325 }
326
327 Float64 nominal_sample_rate;
328 info_size = sizeof(nominal_sample_rate);
329
330 AudioObjectPropertyAddress nominal_sample_rate_address = {
331 kAudioDevicePropertyNominalSampleRate,
332 kAudioObjectPropertyScopeGlobal,
333 kAudioObjectPropertyElementMaster
334 };
335 result = AudioObjectGetPropertyData(device_id,
336 &nominal_sample_rate_address,
337 0,
338 0,
339 &info_size,
340 &nominal_sample_rate);
341 if (result != noErr) {
342 OSSTATUS_DLOG(WARNING, result)
343 << "Could not get default sample rate for device: " << device_id;
344 return 0;
345 }
346
347 return static_cast<int>(nominal_sample_rate);
348 }
349
GetHardwareLatency()350 double AUAudioOutputStream::GetHardwareLatency() {
351 if (!output_unit_ || output_device_id_ == kAudioObjectUnknown) {
352 DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
353 return 0.0;
354 }
355
356 // Get audio unit latency.
357 Float64 audio_unit_latency_sec = 0.0;
358 UInt32 size = sizeof(audio_unit_latency_sec);
359 OSStatus result = AudioUnitGetProperty(output_unit_,
360 kAudioUnitProperty_Latency,
361 kAudioUnitScope_Global,
362 0,
363 &audio_unit_latency_sec,
364 &size);
365 if (result != noErr) {
366 OSSTATUS_DLOG(WARNING, result) << "Could not get audio unit latency";
367 return 0.0;
368 }
369
370 // Get output audio device latency.
371 AudioObjectPropertyAddress property_address = {
372 kAudioDevicePropertyLatency,
373 kAudioDevicePropertyScopeOutput,
374 kAudioObjectPropertyElementMaster
375 };
376 UInt32 device_latency_frames = 0;
377 size = sizeof(device_latency_frames);
378 result = AudioObjectGetPropertyData(output_device_id_,
379 &property_address,
380 0,
381 NULL,
382 &size,
383 &device_latency_frames);
384 if (result != noErr) {
385 OSSTATUS_DLOG(WARNING, result) << "Could not get audio unit latency";
386 return 0.0;
387 }
388
389 return static_cast<double>((audio_unit_latency_sec *
390 format_.mSampleRate) + device_latency_frames);
391 }
392
GetPlayoutLatency(const AudioTimeStamp * output_time_stamp)393 double AUAudioOutputStream::GetPlayoutLatency(
394 const AudioTimeStamp* output_time_stamp) {
395 // Ensure mHostTime is valid.
396 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0)
397 return 0;
398
399 // Get the delay between the moment getting the callback and the scheduled
400 // time stamp that tells when the data is going to be played out.
401 UInt64 output_time_ns = AudioConvertHostTimeToNanos(
402 output_time_stamp->mHostTime);
403 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
404
405 // Prevent overflow leading to huge delay information; occurs regularly on
406 // the bots, probably less so in the wild.
407 if (now_ns > output_time_ns)
408 return 0;
409
410 double delay_frames = static_cast<double>
411 (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate);
412
413 return (delay_frames + hardware_latency_frames_);
414 }
415
416 } // namespace media
417