| 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" | |
| 11 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
| 12 #include "base/logging.h" | 11 #include "base/logging.h" |
| 13 #include "base/mac/mac_logging.h" | 12 #include "base/mac/mac_logging.h" |
| 14 #include "media/audio/mac/audio_manager_mac.h" | 13 #include "media/audio/mac/audio_manager_mac.h" |
| 15 #include "media/base/media_switches.h" | 14 #include "media/base/audio_pull_fifo.h" |
| 16 | 15 |
| 17 namespace media { | 16 namespace media { |
| 18 | 17 |
| 19 static void ZeroBufferList(AudioBufferList* buffer_list) { | 18 static void ZeroBufferList(AudioBufferList* buffer_list) { |
| 20 for (size_t i = 0; i < buffer_list->mNumberBuffers; ++i) { | 19 for (size_t i = 0; i < buffer_list->mNumberBuffers; ++i) { |
| 21 memset(buffer_list->mBuffers[i].mData, | 20 memset(buffer_list->mBuffers[i].mData, |
| 22 0, | 21 0, |
| 23 buffer_list->mBuffers[i].mDataByteSize); | 22 buffer_list->mBuffers[i].mDataByteSize); |
| 24 } | 23 } |
| 25 } | 24 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 51 params_(params), | 50 params_(params), |
| 52 input_channels_(params_.input_channels()), | 51 input_channels_(params_.input_channels()), |
| 53 output_channels_(params_.channels()), | 52 output_channels_(params_.channels()), |
| 54 number_of_frames_(params_.frames_per_buffer()), | 53 number_of_frames_(params_.frames_per_buffer()), |
| 55 source_(NULL), | 54 source_(NULL), |
| 56 device_(device), | 55 device_(device), |
| 57 audio_unit_(0), | 56 audio_unit_(0), |
| 58 volume_(1), | 57 volume_(1), |
| 59 hardware_latency_frames_(0), | 58 hardware_latency_frames_(0), |
| 60 stopped_(false), | 59 stopped_(false), |
| 61 notified_for_possible_device_change_(false), | 60 input_buffer_list_(NULL), |
| 62 input_buffer_list_(NULL) { | 61 current_hardware_pending_bytes_(0) { |
| 63 // We must have a manager. | 62 // We must have a manager. |
| 64 DCHECK(manager_); | 63 DCHECK(manager_); |
| 65 | 64 |
| 66 VLOG(1) << "AUHALStream::AUHALStream()"; | 65 VLOG(1) << "AUHALStream::AUHALStream()"; |
| 67 VLOG(1) << "Device: " << device; | 66 VLOG(1) << "Device: " << device; |
| 68 VLOG(1) << "Input channels: " << input_channels_; | 67 VLOG(1) << "Input channels: " << input_channels_; |
| 69 VLOG(1) << "Output channels: " << output_channels_; | 68 VLOG(1) << "Output channels: " << output_channels_; |
| 70 VLOG(1) << "Sample rate: " << params_.sample_rate(); | 69 VLOG(1) << "Sample rate: " << params_.sample_rate(); |
| 71 VLOG(1) << "Buffer size: " << number_of_frames_; | 70 VLOG(1) << "Buffer size: " << number_of_frames_; |
| 72 } | 71 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 } | 142 } |
| 144 | 143 |
| 145 void AUHALStream::Start(AudioSourceCallback* callback) { | 144 void AUHALStream::Start(AudioSourceCallback* callback) { |
| 146 DCHECK(callback); | 145 DCHECK(callback); |
| 147 if (!audio_unit_) { | 146 if (!audio_unit_) { |
| 148 DLOG(ERROR) << "Open() has not been called successfully"; | 147 DLOG(ERROR) << "Open() has not been called successfully"; |
| 149 return; | 148 return; |
| 150 } | 149 } |
| 151 | 150 |
| 152 stopped_ = false; | 151 stopped_ = false; |
| 153 notified_for_possible_device_change_ = false; | 152 audio_fifo_.reset(); |
| 154 { | 153 { |
| 155 base::AutoLock auto_lock(source_lock_); | 154 base::AutoLock auto_lock(source_lock_); |
| 156 source_ = callback; | 155 source_ = callback; |
| 157 } | 156 } |
| 158 | 157 |
| 159 OSStatus result = AudioOutputUnitStart(audio_unit_); | 158 OSStatus result = AudioOutputUnitStart(audio_unit_); |
| 160 if (result == noErr) | 159 if (result == noErr) |
| 161 return; | 160 return; |
| 162 | 161 |
| 163 Stop(); | 162 Stop(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 193 // be contended in the middle of stream processing here (starting and stopping | 192 // 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. | 193 // the stream are ok) because this is running on a real-time thread. |
| 195 OSStatus AUHALStream::Render( | 194 OSStatus AUHALStream::Render( |
| 196 AudioUnitRenderActionFlags* flags, | 195 AudioUnitRenderActionFlags* flags, |
| 197 const AudioTimeStamp* output_time_stamp, | 196 const AudioTimeStamp* output_time_stamp, |
| 198 UInt32 bus_number, | 197 UInt32 bus_number, |
| 199 UInt32 number_of_frames, | 198 UInt32 number_of_frames, |
| 200 AudioBufferList* io_data) { | 199 AudioBufferList* io_data) { |
| 201 TRACE_EVENT0("audio", "AUHALStream::Render"); | 200 TRACE_EVENT0("audio", "AUHALStream::Render"); |
| 202 | 201 |
| 202 // If the stream parameters change for any reason, we need to insert a FIFO |
| 203 // since the OnMoreData() pipeline can't handle frame size changes. Generally |
| 204 // this is a temporary situation which can occur after a device change has |
| 205 // occurred but the AudioManager hasn't received the notification yet. |
| 203 if (number_of_frames != number_of_frames_) { | 206 if (number_of_frames != number_of_frames_) { |
| 204 // This can happen if we've suddenly changed sample-rates. | 207 // Create a FIFO on the fly to handle any discrepancies in callback rates. |
| 205 // The stream should be stopping very soon. | 208 if (!audio_fifo_) { |
| 206 // | 209 VLOG(1) << "Audio frame size change detected; adding FIFO to compensate."; |
| 207 // Unfortunately AUAudioInputStream and AUHALStream share the frame | 210 audio_fifo_.reset(new AudioPullFifo( |
| 208 // size set by kAudioDevicePropertyBufferFrameSize above on a per process | 211 output_channels_, |
| 209 // basis. What this means is that the |number_of_frames| value may be | 212 number_of_frames_, |
| 210 // larger or smaller than the value set during ConfigureAUHAL(). | 213 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); |
| 211 // In this case either audio input or audio output will be broken, | 214 } |
| 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 |