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.
5 #include "media/audio/mac/audio_low_latency_output_mac.h"
7 #include <CoreServices/CoreServices.h>
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"
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
;
31 static AudioObjectPropertyAddress kDefaultOutputDeviceAddress
= {
32 kAudioHardwarePropertyDefaultOutputDevice
,
33 kAudioObjectPropertyScopeGlobal
,
34 kAudioObjectPropertyElementMaster
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
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.
51 AUAudioOutputStream::AUAudioOutputStream(
52 AudioManagerMac
* manager
, const AudioParameters
& params
)
56 output_device_id_(kAudioObjectUnknown
),
58 hardware_latency_frames_(0),
60 audio_bus_(AudioBus::Create(params
)) {
61 // We must have a manager.
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;
78 DVLOG(1) << "Desired ouput format: " << format_
;
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_
;
85 AUAudioOutputStream::~AUAudioOutputStream() {
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
,
97 if (result
!= noErr
|| output_device_id_
== kAudioObjectUnknown
) {
98 OSSTATUS_DLOG(ERROR
, result
)
99 << "Could not get default audio output device.";
103 // Open and initialize the DefaultOutputUnit.
105 AudioComponentDescription desc
;
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
);
116 result
= AudioComponentInstanceNew(comp
, &output_unit_
);
117 if (result
!= noErr
) {
118 OSSTATUS_DLOG(ERROR
, result
) << "AudioComponentInstanceNew() failed.";
122 result
= AudioUnitInitialize(output_unit_
);
123 if (result
!= noErr
) {
124 OSSTATUS_DLOG(ERROR
, result
) << "AudioUnitInitialize() failed.";
128 hardware_latency_frames_
= GetHardwareLatency();
133 bool AUAudioOutputStream::Configure() {
134 // Set the render callback.
135 AURenderCallbackStruct input
;
136 input
.inputProc
= InputProc
;
137 input
.inputProcRefCon
= this;
138 OSStatus result
= AudioUnitSetProperty(
140 kAudioUnitProperty_SetRenderCallback
,
141 kAudioUnitScope_Global
,
145 if (result
!= noErr
) {
146 OSSTATUS_DLOG(ERROR
, result
)
147 << "AudioUnitSetProperty(kAudioUnitProperty_SetRenderCallback) failed.";
151 // Set the stream format.
152 result
= AudioUnitSetProperty(
154 kAudioUnitProperty_StreamFormat
,
155 kAudioUnitScope_Input
,
159 if (result
!= noErr
) {
160 OSSTATUS_DLOG(ERROR
, result
)
161 << "AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed.";
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.";
178 UInt32 buffer_size
= number_of_frames_
;
179 result
= AudioUnitSetProperty(
181 kAudioDevicePropertyBufferFrameSize
,
182 kAudioUnitScope_Output
,
185 sizeof(buffer_size
));
186 if (result
!= noErr
) {
187 OSSTATUS_DLOG(ERROR
, result
)
188 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed.";
195 void AUAudioOutputStream::Close() {
197 AudioComponentInstanceDispose(output_unit_
);
199 // Inform the audio manager that we have been closed. This can cause our
201 manager_
->ReleaseOutputStream(this);
204 void AUAudioOutputStream::Start(AudioSourceCallback
* callback
) {
207 DLOG(ERROR
) << "Open() has not been called successfully";
213 base::AutoLock
auto_lock(source_lock_
);
217 AudioOutputUnitStart(output_unit_
);
220 void AUAudioOutputStream::Stop() {
224 AudioOutputUnitStop(output_unit_
);
226 base::AutoLock
auto_lock(source_lock_
);
231 void AUAudioOutputStream::SetVolume(double volume
) {
234 volume_
= static_cast<float>(volume
);
236 // TODO(crogers): set volume property
239 void AUAudioOutputStream::GetVolume(double* volume
) {
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).
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
);
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
);
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
);
271 int frames_filled
= 0;
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_
);
279 memset(audio_data
, 0, number_of_frames
* format_
.mBytesPerFrame
);
283 frames_filled
= source_
->OnMoreData(
284 audio_bus_
.get(), AudioBuffersState(0, hardware_pending_bytes
));
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
);
296 // DefaultOutputUnit callback
297 OSStatus
AUAudioOutputStream::InputProc(void* user_data
,
298 AudioUnitRenderActionFlags
*,
299 const AudioTimeStamp
* output_time_stamp
,
301 UInt32 number_of_frames
,
302 AudioBufferList
* io_data
) {
303 AUAudioOutputStream
* audio_output
=
304 static_cast<AUAudioOutputStream
*>(user_data
);
308 return audio_output
->Render(number_of_frames
, io_data
, output_time_stamp
);
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
,
321 if (result
!= noErr
|| device_id
== kAudioObjectUnknown
) {
322 OSSTATUS_DLOG(WARNING
, result
)
323 << "Could not get default audio output device.";
327 Float64 nominal_sample_rate
;
328 info_size
= sizeof(nominal_sample_rate
);
330 AudioObjectPropertyAddress nominal_sample_rate_address
= {
331 kAudioDevicePropertyNominalSampleRate
,
332 kAudioObjectPropertyScopeGlobal
,
333 kAudioObjectPropertyElementMaster
335 result
= AudioObjectGetPropertyData(device_id
,
336 &nominal_sample_rate_address
,
340 &nominal_sample_rate
);
341 if (result
!= noErr
) {
342 OSSTATUS_DLOG(WARNING
, result
)
343 << "Could not get default sample rate for device: " << device_id
;
347 return static_cast<int>(nominal_sample_rate
);
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";
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
,
363 &audio_unit_latency_sec
,
365 if (result
!= noErr
) {
366 OSSTATUS_DLOG(WARNING
, result
) << "Could not get audio unit latency";
370 // Get output audio device latency.
371 AudioObjectPropertyAddress property_address
= {
372 kAudioDevicePropertyLatency
,
373 kAudioDevicePropertyScopeOutput
,
374 kAudioObjectPropertyElementMaster
376 UInt32 device_latency_frames
= 0;
377 size
= sizeof(device_latency_frames
);
378 result
= AudioObjectGetPropertyData(output_device_id_
,
383 &device_latency_frames
);
384 if (result
!= noErr
) {
385 OSSTATUS_DLOG(WARNING
, result
) << "Could not get audio unit latency";
389 return static_cast<double>((audio_unit_latency_sec
*
390 format_
.mSampleRate
) + device_latency_frames
);
393 double AUAudioOutputStream::GetPlayoutLatency(
394 const AudioTimeStamp
* output_time_stamp
) {
395 // Ensure mHostTime is valid.
396 if ((output_time_stamp
->mFlags
& kAudioTimeStampHostTimeValid
) == 0)
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());
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
)
410 double delay_frames
= static_cast<double>
411 (1e-9 * (output_time_ns
- now_ns
) * format_
.mSampleRate
);
413 return (delay_frames
+ hardware_latency_frames_
);