Chromium Code Reviews| 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 |