OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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_low_latency_input_mac.h" | 5 #include "media/audio/mac/audio_low_latency_input_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/logging.h" | 10 #include "base/logging.h" |
11 #include "base/mac/mac_logging.h" | 11 #include "base/mac/mac_logging.h" |
12 #include "media/audio/mac/audio_manager_mac.h" | 12 #include "media/audio/mac/audio_manager_mac.h" |
13 #include "media/base/audio_block_fifo.h" | |
14 #include "media/base/audio_bus.h" | 13 #include "media/base/audio_bus.h" |
15 #include "media/base/data_buffer.h" | 14 #include "media/base/data_buffer.h" |
16 | 15 |
17 namespace media { | 16 namespace media { |
18 | 17 |
19 // Number of blocks of buffers used in the |fifo_|. | 18 // Number of blocks of buffers used in the |fifo_|. |
20 const int kNumberOfBlocksBufferInFifo = 2; | 19 const int kNumberOfBlocksBufferInFifo = 2; |
21 | 20 |
22 static std::ostream& operator<<(std::ostream& os, | 21 static std::ostream& operator<<(std::ostream& os, |
23 const AudioStreamBasicDescription& format) { | 22 const AudioStreamBasicDescription& format) { |
24 os << "sample rate : " << format.mSampleRate << std::endl | 23 os << "sample rate : " << format.mSampleRate << std::endl |
25 << "format ID : " << format.mFormatID << std::endl | 24 << "format ID : " << format.mFormatID << std::endl |
26 << "format flags : " << format.mFormatFlags << std::endl | 25 << "format flags : " << format.mFormatFlags << std::endl |
27 << "bytes per packet : " << format.mBytesPerPacket << std::endl | 26 << "bytes per packet : " << format.mBytesPerPacket << std::endl |
28 << "frames per packet : " << format.mFramesPerPacket << std::endl | 27 << "frames per packet : " << format.mFramesPerPacket << std::endl |
29 << "bytes per frame : " << format.mBytesPerFrame << std::endl | 28 << "bytes per frame : " << format.mBytesPerFrame << std::endl |
30 << "channels per frame: " << format.mChannelsPerFrame << std::endl | 29 << "channels per frame: " << format.mChannelsPerFrame << std::endl |
31 << "bits per channel : " << format.mBitsPerChannel; | 30 << "bits per channel : " << format.mBitsPerChannel; |
32 return os; | 31 return os; |
33 } | 32 } |
34 | 33 |
35 static void WrapBufferList(AudioBufferList* buffer_list, | |
36 AudioBus* bus, | |
37 int frames) { | |
38 DCHECK(buffer_list); | |
39 DCHECK(bus); | |
40 const int channels = bus->channels(); | |
41 const int buffer_list_channels = buffer_list->mNumberBuffers; | |
42 CHECK_EQ(channels, buffer_list_channels); | |
43 | |
44 // Copy pointers from AudioBufferList. | |
45 for (int i = 0; i < channels; ++i) | |
46 bus->SetChannelData(i, static_cast<float*>(buffer_list->mBuffers[i].mData)); | |
47 | |
48 // Finally set the actual length. | |
49 bus->set_frames(frames); | |
50 } | |
51 | |
52 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit" | 34 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit" |
53 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html | 35 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html |
54 // for more details and background regarding this implementation. | 36 // for more details and background regarding this implementation. |
55 | 37 |
56 AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager, | 38 AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager, |
57 const AudioParameters& input_params, | 39 const AudioParameters& input_params, |
58 AudioDeviceID audio_device_id) | 40 AudioDeviceID audio_device_id) |
59 : manager_(manager), | 41 : manager_(manager), |
60 number_of_frames_(input_params.frames_per_buffer()), | 42 number_of_frames_(input_params.frames_per_buffer()), |
61 sink_(NULL), | 43 sink_(NULL), |
62 audio_unit_(0), | 44 audio_unit_(0), |
63 input_device_id_(audio_device_id), | 45 input_device_id_(audio_device_id), |
64 started_(false), | 46 started_(false), |
65 hardware_latency_frames_(0), | 47 hardware_latency_frames_(0), |
66 number_of_channels_in_frame_(0), | 48 number_of_channels_in_frame_(0), |
67 audio_wrapper_(AudioBus::CreateWrapper(input_params.channels())) { | 49 fifo_(input_params.channels(), |
| 50 number_of_frames_, |
| 51 kNumberOfBlocksBufferInFifo) { |
68 DCHECK(manager_); | 52 DCHECK(manager_); |
69 | 53 |
70 // Set up the desired (output) format specified by the client. | 54 // Set up the desired (output) format specified by the client. |
71 format_.mSampleRate = input_params.sample_rate(); | 55 format_.mSampleRate = input_params.sample_rate(); |
72 format_.mFormatID = kAudioFormatLinearPCM; | 56 format_.mFormatID = kAudioFormatLinearPCM; |
73 format_.mFormatFlags = | 57 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | |
74 kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved; | 58 kLinearPCMFormatFlagIsSignedInteger; |
75 size_t bytes_per_sample = sizeof(Float32); | 59 format_.mBitsPerChannel = input_params.bits_per_sample(); |
76 format_.mBitsPerChannel = bytes_per_sample * 8; | |
77 format_.mChannelsPerFrame = input_params.channels(); | 60 format_.mChannelsPerFrame = input_params.channels(); |
78 format_.mFramesPerPacket = 1; | 61 format_.mFramesPerPacket = 1; // uncompressed audio |
79 format_.mBytesPerFrame = bytes_per_sample; | 62 format_.mBytesPerPacket = (format_.mBitsPerChannel * |
80 format_.mBytesPerPacket = format_.mBytesPerFrame * format_.mFramesPerPacket; | 63 input_params.channels()) / 8; |
| 64 format_.mBytesPerFrame = format_.mBytesPerPacket; |
81 format_.mReserved = 0; | 65 format_.mReserved = 0; |
82 | 66 |
83 DVLOG(1) << "Desired ouput format: " << format_; | 67 DVLOG(1) << "Desired ouput format: " << format_; |
84 | 68 |
85 // Allocate AudioBufferList based on the number of channels. | 69 // Derive size (in bytes) of the buffers that we will render to. |
86 audio_buffer_list_.reset(static_cast<AudioBufferList*>( | 70 UInt32 data_byte_size = number_of_frames_ * format_.mBytesPerFrame; |
87 malloc(sizeof(AudioBufferList) * input_params.channels()))); | 71 DVLOG(1) << "Size of data buffer in bytes : " << data_byte_size; |
88 audio_buffer_list_->mNumberBuffers = input_params.channels(); | |
89 | 72 |
90 // Allocate AudioBuffers to be used as storage for the received audio. | 73 // Allocate AudioBuffers to be used as storage for the received audio. |
91 // The AudioBufferList structure works as a placeholder for the | 74 // The AudioBufferList structure works as a placeholder for the |
92 // AudioBuffer structure, which holds a pointer to the actual data buffer. | 75 // AudioBuffer structure, which holds a pointer to the actual data buffer. |
93 UInt32 data_byte_size = number_of_frames_ * format_.mBytesPerFrame; | 76 audio_data_buffer_.reset(new uint8[data_byte_size]); |
94 audio_data_buffer_.reset(static_cast<float*>(base::AlignedAlloc( | 77 audio_buffer_list_.mNumberBuffers = 1; |
95 data_byte_size * audio_buffer_list_->mNumberBuffers, | 78 |
96 AudioBus::kChannelAlignment))); | 79 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers; |
97 AudioBuffer* audio_buffer = audio_buffer_list_->mBuffers; | 80 audio_buffer->mNumberChannels = input_params.channels(); |
98 for (UInt32 i = 0; i < audio_buffer_list_->mNumberBuffers; ++i) { | 81 audio_buffer->mDataByteSize = data_byte_size; |
99 audio_buffer[i].mNumberChannels = 1; | 82 audio_buffer->mData = audio_data_buffer_.get(); |
100 audio_buffer[i].mDataByteSize = data_byte_size; | |
101 audio_buffer[i].mData = audio_data_buffer_.get() + i * data_byte_size; | |
102 } | |
103 } | 83 } |
104 | 84 |
105 AUAudioInputStream::~AUAudioInputStream() { | 85 AUAudioInputStream::~AUAudioInputStream() {} |
106 } | |
107 | 86 |
108 // Obtain and open the AUHAL AudioOutputUnit for recording. | 87 // Obtain and open the AUHAL AudioOutputUnit for recording. |
109 bool AUAudioInputStream::Open() { | 88 bool AUAudioInputStream::Open() { |
110 // Verify that we are not already opened. | 89 // Verify that we are not already opened. |
111 if (audio_unit_) | 90 if (audio_unit_) |
112 return false; | 91 return false; |
113 | 92 |
114 // Verify that we have a valid device. | 93 // Verify that we have a valid device. |
115 if (input_device_id_ == kAudioObjectUnknown) { | 94 if (input_device_id_ == kAudioObjectUnknown) { |
116 NOTREACHED() << "Device ID is unknown"; | 95 NOTREACHED() << "Device ID is unknown"; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 // Note that, devices can only be set to the AUHAL after enabling IO. | 156 // Note that, devices can only be set to the AUHAL after enabling IO. |
178 result = AudioUnitSetProperty(audio_unit_, | 157 result = AudioUnitSetProperty(audio_unit_, |
179 kAudioOutputUnitProperty_CurrentDevice, | 158 kAudioOutputUnitProperty_CurrentDevice, |
180 kAudioUnitScope_Global, | 159 kAudioUnitScope_Global, |
181 0, | 160 0, |
182 &input_device_id_, | 161 &input_device_id_, |
183 sizeof(input_device_id_)); | 162 sizeof(input_device_id_)); |
184 if (result) { | 163 if (result) { |
185 HandleError(result); | 164 HandleError(result); |
186 return false; | 165 return false; |
| 166 } |
| 167 |
| 168 // Register the input procedure for the AUHAL. |
| 169 // This procedure will be called when the AUHAL has received new data |
| 170 // from the input device. |
| 171 AURenderCallbackStruct callback; |
| 172 callback.inputProc = InputProc; |
| 173 callback.inputProcRefCon = this; |
| 174 result = AudioUnitSetProperty(audio_unit_, |
| 175 kAudioOutputUnitProperty_SetInputCallback, |
| 176 kAudioUnitScope_Global, |
| 177 0, |
| 178 &callback, |
| 179 sizeof(callback)); |
| 180 if (result) { |
| 181 HandleError(result); |
| 182 return false; |
187 } | 183 } |
188 | 184 |
189 // Set up the the desired (output) format. | 185 // Set up the the desired (output) format. |
190 // For obtaining input from a device, the device format is always expressed | 186 // For obtaining input from a device, the device format is always expressed |
191 // on the output scope of the AUHAL's Element 1. | 187 // on the output scope of the AUHAL's Element 1. |
192 result = AudioUnitSetProperty(audio_unit_, | 188 result = AudioUnitSetProperty(audio_unit_, |
193 kAudioUnitProperty_StreamFormat, | 189 kAudioUnitProperty_StreamFormat, |
194 kAudioUnitScope_Output, | 190 kAudioUnitScope_Output, |
195 1, | 191 1, |
196 &format_, | 192 &format_, |
(...skipping 29 matching lines...) Expand all Loading... |
226 kAudioUnitScope_Output, | 222 kAudioUnitScope_Output, |
227 1, | 223 1, |
228 &buffer_size, | 224 &buffer_size, |
229 sizeof(buffer_size)); | 225 sizeof(buffer_size)); |
230 if (result != noErr) { | 226 if (result != noErr) { |
231 HandleError(result); | 227 HandleError(result); |
232 return false; | 228 return false; |
233 } | 229 } |
234 } | 230 } |
235 | 231 |
236 // Register the input procedure for the AUHAL. | |
237 // This procedure will be called when the AUHAL has received new data | |
238 // from the input device. | |
239 AURenderCallbackStruct callback; | |
240 callback.inputProc = InputProc; | |
241 callback.inputProcRefCon = this; | |
242 result = AudioUnitSetProperty(audio_unit_, | |
243 kAudioOutputUnitProperty_SetInputCallback, | |
244 kAudioUnitScope_Global, | |
245 0, | |
246 &callback, | |
247 sizeof(callback)); | |
248 if (result) { | |
249 HandleError(result); | |
250 return false; | |
251 } | |
252 | |
253 // Finally, initialize the audio unit and ensure that it is ready to render. | 232 // Finally, initialize the audio unit and ensure that it is ready to render. |
254 // Allocates memory according to the maximum number of audio frames | 233 // Allocates memory according to the maximum number of audio frames |
255 // it can produce in response to a single render call. | 234 // it can produce in response to a single render call. |
256 result = AudioUnitInitialize(audio_unit_); | 235 result = AudioUnitInitialize(audio_unit_); |
257 if (result) { | 236 if (result) { |
258 HandleError(result); | 237 HandleError(result); |
259 return false; | 238 return false; |
260 } | 239 } |
261 | 240 |
262 // The hardware latency is fixed and will not change during the call. | 241 // The hardware latency is fixed and will not change during the call. |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 DCHECK_LE(volume, 1.0); | 335 DCHECK_LE(volume, 1.0); |
357 | 336 |
358 // Verify that we have a valid device. | 337 // Verify that we have a valid device. |
359 if (input_device_id_ == kAudioObjectUnknown) { | 338 if (input_device_id_ == kAudioObjectUnknown) { |
360 NOTREACHED() << "Device ID is unknown"; | 339 NOTREACHED() << "Device ID is unknown"; |
361 return; | 340 return; |
362 } | 341 } |
363 | 342 |
364 Float32 volume_float32 = static_cast<Float32>(volume); | 343 Float32 volume_float32 = static_cast<Float32>(volume); |
365 AudioObjectPropertyAddress property_address = { | 344 AudioObjectPropertyAddress property_address = { |
366 kAudioDevicePropertyVolumeScalar, | 345 kAudioDevicePropertyVolumeScalar, |
367 kAudioDevicePropertyScopeInput, | 346 kAudioDevicePropertyScopeInput, |
368 kAudioObjectPropertyElementMaster | 347 kAudioObjectPropertyElementMaster |
369 }; | 348 }; |
370 | 349 |
371 // Try to set the volume for master volume channel. | 350 // Try to set the volume for master volume channel. |
372 if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) { | 351 if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) { |
373 OSStatus result = AudioObjectSetPropertyData(input_device_id_, | 352 OSStatus result = AudioObjectSetPropertyData(input_device_id_, |
374 &property_address, | 353 &property_address, |
375 0, | 354 0, |
376 NULL, | 355 NULL, |
377 sizeof(volume_float32), | 356 sizeof(volume_float32), |
378 &volume_float32); | 357 &volume_float32); |
(...skipping 25 matching lines...) Expand all Loading... |
404 // Update the AGC volume level based on the last setting above. Note that, | 383 // Update the AGC volume level based on the last setting above. Note that, |
405 // the volume-level resolution is not infinite and it is therefore not | 384 // the volume-level resolution is not infinite and it is therefore not |
406 // possible to assume that the volume provided as input parameter can be | 385 // possible to assume that the volume provided as input parameter can be |
407 // used directly. Instead, a new query to the audio hardware is required. | 386 // used directly. Instead, a new query to the audio hardware is required. |
408 // This method does nothing if AGC is disabled. | 387 // This method does nothing if AGC is disabled. |
409 UpdateAgcVolume(); | 388 UpdateAgcVolume(); |
410 } | 389 } |
411 | 390 |
412 double AUAudioInputStream::GetVolume() { | 391 double AUAudioInputStream::GetVolume() { |
413 // Verify that we have a valid device. | 392 // Verify that we have a valid device. |
414 if (input_device_id_ == kAudioObjectUnknown) { | 393 if (input_device_id_ == kAudioObjectUnknown){ |
415 NOTREACHED() << "Device ID is unknown"; | 394 NOTREACHED() << "Device ID is unknown"; |
416 return 0.0; | 395 return 0.0; |
417 } | 396 } |
418 | 397 |
419 AudioObjectPropertyAddress property_address = { | 398 AudioObjectPropertyAddress property_address = { |
420 kAudioDevicePropertyVolumeScalar, | 399 kAudioDevicePropertyVolumeScalar, |
421 kAudioDevicePropertyScopeInput, | 400 kAudioDevicePropertyScopeInput, |
422 kAudioObjectPropertyElementMaster | 401 kAudioObjectPropertyElementMaster |
423 }; | 402 }; |
424 | 403 |
425 if (AudioObjectHasProperty(input_device_id_, &property_address)) { | 404 if (AudioObjectHasProperty(input_device_id_, &property_address)) { |
426 // The device supports master volume control, get the volume from the | 405 // The device supports master volume control, get the volume from the |
427 // master channel. | 406 // master channel. |
428 Float32 volume_float32 = 0.0; | 407 Float32 volume_float32 = 0.0; |
429 UInt32 size = sizeof(volume_float32); | 408 UInt32 size = sizeof(volume_float32); |
430 OSStatus result = AudioObjectGetPropertyData( | 409 OSStatus result = AudioObjectGetPropertyData(input_device_id_, |
431 input_device_id_, &property_address, 0, NULL, &size, &volume_float32); | 410 &property_address, |
| 411 0, |
| 412 NULL, |
| 413 &size, |
| 414 &volume_float32); |
432 if (result == noErr) | 415 if (result == noErr) |
433 return static_cast<double>(volume_float32); | 416 return static_cast<double>(volume_float32); |
434 } else { | 417 } else { |
435 // There is no master volume control, try to get the average volume of | 418 // There is no master volume control, try to get the average volume of |
436 // all the channels. | 419 // all the channels. |
437 Float32 volume_float32 = 0.0; | 420 Float32 volume_float32 = 0.0; |
438 int successful_channels = 0; | 421 int successful_channels = 0; |
439 for (int i = 1; i <= number_of_channels_in_frame_; ++i) { | 422 for (int i = 1; i <= number_of_channels_in_frame_; ++i) { |
440 property_address.mElement = static_cast<UInt32>(i); | 423 property_address.mElement = static_cast<UInt32>(i); |
441 if (AudioObjectHasProperty(input_device_id_, &property_address)) { | 424 if (AudioObjectHasProperty(input_device_id_, &property_address)) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 OSStatus result = AudioUnitRender(audio_input->audio_unit(), | 465 OSStatus result = AudioUnitRender(audio_input->audio_unit(), |
483 flags, | 466 flags, |
484 time_stamp, | 467 time_stamp, |
485 bus_number, | 468 bus_number, |
486 number_of_frames, | 469 number_of_frames, |
487 audio_input->audio_buffer_list()); | 470 audio_input->audio_buffer_list()); |
488 if (result) | 471 if (result) |
489 return result; | 472 return result; |
490 | 473 |
491 // Deliver recorded data to the consumer as a callback. | 474 // Deliver recorded data to the consumer as a callback. |
492 return audio_input->Provide( | 475 return audio_input->Provide(number_of_frames, |
493 number_of_frames, audio_input->audio_buffer_list(), time_stamp); | 476 audio_input->audio_buffer_list(), |
| 477 time_stamp); |
494 } | 478 } |
495 | 479 |
496 OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames, | 480 OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames, |
497 AudioBufferList* io_data, | 481 AudioBufferList* io_data, |
498 const AudioTimeStamp* time_stamp) { | 482 const AudioTimeStamp* time_stamp) { |
499 // Update the capture latency. | 483 // Update the capture latency. |
500 double capture_latency_frames = GetCaptureLatency(time_stamp); | 484 double capture_latency_frames = GetCaptureLatency(time_stamp); |
501 | 485 |
502 // The AGC volume level is updated once every second on a separate thread. | 486 // The AGC volume level is updated once every second on a separate thread. |
503 // Note that, |volume| is also updated each time SetVolume() is called | 487 // Note that, |volume| is also updated each time SetVolume() is called |
504 // through IPC by the render-side AGC. | 488 // through IPC by the render-side AGC. |
505 double normalized_volume = 0.0; | 489 double normalized_volume = 0.0; |
506 GetAgcVolume(&normalized_volume); | 490 GetAgcVolume(&normalized_volume); |
507 | 491 |
508 AudioBuffer& buffer = io_data->mBuffers[0]; | 492 AudioBuffer& buffer = io_data->mBuffers[0]; |
509 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); | 493 uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); |
510 uint32 capture_delay_bytes = static_cast<uint32>( | 494 uint32 capture_delay_bytes = static_cast<uint32> |
511 (capture_latency_frames + 0.5) * format_.mBytesPerFrame); | 495 ((capture_latency_frames + 0.5) * format_.mBytesPerFrame); |
512 DCHECK(audio_data); | 496 DCHECK(audio_data); |
513 if (!audio_data) | 497 if (!audio_data) |
514 return kAudioUnitErr_InvalidElement; | 498 return kAudioUnitErr_InvalidElement; |
515 | 499 |
516 // Wrap the output AudioBufferList to |audio_wrapper_|. | 500 // Copy captured (and interleaved) data into FIFO. |
517 WrapBufferList(io_data, audio_wrapper_.get(), number_of_frames); | 501 fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8); |
518 | 502 |
519 // If the stream parameters change for any reason, we need to insert a FIFO | 503 // Consume and deliver the data when the FIFO has a block of available data. |
520 // since the OnMoreData() pipeline can't handle frame size changes. | 504 while (fifo_.available_blocks()) { |
521 if (number_of_frames != number_of_frames_) { | 505 const AudioBus* audio_bus = fifo_.Consume(); |
522 // Create a FIFO on the fly to handle any discrepancies in callback rates. | 506 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_)); |
523 if (!fifo_) { | |
524 fifo_.reset(new AudioBlockFifo(audio_wrapper_->channels(), | |
525 number_of_frames_, | |
526 kNumberOfBlocksBufferInFifo)); | |
527 } | |
528 } | |
529 | 507 |
530 // When FIFO does not kick in, data will be directly passed to the callback. | 508 // Compensate the audio delay caused by the FIFO. |
531 if (!fifo_) { | 509 capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame; |
532 CHECK_EQ(audio_wrapper_->frames(), static_cast<int>(number_of_frames_)); | |
533 sink_->OnData( | |
534 this, audio_wrapper_.get(), capture_delay_bytes, normalized_volume); | |
535 return noErr; | |
536 } | |
537 | |
538 // Compensate the audio delay caused by the FIFO. | |
539 capture_delay_bytes += fifo_->GetAvailableFrames() * format_.mBytesPerFrame; | |
540 | |
541 fifo_->Push(audio_wrapper_.get()); | |
542 // Consume and deliver the data when the FIFO has a block of available data. | |
543 while (fifo_->available_blocks()) { | |
544 const AudioBus* audio_bus = fifo_->Consume(); | |
545 DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_)); | |
546 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume); | 510 sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume); |
547 } | 511 } |
548 | 512 |
549 return noErr; | 513 return noErr; |
550 } | 514 } |
551 | 515 |
552 int AUAudioInputStream::HardwareSampleRate() { | 516 int AUAudioInputStream::HardwareSampleRate() { |
553 // Determine the default input device's sample-rate. | 517 // Determine the default input device's sample-rate. |
554 AudioDeviceID device_id = kAudioObjectUnknown; | 518 AudioDeviceID device_id = kAudioObjectUnknown; |
555 UInt32 info_size = sizeof(device_id); | 519 UInt32 info_size = sizeof(device_id); |
556 | 520 |
557 AudioObjectPropertyAddress default_input_device_address = { | 521 AudioObjectPropertyAddress default_input_device_address = { |
558 kAudioHardwarePropertyDefaultInputDevice, | 522 kAudioHardwarePropertyDefaultInputDevice, |
559 kAudioObjectPropertyScopeGlobal, | 523 kAudioObjectPropertyScopeGlobal, |
560 kAudioObjectPropertyElementMaster | 524 kAudioObjectPropertyElementMaster |
561 }; | 525 }; |
562 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 526 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
563 &default_input_device_address, | 527 &default_input_device_address, |
564 0, | 528 0, |
565 0, | 529 0, |
566 &info_size, | 530 &info_size, |
567 &device_id); | 531 &device_id); |
568 if (result != noErr) | 532 if (result != noErr) |
569 return 0.0; | 533 return 0.0; |
570 | 534 |
571 Float64 nominal_sample_rate; | 535 Float64 nominal_sample_rate; |
572 info_size = sizeof(nominal_sample_rate); | 536 info_size = sizeof(nominal_sample_rate); |
573 | 537 |
574 AudioObjectPropertyAddress nominal_sample_rate_address = { | 538 AudioObjectPropertyAddress nominal_sample_rate_address = { |
575 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, | 539 kAudioDevicePropertyNominalSampleRate, |
576 kAudioObjectPropertyElementMaster}; | 540 kAudioObjectPropertyScopeGlobal, |
| 541 kAudioObjectPropertyElementMaster |
| 542 }; |
577 result = AudioObjectGetPropertyData(device_id, | 543 result = AudioObjectGetPropertyData(device_id, |
578 &nominal_sample_rate_address, | 544 &nominal_sample_rate_address, |
579 0, | 545 0, |
580 0, | 546 0, |
581 &info_size, | 547 &info_size, |
582 &nominal_sample_rate); | 548 &nominal_sample_rate); |
583 if (result != noErr) | 549 if (result != noErr) |
584 return 0.0; | 550 return 0.0; |
585 | 551 |
586 return static_cast<int>(nominal_sample_rate); | 552 return static_cast<int>(nominal_sample_rate); |
(...skipping 12 matching lines...) Expand all Loading... |
599 kAudioUnitProperty_Latency, | 565 kAudioUnitProperty_Latency, |
600 kAudioUnitScope_Global, | 566 kAudioUnitScope_Global, |
601 0, | 567 0, |
602 &audio_unit_latency_sec, | 568 &audio_unit_latency_sec, |
603 &size); | 569 &size); |
604 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) | 570 OSSTATUS_DLOG_IF(WARNING, result != noErr, result) |
605 << "Could not get audio unit latency"; | 571 << "Could not get audio unit latency"; |
606 | 572 |
607 // Get input audio device latency. | 573 // Get input audio device latency. |
608 AudioObjectPropertyAddress property_address = { | 574 AudioObjectPropertyAddress property_address = { |
609 kAudioDevicePropertyLatency, | 575 kAudioDevicePropertyLatency, |
610 kAudioDevicePropertyScopeInput, | 576 kAudioDevicePropertyScopeInput, |
611 kAudioObjectPropertyElementMaster | 577 kAudioObjectPropertyElementMaster |
612 }; | 578 }; |
613 UInt32 device_latency_frames = 0; | 579 UInt32 device_latency_frames = 0; |
614 size = sizeof(device_latency_frames); | 580 size = sizeof(device_latency_frames); |
615 result = AudioObjectGetPropertyData(input_device_id_, | 581 result = AudioObjectGetPropertyData(input_device_id_, |
616 &property_address, | 582 &property_address, |
617 0, | 583 0, |
618 NULL, | 584 NULL, |
619 &size, | 585 &size, |
620 &device_latency_frames); | 586 &device_latency_frames); |
621 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; | 587 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; |
622 | 588 |
623 return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) + | 589 return static_cast<double>((audio_unit_latency_sec * |
624 device_latency_frames); | 590 format_.mSampleRate) + device_latency_frames); |
625 } | 591 } |
626 | 592 |
627 double AUAudioInputStream::GetCaptureLatency( | 593 double AUAudioInputStream::GetCaptureLatency( |
628 const AudioTimeStamp* input_time_stamp) { | 594 const AudioTimeStamp* input_time_stamp) { |
629 // Get the delay between between the actual recording instant and the time | 595 // Get the delay between between the actual recording instant and the time |
630 // when the data packet is provided as a callback. | 596 // when the data packet is provided as a callback. |
631 UInt64 capture_time_ns = | 597 UInt64 capture_time_ns = AudioConvertHostTimeToNanos( |
632 AudioConvertHostTimeToNanos(input_time_stamp->mHostTime); | 598 input_time_stamp->mHostTime); |
633 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | 599 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
634 double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) * | 600 double delay_frames = static_cast<double> |
635 format_.mSampleRate); | 601 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); |
636 | 602 |
637 // Total latency is composed by the dynamic latency and the fixed | 603 // Total latency is composed by the dynamic latency and the fixed |
638 // hardware latency. | 604 // hardware latency. |
639 return (delay_frames + hardware_latency_frames_); | 605 return (delay_frames + hardware_latency_frames_); |
640 } | 606 } |
641 | 607 |
642 int AUAudioInputStream::GetNumberOfChannelsFromStream() { | 608 int AUAudioInputStream::GetNumberOfChannelsFromStream() { |
643 // Get the stream format, to be able to read the number of channels. | 609 // Get the stream format, to be able to read the number of channels. |
644 AudioObjectPropertyAddress property_address = { | 610 AudioObjectPropertyAddress property_address = { |
645 kAudioDevicePropertyStreamFormat, | 611 kAudioDevicePropertyStreamFormat, |
646 kAudioDevicePropertyScopeInput, | 612 kAudioDevicePropertyScopeInput, |
647 kAudioObjectPropertyElementMaster | 613 kAudioObjectPropertyElementMaster |
648 }; | 614 }; |
649 AudioStreamBasicDescription stream_format; | 615 AudioStreamBasicDescription stream_format; |
650 UInt32 size = sizeof(stream_format); | 616 UInt32 size = sizeof(stream_format); |
651 OSStatus result = AudioObjectGetPropertyData( | 617 OSStatus result = AudioObjectGetPropertyData(input_device_id_, |
652 input_device_id_, &property_address, 0, NULL, &size, &stream_format); | 618 &property_address, |
| 619 0, |
| 620 NULL, |
| 621 &size, |
| 622 &stream_format); |
653 if (result != noErr) { | 623 if (result != noErr) { |
654 DLOG(WARNING) << "Could not get stream format"; | 624 DLOG(WARNING) << "Could not get stream format"; |
655 return 0; | 625 return 0; |
656 } | 626 } |
657 | 627 |
658 return static_cast<int>(stream_format.mChannelsPerFrame); | 628 return static_cast<int>(stream_format.mChannelsPerFrame); |
659 } | 629 } |
660 | 630 |
661 void AUAudioInputStream::HandleError(OSStatus err) { | 631 void AUAudioInputStream::HandleError(OSStatus err) { |
662 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) << " (" << err | 632 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) |
663 << ")"; | 633 << " (" << err << ")"; |
664 if (sink_) | 634 if (sink_) |
665 sink_->OnError(this); | 635 sink_->OnError(this); |
666 } | 636 } |
667 | 637 |
668 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { | 638 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) { |
669 Boolean is_settable = false; | 639 Boolean is_settable = false; |
670 AudioObjectPropertyAddress property_address = { | 640 AudioObjectPropertyAddress property_address = { |
671 kAudioDevicePropertyVolumeScalar, | 641 kAudioDevicePropertyVolumeScalar, |
672 kAudioDevicePropertyScopeInput, | 642 kAudioDevicePropertyScopeInput, |
673 static_cast<UInt32>(channel) | 643 static_cast<UInt32>(channel) |
674 }; | 644 }; |
675 OSStatus result = AudioObjectIsPropertySettable( | 645 OSStatus result = AudioObjectIsPropertySettable(input_device_id_, |
676 input_device_id_, &property_address, &is_settable); | 646 &property_address, |
| 647 &is_settable); |
677 return (result == noErr) ? is_settable : false; | 648 return (result == noErr) ? is_settable : false; |
678 } | 649 } |
679 | 650 |
680 } // namespace media | 651 } // namespace media |
OLD | NEW |