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