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