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

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

Issue 501823002: Used native deinterleaved and float point format for the input streams. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: minor format changes Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698