Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: media/audio/mac/audio_auhal_mac.cc

Issue 290003002: Remove OnMoreIOData() (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/audio/mac/audio_auhal_mac.h ('k') | media/audio/mac/audio_auhal_mac_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/bind.h" 10 #include "base/bind.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 // Finally set the actual length. 44 // Finally set the actual length.
45 bus->set_frames(frames); 45 bus->set_frames(frames);
46 } 46 }
47 47
48 AUHALStream::AUHALStream( 48 AUHALStream::AUHALStream(
49 AudioManagerMac* manager, 49 AudioManagerMac* manager,
50 const AudioParameters& params, 50 const AudioParameters& params,
51 AudioDeviceID device) 51 AudioDeviceID device)
52 : manager_(manager), 52 : manager_(manager),
53 params_(params), 53 params_(params),
54 input_channels_(params_.input_channels()),
55 output_channels_(params_.channels()), 54 output_channels_(params_.channels()),
56 number_of_frames_(params_.frames_per_buffer()), 55 number_of_frames_(params_.frames_per_buffer()),
57 source_(NULL), 56 source_(NULL),
58 device_(device), 57 device_(device),
59 audio_unit_(0), 58 audio_unit_(0),
60 volume_(1), 59 volume_(1),
61 hardware_latency_frames_(0), 60 hardware_latency_frames_(0),
62 stopped_(false), 61 stopped_(false),
63 input_buffer_list_(NULL),
64 current_hardware_pending_bytes_(0) { 62 current_hardware_pending_bytes_(0) {
65 // We must have a manager. 63 // We must have a manager.
66 DCHECK(manager_); 64 DCHECK(manager_);
67 65
68 VLOG(1) << "AUHALStream::AUHALStream()"; 66 VLOG(1) << "AUHALStream::AUHALStream()";
69 VLOG(1) << "Device: " << device; 67 VLOG(1) << "Device: " << device;
70 VLOG(1) << "Input channels: " << input_channels_;
71 VLOG(1) << "Output channels: " << output_channels_; 68 VLOG(1) << "Output channels: " << output_channels_;
72 VLOG(1) << "Sample rate: " << params_.sample_rate(); 69 VLOG(1) << "Sample rate: " << params_.sample_rate();
73 VLOG(1) << "Buffer size: " << number_of_frames_; 70 VLOG(1) << "Buffer size: " << number_of_frames_;
74 } 71 }
75 72
76 AUHALStream::~AUHALStream() { 73 AUHALStream::~AUHALStream() {
77 } 74 }
78 75
79 bool AUHALStream::Open() { 76 bool AUHALStream::Open() {
80 // Get the total number of input and output channels that the 77 // Get the total number of output channels that the
81 // hardware supports. 78 // hardware supports.
82 int device_input_channels;
83 bool got_input_channels = AudioManagerMac::GetDeviceChannels(
84 device_,
85 kAudioDevicePropertyScopeInput,
86 &device_input_channels);
87
88 int device_output_channels; 79 int device_output_channels;
89 bool got_output_channels = AudioManagerMac::GetDeviceChannels( 80 bool got_output_channels = AudioManagerMac::GetDeviceChannels(
90 device_, 81 device_,
91 kAudioDevicePropertyScopeOutput, 82 kAudioDevicePropertyScopeOutput,
92 &device_output_channels); 83 &device_output_channels);
93 84
94 // Sanity check the requested I/O channels. 85 // Sanity check the requested output channels.
95 if (!got_input_channels ||
96 input_channels_ < 0 || input_channels_ > device_input_channels) {
97 LOG(ERROR) << "AudioDevice does not support requested input channels.";
98 return false;
99 }
100
101 if (!got_output_channels || 86 if (!got_output_channels ||
102 output_channels_ <= 0 || output_channels_ > device_output_channels) { 87 output_channels_ <= 0 || output_channels_ > device_output_channels) {
103 LOG(ERROR) << "AudioDevice does not support requested output channels."; 88 LOG(ERROR) << "AudioDevice does not support requested output channels.";
104 return false; 89 return false;
105 } 90 }
106 91
107 // The requested sample-rate must match the hardware sample-rate. 92 // The requested sample-rate must match the hardware sample-rate.
108 int sample_rate = AudioManagerMac::HardwareSampleRateForDevice(device_); 93 int sample_rate = AudioManagerMac::HardwareSampleRateForDevice(device_);
109 94
110 if (sample_rate != params_.sample_rate()) { 95 if (sample_rate != params_.sample_rate()) {
111 LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate() 96 LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate()
112 << " must match the hardware sample-rate: " << sample_rate; 97 << " must match the hardware sample-rate: " << sample_rate;
113 return false; 98 return false;
114 } 99 }
115 100
116 CreateIOBusses(); 101 // The output bus will wrap the AudioBufferList given to us in
102 // the Render() callback.
103 DCHECK_GT(output_channels_, 0);
104 output_bus_ = AudioBus::CreateWrapper(output_channels_);
117 105
118 bool configured = ConfigureAUHAL(); 106 bool configured = ConfigureAUHAL();
119 if (configured) 107 if (configured)
120 hardware_latency_frames_ = GetHardwareLatency(); 108 hardware_latency_frames_ = GetHardwareLatency();
121 109
122 return configured; 110 return configured;
123 } 111 }
124 112
125 void AUHALStream::Close() { 113 void AUHALStream::Close() {
126 if (input_buffer_list_) {
127 input_buffer_list_storage_.reset();
128 input_buffer_list_ = NULL;
129 input_bus_.reset(NULL);
130 output_bus_.reset(NULL);
131 }
132
133 if (audio_unit_) { 114 if (audio_unit_) {
134 OSStatus result = AudioUnitUninitialize(audio_unit_); 115 OSStatus result = AudioUnitUninitialize(audio_unit_);
135 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 116 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
136 << "AudioUnitUninitialize() failed."; 117 << "AudioUnitUninitialize() failed.";
137 result = AudioComponentInstanceDispose(audio_unit_); 118 result = AudioComponentInstanceDispose(audio_unit_);
138 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 119 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
139 << "AudioComponentInstanceDispose() failed."; 120 << "AudioComponentInstanceDispose() failed.";
140 } 121 }
141 122
142 // Inform the audio manager that we have been closed. This will cause our 123 // Inform the audio manager that we have been closed. This will cause our
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 186
206 // Pulls on our provider to get rendered audio stream. 187 // Pulls on our provider to get rendered audio stream.
207 // Note to future hackers of this function: Do not add locks which can 188 // Note to future hackers of this function: Do not add locks which can
208 // be contended in the middle of stream processing here (starting and stopping 189 // be contended in the middle of stream processing here (starting and stopping
209 // the stream are ok) because this is running on a real-time thread. 190 // the stream are ok) because this is running on a real-time thread.
210 OSStatus AUHALStream::Render( 191 OSStatus AUHALStream::Render(
211 AudioUnitRenderActionFlags* flags, 192 AudioUnitRenderActionFlags* flags,
212 const AudioTimeStamp* output_time_stamp, 193 const AudioTimeStamp* output_time_stamp,
213 UInt32 bus_number, 194 UInt32 bus_number,
214 UInt32 number_of_frames, 195 UInt32 number_of_frames,
215 AudioBufferList* io_data) { 196 AudioBufferList* data) {
216 TRACE_EVENT0("audio", "AUHALStream::Render"); 197 TRACE_EVENT0("audio", "AUHALStream::Render");
217 198
218 // If the stream parameters change for any reason, we need to insert a FIFO 199 // If the stream parameters change for any reason, we need to insert a FIFO
219 // since the OnMoreData() pipeline can't handle frame size changes. 200 // since the OnMoreData() pipeline can't handle frame size changes.
220 if (number_of_frames != number_of_frames_) { 201 if (number_of_frames != number_of_frames_) {
221 // Create a FIFO on the fly to handle any discrepancies in callback rates. 202 // Create a FIFO on the fly to handle any discrepancies in callback rates.
222 if (!audio_fifo_) { 203 if (!audio_fifo_) {
223 VLOG(1) << "Audio frame size changed from " << number_of_frames_ << " to " 204 VLOG(1) << "Audio frame size changed from " << number_of_frames_ << " to "
224 << number_of_frames << "; adding FIFO to compensate."; 205 << number_of_frames << "; adding FIFO to compensate.";
225 audio_fifo_.reset(new AudioPullFifo( 206 audio_fifo_.reset(new AudioPullFifo(
226 output_channels_, 207 output_channels_,
227 number_of_frames_, 208 number_of_frames_,
228 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); 209 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this))));
229 } 210 }
230
231 // Synchronous IO is not supported in this state.
232 if (input_channels_ > 0)
233 input_bus_->Zero();
234 } else {
235 if (input_channels_ > 0 && input_buffer_list_) {
236 // Get the input data. |input_buffer_list_| is wrapped
237 // to point to the data allocated in |input_bus_|.
238 OSStatus result = AudioUnitRender(audio_unit_,
239 flags,
240 output_time_stamp,
241 1,
242 number_of_frames,
243 input_buffer_list_);
244 if (result != noErr)
245 ZeroBufferList(input_buffer_list_);
246 }
247 } 211 }
248 212
249 // Make |output_bus_| wrap the output AudioBufferList. 213 // Make |output_bus_| wrap the output AudioBufferList.
250 WrapBufferList(io_data, output_bus_.get(), number_of_frames); 214 WrapBufferList(data, output_bus_.get(), number_of_frames);
251 215
252 // Update the playout latency. 216 // Update the playout latency.
253 const double playout_latency_frames = GetPlayoutLatency(output_time_stamp); 217 const double playout_latency_frames = GetPlayoutLatency(output_time_stamp);
254 current_hardware_pending_bytes_ = static_cast<uint32>( 218 current_hardware_pending_bytes_ = static_cast<uint32>(
255 (playout_latency_frames + 0.5) * params_.GetBytesPerFrame()); 219 (playout_latency_frames + 0.5) * params_.GetBytesPerFrame());
256 220
257 if (audio_fifo_) 221 if (audio_fifo_)
258 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); 222 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames());
259 else 223 else
260 ProvideInput(0, output_bus_.get()); 224 ProvideInput(0, output_bus_.get());
261 225
262 return noErr; 226 return noErr;
263 } 227 }
264 228
265 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { 229 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) {
266 base::AutoLock auto_lock(source_lock_); 230 base::AutoLock auto_lock(source_lock_);
267 if (!source_) { 231 if (!source_) {
268 dest->Zero(); 232 dest->Zero();
269 return; 233 return;
270 } 234 }
271 235
272 // Supply the input data and render the output data. 236 // Supply the input data and render the output data.
273 source_->OnMoreIOData( 237 source_->OnMoreData(
274 input_bus_.get(),
275 dest, 238 dest,
276 AudioBuffersState(0, 239 AudioBuffersState(0,
277 current_hardware_pending_bytes_ + 240 current_hardware_pending_bytes_ +
278 frame_delay * params_.GetBytesPerFrame())); 241 frame_delay * params_.GetBytesPerFrame()));
279 dest->Scale(volume_); 242 dest->Scale(volume_);
280 } 243 }
281 244
282 // AUHAL callback. 245 // AUHAL callback.
283 OSStatus AUHALStream::InputProc( 246 OSStatus AUHALStream::InputProc(
284 void* user_data, 247 void* user_data,
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 // the bots, probably less so in the wild. 326 // the bots, probably less so in the wild.
364 if (now_ns > output_time_ns) 327 if (now_ns > output_time_ns)
365 return 0; 328 return 0;
366 329
367 double delay_frames = static_cast<double> 330 double delay_frames = static_cast<double>
368 (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate); 331 (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate);
369 332
370 return (delay_frames + hardware_latency_frames_); 333 return (delay_frames + hardware_latency_frames_);
371 } 334 }
372 335
373 void AUHALStream::CreateIOBusses() { 336 bool AUHALStream::EnableIO() {
DaleCurtis 2014/05/15 17:53:22 Just inline this with the method below?
no longer working on chromium 2014/05/16 13:52:37 Done.
374 if (input_channels_ > 0) {
375 // Allocate storage for the AudioBufferList used for the
376 // input data from the input AudioUnit.
377 // We allocate enough space for with one AudioBuffer per channel.
378 size_t buffer_list_size = offsetof(AudioBufferList, mBuffers[0]) +
379 (sizeof(AudioBuffer) * input_channels_);
380 input_buffer_list_storage_.reset(new uint8[buffer_list_size]);
381
382 input_buffer_list_ =
383 reinterpret_cast<AudioBufferList*>(input_buffer_list_storage_.get());
384 input_buffer_list_->mNumberBuffers = input_channels_;
385
386 // |input_bus_| allocates the storage for the PCM input data.
387 input_bus_ = AudioBus::Create(input_channels_, number_of_frames_);
388
389 // Make the AudioBufferList point to the memory in |input_bus_|.
390 UInt32 buffer_size_bytes = input_bus_->frames() * sizeof(Float32);
391 for (size_t i = 0; i < input_buffer_list_->mNumberBuffers; ++i) {
392 input_buffer_list_->mBuffers[i].mNumberChannels = 1;
393 input_buffer_list_->mBuffers[i].mDataByteSize = buffer_size_bytes;
394 input_buffer_list_->mBuffers[i].mData = input_bus_->channel(i);
395 }
396 }
397
398 // The output bus will wrap the AudioBufferList given to us in
399 // the Render() callback.
400 DCHECK_GT(output_channels_, 0);
401 output_bus_ = AudioBus::CreateWrapper(output_channels_);
402 }
403
404 bool AUHALStream::EnableIO(bool enable, UInt32 scope) {
405 // See Apple technote for details about the EnableIO property. 337 // See Apple technote for details about the EnableIO property.
406 // Note that we use bus 1 for input and bus 0 for output: 338 // Note that we use bus 1 for input and bus 0 for output:
407 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html 339 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
408 UInt32 enable_IO = enable ? 1 : 0; 340 UInt32 enable_IO = 1;
341 UInt32 scope = kAudioUnitScope_Output;
409 OSStatus result = AudioUnitSetProperty( 342 OSStatus result = AudioUnitSetProperty(
410 audio_unit_, 343 audio_unit_,
411 kAudioOutputUnitProperty_EnableIO, 344 kAudioOutputUnitProperty_EnableIO,
412 scope, 345 scope,
413 (scope == kAudioUnitScope_Input) ? 1 : 0, 346 0,
414 &enable_IO, 347 &enable_IO,
415 sizeof(enable_IO)); 348 sizeof(enable_IO));
416 return (result == noErr); 349 return (result == noErr);
417 } 350 }
418 351
419 bool AUHALStream::SetStreamFormat( 352 bool AUHALStream::SetStreamFormat(
420 AudioStreamBasicDescription* desc, 353 AudioStreamBasicDescription* desc,
421 int channels, 354 int channels,
422 UInt32 scope, 355 UInt32 scope,
423 UInt32 element) { 356 UInt32 element) {
(...skipping 15 matching lines...) Expand all
439 audio_unit_, 372 audio_unit_,
440 kAudioUnitProperty_StreamFormat, 373 kAudioUnitProperty_StreamFormat,
441 scope, 374 scope,
442 element, 375 element,
443 &format, 376 &format,
444 sizeof(format)); 377 sizeof(format));
445 return (result == noErr); 378 return (result == noErr);
446 } 379 }
447 380
448 bool AUHALStream::ConfigureAUHAL() { 381 bool AUHALStream::ConfigureAUHAL() {
449 if (device_ == kAudioObjectUnknown || 382 if (device_ == kAudioObjectUnknown || output_channels_ == 0)
450 (input_channels_ == 0 && output_channels_ == 0))
451 return false; 383 return false;
452 384
453 AudioComponentDescription desc = { 385 AudioComponentDescription desc = {
454 kAudioUnitType_Output, 386 kAudioUnitType_Output,
455 kAudioUnitSubType_HALOutput, 387 kAudioUnitSubType_HALOutput,
456 kAudioUnitManufacturer_Apple, 388 kAudioUnitManufacturer_Apple,
457 0, 389 0,
458 0 390 0
459 }; 391 };
460 AudioComponent comp = AudioComponentFindNext(0, &desc); 392 AudioComponent comp = AudioComponentFindNext(0, &desc);
461 if (!comp) 393 if (!comp)
462 return false; 394 return false;
463 395
464 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_); 396 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_);
465 if (result != noErr) { 397 if (result != noErr) {
466 OSSTATUS_DLOG(ERROR, result) << "AudioComponentInstanceNew() failed."; 398 OSSTATUS_DLOG(ERROR, result) << "AudioComponentInstanceNew() failed.";
467 return false; 399 return false;
468 } 400 }
469 401
470 // Enable input and output as appropriate. 402 // Enable output as appropriate.
471 if (!EnableIO(input_channels_ > 0, kAudioUnitScope_Input)) 403 if (!EnableIO())
472 return false;
473 if (!EnableIO(output_channels_ > 0, kAudioUnitScope_Output))
474 return false; 404 return false;
475 405
476 // Set the device to be used with the AUHAL AudioUnit. 406 // Set the device to be used with the AUHAL AudioUnit.
477 result = AudioUnitSetProperty( 407 result = AudioUnitSetProperty(
478 audio_unit_, 408 audio_unit_,
479 kAudioOutputUnitProperty_CurrentDevice, 409 kAudioOutputUnitProperty_CurrentDevice,
480 kAudioUnitScope_Global, 410 kAudioUnitScope_Global,
481 0, 411 0,
482 &device_, 412 &device_,
483 sizeof(AudioDeviceID)); 413 sizeof(AudioDeviceID));
484 if (result != noErr) 414 if (result != noErr)
485 return false; 415 return false;
486 416
487 // Set stream formats. 417 // Set stream formats.
488 // See Apple's tech note for details on the peculiar way that 418 // See Apple's tech note for details on the peculiar way that
489 // inputs and outputs are handled in the AUHAL concerning scope and bus 419 // inputs and outputs are handled in the AUHAL concerning scope and bus
490 // (element) numbers: 420 // (element) numbers:
491 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html 421 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
492 422
493 if (input_channels_ > 0) { 423 if (!SetStreamFormat(&output_format_,
494 if (!SetStreamFormat(&input_format_, 424 output_channels_,
495 input_channels_, 425 kAudioUnitScope_Input,
496 kAudioUnitScope_Output, 426 0)) {
497 1)) 427 return false;
498 return false;
499 }
500
501 if (output_channels_ > 0) {
502 if (!SetStreamFormat(&output_format_,
503 output_channels_,
504 kAudioUnitScope_Input,
505 0))
506 return false;
507 } 428 }
508 429
509 // Set the buffer frame size. 430 // Set the buffer frame size.
510 // WARNING: Setting this value changes the frame size for all output audio 431 // WARNING: Setting this value changes the frame size for all output audio
511 // units in the current process. As a result, the AURenderCallback must be 432 // units in the current process. As a result, the AURenderCallback must be
512 // able to handle arbitrary buffer sizes and FIFO appropriately. 433 // able to handle arbitrary buffer sizes and FIFO appropriately.
513 UInt32 buffer_size = 0; 434 UInt32 buffer_size = 0;
514 UInt32 property_size = sizeof(buffer_size); 435 UInt32 property_size = sizeof(buffer_size);
515 result = AudioUnitGetProperty(audio_unit_, 436 result = AudioUnitGetProperty(audio_unit_,
516 kAudioDevicePropertyBufferFrameSize, 437 kAudioDevicePropertyBufferFrameSize,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 result = AudioUnitInitialize(audio_unit_); 480 result = AudioUnitInitialize(audio_unit_);
560 if (result != noErr) { 481 if (result != noErr) {
561 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed."; 482 OSSTATUS_DLOG(ERROR, result) << "AudioUnitInitialize() failed.";
562 return false; 483 return false;
563 } 484 }
564 485
565 return true; 486 return true;
566 } 487 }
567 488
568 } // namespace media 489 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/mac/audio_auhal_mac.h ('k') | media/audio/mac/audio_auhal_mac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698