OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_auhal_mac.h" | 5 #include "media/audio/mac/audio_auhal_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/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
51 params_(params), | 51 params_(params), |
52 input_channels_(params_.input_channels()), | 52 input_channels_(params_.input_channels()), |
53 output_channels_(params_.channels()), | 53 output_channels_(params_.channels()), |
54 number_of_frames_(params_.frames_per_buffer()), | 54 number_of_frames_(params_.frames_per_buffer()), |
55 source_(NULL), | 55 source_(NULL), |
56 device_(device), | 56 device_(device), |
57 audio_unit_(0), | 57 audio_unit_(0), |
58 volume_(1), | 58 volume_(1), |
59 hardware_latency_frames_(0), | 59 hardware_latency_frames_(0), |
60 stopped_(false), | 60 stopped_(false), |
61 notified_for_possible_device_change_(false), | 61 input_buffer_list_(NULL), |
62 input_buffer_list_(NULL) { | 62 current_hardware_pending_bytes_(0) { |
63 // We must have a manager. | 63 // We must have a manager. |
64 DCHECK(manager_); | 64 DCHECK(manager_); |
65 | 65 |
66 VLOG(1) << "AUHALStream::AUHALStream()"; | 66 VLOG(1) << "AUHALStream::AUHALStream()"; |
67 VLOG(1) << "Device: " << device; | 67 VLOG(1) << "Device: " << device; |
68 VLOG(1) << "Input channels: " << input_channels_; | 68 VLOG(1) << "Input channels: " << input_channels_; |
69 VLOG(1) << "Output channels: " << output_channels_; | 69 VLOG(1) << "Output channels: " << output_channels_; |
70 VLOG(1) << "Sample rate: " << params_.sample_rate(); | 70 VLOG(1) << "Sample rate: " << params_.sample_rate(); |
71 VLOG(1) << "Buffer size: " << number_of_frames_; | 71 VLOG(1) << "Buffer size: " << number_of_frames_; |
72 } | 72 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
143 } | 143 } |
144 | 144 |
145 void AUHALStream::Start(AudioSourceCallback* callback) { | 145 void AUHALStream::Start(AudioSourceCallback* callback) { |
146 DCHECK(callback); | 146 DCHECK(callback); |
147 if (!audio_unit_) { | 147 if (!audio_unit_) { |
148 DLOG(ERROR) << "Open() has not been called successfully"; | 148 DLOG(ERROR) << "Open() has not been called successfully"; |
149 return; | 149 return; |
150 } | 150 } |
151 | 151 |
152 stopped_ = false; | 152 stopped_ = false; |
153 notified_for_possible_device_change_ = false; | 153 audio_fifo_.reset(); |
154 { | 154 { |
155 base::AutoLock auto_lock(source_lock_); | 155 base::AutoLock auto_lock(source_lock_); |
156 source_ = callback; | 156 source_ = callback; |
157 } | 157 } |
158 | 158 |
159 OSStatus result = AudioOutputUnitStart(audio_unit_); | 159 OSStatus result = AudioOutputUnitStart(audio_unit_); |
160 if (result == noErr) | 160 if (result == noErr) |
161 return; | 161 return; |
162 | 162 |
163 Stop(); | 163 Stop(); |
(...skipping 29 matching lines...) Expand all Loading... | |
193 // be contended in the middle of stream processing here (starting and stopping | 193 // be contended in the middle of stream processing here (starting and stopping |
194 // the stream are ok) because this is running on a real-time thread. | 194 // the stream are ok) because this is running on a real-time thread. |
195 OSStatus AUHALStream::Render( | 195 OSStatus AUHALStream::Render( |
196 AudioUnitRenderActionFlags* flags, | 196 AudioUnitRenderActionFlags* flags, |
197 const AudioTimeStamp* output_time_stamp, | 197 const AudioTimeStamp* output_time_stamp, |
198 UInt32 bus_number, | 198 UInt32 bus_number, |
199 UInt32 number_of_frames, | 199 UInt32 number_of_frames, |
200 AudioBufferList* io_data) { | 200 AudioBufferList* io_data) { |
201 TRACE_EVENT0("audio", "AUHALStream::Render"); | 201 TRACE_EVENT0("audio", "AUHALStream::Render"); |
202 | 202 |
203 // If the stream parameters change for any reason, we need to insert a FIFO | |
204 // since our pipeline can't handle frame size changes. Generally this is a | |
scherkus (not reviewing)
2013/11/13 18:35:19
is this referring to media::Pipeline, or something
DaleCurtis
2013/11/13 20:06:24
Comment clarified.
The shared memory is sized to
| |
205 // temporary situation which can occur after a device change has occurred but | |
206 // the AudioManager hasn't received the notification yet. | |
203 if (number_of_frames != number_of_frames_) { | 207 if (number_of_frames != number_of_frames_) { |
204 // This can happen if we've suddenly changed sample-rates. | 208 // Create a FIFO on the fly to handle any discrepancies in callback rates. |
205 // The stream should be stopping very soon. | 209 if (!audio_fifo_) { |
206 // | 210 audio_fifo_.reset(new AudioPullFifo( |
scherkus (not reviewing)
2013/11/13 18:35:19
OOC does using the fifo have a perf impact? (i.e.,
DaleCurtis
2013/11/13 20:06:24
Yes it has a perf impact of at least 6.5% (see Aud
| |
207 // Unfortunately AUAudioInputStream and AUHALStream share the frame | 211 output_channels_, |
208 // size set by kAudioDevicePropertyBufferFrameSize above on a per process | 212 number_of_frames_, |
209 // basis. What this means is that the |number_of_frames| value may be | 213 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); |
210 // larger or smaller than the value set during ConfigureAUHAL(). | 214 } |
211 // In this case either audio input or audio output will be broken, | |
212 // so just output silence. | |
213 ZeroBufferList(io_data); | |
214 return noErr; | |
215 } | |
216 | 215 |
217 if (input_channels_ > 0 && input_buffer_list_) { | 216 // Synchronous IO is not supported in this state. |
218 // Get the input data. |input_buffer_list_| is wrapped | 217 if (input_channels_ > 0) |
219 // to point to the data allocated in |input_bus_|. | 218 input_bus_->Zero(); |
220 OSStatus result = AudioUnitRender( | 219 } else { |
221 audio_unit_, | 220 if (input_channels_ > 0 && input_buffer_list_) { |
222 flags, | 221 // Get the input data. |input_buffer_list_| is wrapped |
223 output_time_stamp, | 222 // to point to the data allocated in |input_bus_|. |
224 1, | 223 OSStatus result = AudioUnitRender(audio_unit_, |
225 number_of_frames, | 224 flags, |
226 input_buffer_list_); | 225 output_time_stamp, |
227 if (result != noErr) | 226 1, |
228 ZeroBufferList(input_buffer_list_); | 227 number_of_frames, |
228 input_buffer_list_); | |
229 if (result != noErr) | |
230 ZeroBufferList(input_buffer_list_); | |
231 } | |
229 } | 232 } |
230 | 233 |
231 // Make |output_bus_| wrap the output AudioBufferList. | 234 // Make |output_bus_| wrap the output AudioBufferList. |
232 WrapBufferList(io_data, output_bus_.get(), number_of_frames); | 235 WrapBufferList(io_data, output_bus_.get(), number_of_frames); |
233 | 236 |
234 // Update the playout latency. | 237 // Update the playout latency. |
235 double playout_latency_frames = GetPlayoutLatency(output_time_stamp); | 238 const double playout_latency_frames = GetPlayoutLatency(output_time_stamp); |
239 current_hardware_pending_bytes_ = static_cast<uint32>( | |
240 (playout_latency_frames + 0.5) * params_.GetBytesPerFrame()); | |
236 | 241 |
237 uint32 hardware_pending_bytes = static_cast<uint32> | 242 if (audio_fifo_) |
238 ((playout_latency_frames + 0.5) * output_format_.mBytesPerFrame); | 243 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); |
239 | 244 else |
240 { | 245 ProvideInput(0, output_bus_.get()); |
241 // Render() shouldn't be called except between AudioOutputUnitStart() and | |
242 // AudioOutputUnitStop() calls, but crash reports have shown otherwise: | |
243 // http://crbug.com/178765. We use |source_lock_| to prevent races and | |
244 // crashes in Render() when |source_| is cleared. | |
245 base::AutoLock auto_lock(source_lock_); | |
246 if (!source_) { | |
247 ZeroBufferList(io_data); | |
248 return noErr; | |
249 } | |
250 | |
251 // Supply the input data and render the output data. | |
252 source_->OnMoreIOData( | |
253 input_bus_.get(), | |
254 output_bus_.get(), | |
255 AudioBuffersState(0, hardware_pending_bytes)); | |
256 output_bus_->Scale(volume_); | |
257 } | |
258 | 246 |
259 return noErr; | 247 return noErr; |
260 } | 248 } |
261 | 249 |
250 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { | |
251 base::AutoLock auto_lock(source_lock_); | |
252 if (!source_) { | |
253 dest->Zero(); | |
254 return; | |
255 } | |
256 | |
257 // Supply the input data and render the output data. | |
258 source_->OnMoreIOData( | |
259 input_bus_.get(), | |
260 dest, | |
261 AudioBuffersState(0, | |
262 current_hardware_pending_bytes_ + | |
263 frame_delay * params_.GetBytesPerFrame())); | |
264 dest->Scale(volume_); | |
265 } | |
266 | |
262 // AUHAL callback. | 267 // AUHAL callback. |
263 OSStatus AUHALStream::InputProc( | 268 OSStatus AUHALStream::InputProc( |
264 void* user_data, | 269 void* user_data, |
265 AudioUnitRenderActionFlags* flags, | 270 AudioUnitRenderActionFlags* flags, |
266 const AudioTimeStamp* output_time_stamp, | 271 const AudioTimeStamp* output_time_stamp, |
267 UInt32 bus_number, | 272 UInt32 bus_number, |
268 UInt32 number_of_frames, | 273 UInt32 number_of_frames, |
269 AudioBufferList* io_data) { | 274 AudioBufferList* io_data) { |
270 // Dispatch to our class method. | 275 // Dispatch to our class method. |
271 AUHALStream* audio_output = | 276 AUHALStream* audio_output = |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
523 result = AudioUnitInitialize(audio_unit_); | 528 result = AudioUnitInitialize(audio_unit_); |
524 if (result != noErr) { | 529 if (result != noErr) { |
525 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed."; | 530 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed."; |
526 return false; | 531 return false; |
527 } | 532 } |
528 | 533 |
529 return true; | 534 return true; |
530 } | 535 } |
531 | 536 |
532 } // namespace media | 537 } // namespace media |
OLD | NEW |