• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "media/audio/mac/audio_low_latency_input_mac.h"
6 
7 #include <CoreServices/CoreServices.h>
8 
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "base/mac/mac_logging.h"
12 #include "media/audio/mac/audio_manager_mac.h"
13 #include "media/base/audio_bus.h"
14 #include "media/base/data_buffer.h"
15 
16 namespace media {
17 
operator <<(std::ostream & os,const AudioStreamBasicDescription & format)18 static std::ostream& operator<<(std::ostream& os,
19                                 const AudioStreamBasicDescription& format) {
20   os << "sample rate       : " << format.mSampleRate << std::endl
21      << "format ID         : " << format.mFormatID << std::endl
22      << "format flags      : " << format.mFormatFlags << std::endl
23      << "bytes per packet  : " << format.mBytesPerPacket << std::endl
24      << "frames per packet : " << format.mFramesPerPacket << std::endl
25      << "bytes per frame   : " << format.mBytesPerFrame << std::endl
26      << "channels per frame: " << format.mChannelsPerFrame << std::endl
27      << "bits per channel  : " << format.mBitsPerChannel;
28   return os;
29 }
30 
31 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit"
32 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
33 // for more details and background regarding this implementation.
34 
AUAudioInputStream(AudioManagerMac * manager,const AudioParameters & input_params,const AudioParameters & output_params,AudioDeviceID audio_device_id)35 AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager,
36                                        const AudioParameters& input_params,
37                                        const AudioParameters& output_params,
38                                        AudioDeviceID audio_device_id)
39     : manager_(manager),
40       sink_(NULL),
41       audio_unit_(0),
42       input_device_id_(audio_device_id),
43       started_(false),
44       hardware_latency_frames_(0),
45       fifo_delay_bytes_(0),
46       number_of_channels_in_frame_(0),
47       audio_bus_(media::AudioBus::Create(input_params)) {
48   DCHECK(manager_);
49 
50   // Set up the desired (output) format specified by the client.
51   format_.mSampleRate = input_params.sample_rate();
52   format_.mFormatID = kAudioFormatLinearPCM;
53   format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
54                          kLinearPCMFormatFlagIsSignedInteger;
55   format_.mBitsPerChannel = input_params.bits_per_sample();
56   format_.mChannelsPerFrame = input_params.channels();
57   format_.mFramesPerPacket = 1;  // uncompressed audio
58   format_.mBytesPerPacket = (format_.mBitsPerChannel *
59                              input_params.channels()) / 8;
60   format_.mBytesPerFrame = format_.mBytesPerPacket;
61   format_.mReserved = 0;
62 
63   DVLOG(1) << "Desired ouput format: " << format_;
64 
65   // Set number of sample frames per callback used by the internal audio layer.
66   // An internal FIFO is then utilized to adapt the internal size to the size
67   // requested by the client.
68   number_of_frames_ = output_params.frames_per_buffer();
69   DVLOG(1) << "Size of data buffer in frames : " << number_of_frames_;
70 
71   // Derive size (in bytes) of the buffers that we will render to.
72   UInt32 data_byte_size = number_of_frames_ * format_.mBytesPerFrame;
73   DVLOG(1) << "Size of data buffer in bytes : " << data_byte_size;
74 
75   // Allocate AudioBuffers to be used as storage for the received audio.
76   // The AudioBufferList structure works as a placeholder for the
77   // AudioBuffer structure, which holds a pointer to the actual data buffer.
78   audio_data_buffer_.reset(new uint8[data_byte_size]);
79   audio_buffer_list_.mNumberBuffers = 1;
80 
81   AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
82   audio_buffer->mNumberChannels = input_params.channels();
83   audio_buffer->mDataByteSize = data_byte_size;
84   audio_buffer->mData = audio_data_buffer_.get();
85 
86   // Set up an internal FIFO buffer that will accumulate recorded audio frames
87   // until a requested size is ready to be sent to the client.
88   // It is not possible to ask for less than |kAudioFramesPerCallback| number of
89   // audio frames.
90   size_t requested_size_frames =
91       input_params.GetBytesPerBuffer() / format_.mBytesPerPacket;
92   if (requested_size_frames < number_of_frames_) {
93     // For devices that only support a low sample rate like 8kHz, we adjust the
94     // buffer size to match number_of_frames_.  The value of number_of_frames_
95     // in this case has not been calculated based on hardware settings but
96     // rather our hardcoded defaults (see ChooseBufferSize).
97     requested_size_frames = number_of_frames_;
98   }
99 
100   requested_size_bytes_ = requested_size_frames * format_.mBytesPerFrame;
101   DVLOG(1) << "Requested buffer size in bytes : " << requested_size_bytes_;
102   DVLOG_IF(0, requested_size_frames > number_of_frames_) << "FIFO is used";
103 
104   const int number_of_bytes = number_of_frames_ * format_.mBytesPerFrame;
105   fifo_delay_bytes_ = requested_size_bytes_ - number_of_bytes;
106 
107   // Allocate some extra memory to avoid memory reallocations.
108   // Ensure that the size is an even multiple of |number_of_frames_ and
109   // larger than |requested_size_frames|.
110   // Example: number_of_frames_=128, requested_size_frames=480 =>
111   // allocated space equals 4*128=512 audio frames
112   const int max_forward_capacity = number_of_bytes *
113       ((requested_size_frames / number_of_frames_) + 1);
114   fifo_.reset(new media::SeekableBuffer(0, max_forward_capacity));
115 
116   data_ = new media::DataBuffer(requested_size_bytes_);
117 }
118 
~AUAudioInputStream()119 AUAudioInputStream::~AUAudioInputStream() {}
120 
121 // Obtain and open the AUHAL AudioOutputUnit for recording.
Open()122 bool AUAudioInputStream::Open() {
123   // Verify that we are not already opened.
124   if (audio_unit_)
125     return false;
126 
127   // Verify that we have a valid device.
128   if (input_device_id_ == kAudioObjectUnknown) {
129     NOTREACHED() << "Device ID is unknown";
130     return false;
131   }
132 
133   // Start by obtaining an AudioOuputUnit using an AUHAL component description.
134 
135   Component comp;
136   ComponentDescription desc;
137 
138   // Description for the Audio Unit we want to use (AUHAL in this case).
139   desc.componentType = kAudioUnitType_Output;
140   desc.componentSubType = kAudioUnitSubType_HALOutput;
141   desc.componentManufacturer = kAudioUnitManufacturer_Apple;
142   desc.componentFlags = 0;
143   desc.componentFlagsMask = 0;
144   comp = FindNextComponent(0, &desc);
145   DCHECK(comp);
146 
147   // Get access to the service provided by the specified Audio Unit.
148   OSStatus result = OpenAComponent(comp, &audio_unit_);
149   if (result) {
150     HandleError(result);
151     return false;
152   }
153 
154   // Enable IO on the input scope of the Audio Unit.
155 
156   // After creating the AUHAL object, we must enable IO on the input scope
157   // of the Audio Unit to obtain the device input. Input must be explicitly
158   // enabled with the kAudioOutputUnitProperty_EnableIO property on Element 1
159   // of the AUHAL. Beacause the AUHAL can be used for both input and output,
160   // we must also disable IO on the output scope.
161 
162   UInt32 enableIO = 1;
163 
164   // Enable input on the AUHAL.
165   result = AudioUnitSetProperty(audio_unit_,
166                                 kAudioOutputUnitProperty_EnableIO,
167                                 kAudioUnitScope_Input,
168                                 1,          // input element 1
169                                 &enableIO,  // enable
170                                 sizeof(enableIO));
171   if (result) {
172     HandleError(result);
173     return false;
174   }
175 
176   // Disable output on the AUHAL.
177   enableIO = 0;
178   result = AudioUnitSetProperty(audio_unit_,
179                                 kAudioOutputUnitProperty_EnableIO,
180                                 kAudioUnitScope_Output,
181                                 0,          // output element 0
182                                 &enableIO,  // disable
183                                 sizeof(enableIO));
184   if (result) {
185     HandleError(result);
186     return false;
187   }
188 
189   // Next, set the audio device to be the Audio Unit's current device.
190   // Note that, devices can only be set to the AUHAL after enabling IO.
191   result = AudioUnitSetProperty(audio_unit_,
192                                 kAudioOutputUnitProperty_CurrentDevice,
193                                 kAudioUnitScope_Global,
194                                 0,
195                                 &input_device_id_,
196                                 sizeof(input_device_id_));
197   if (result) {
198     HandleError(result);
199     return false;
200   }
201 
202   // Register the input procedure for the AUHAL.
203   // This procedure will be called when the AUHAL has received new data
204   // from the input device.
205   AURenderCallbackStruct callback;
206   callback.inputProc = InputProc;
207   callback.inputProcRefCon = this;
208   result = AudioUnitSetProperty(audio_unit_,
209                                 kAudioOutputUnitProperty_SetInputCallback,
210                                 kAudioUnitScope_Global,
211                                 0,
212                                 &callback,
213                                 sizeof(callback));
214   if (result) {
215     HandleError(result);
216     return false;
217   }
218 
219   // Set up the the desired (output) format.
220   // For obtaining input from a device, the device format is always expressed
221   // on the output scope of the AUHAL's Element 1.
222   result = AudioUnitSetProperty(audio_unit_,
223                                 kAudioUnitProperty_StreamFormat,
224                                 kAudioUnitScope_Output,
225                                 1,
226                                 &format_,
227                                 sizeof(format_));
228   if (result) {
229     HandleError(result);
230     return false;
231   }
232 
233   // Set the desired number of frames in the IO buffer (output scope).
234   // WARNING: Setting this value changes the frame size for all input audio
235   // units in the current process.  As a result, the AURenderCallback must be
236   // able to handle arbitrary buffer sizes and FIFO appropriately.
237   UInt32 buffer_size = 0;
238   UInt32 property_size = sizeof(buffer_size);
239   result = AudioUnitGetProperty(audio_unit_,
240                                 kAudioDevicePropertyBufferFrameSize,
241                                 kAudioUnitScope_Output,
242                                 1,
243                                 &buffer_size,
244                                 &property_size);
245   if (result != noErr) {
246     HandleError(result);
247     return false;
248   }
249 
250   // Only set the buffer size if we're the only active stream or the buffer size
251   // is lower than the current buffer size.
252   if (manager_->input_stream_count() == 1 || number_of_frames_ < buffer_size) {
253     buffer_size = number_of_frames_;
254     result = AudioUnitSetProperty(audio_unit_,
255                                   kAudioDevicePropertyBufferFrameSize,
256                                   kAudioUnitScope_Output,
257                                   1,
258                                   &buffer_size,
259                                   sizeof(buffer_size));
260     if (result != noErr) {
261       HandleError(result);
262       return false;
263     }
264   }
265 
266   // Finally, initialize the audio unit and ensure that it is ready to render.
267   // Allocates memory according to the maximum number of audio frames
268   // it can produce in response to a single render call.
269   result = AudioUnitInitialize(audio_unit_);
270   if (result) {
271     HandleError(result);
272     return false;
273   }
274 
275   // The hardware latency is fixed and will not change during the call.
276   hardware_latency_frames_ = GetHardwareLatency();
277 
278   // The master channel is 0, Left and right are channels 1 and 2.
279   // And the master channel is not counted in |number_of_channels_in_frame_|.
280   number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
281 
282   return true;
283 }
284 
Start(AudioInputCallback * callback)285 void AUAudioInputStream::Start(AudioInputCallback* callback) {
286   DCHECK(callback);
287   DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully";
288   if (started_ || !audio_unit_)
289     return;
290 
291   // Check if we should defer Start() for http://crbug.com/160920.
292   if (manager_->ShouldDeferStreamStart()) {
293     // Use a cancellable closure so that if Stop() is called before Start()
294     // actually runs, we can cancel the pending start.
295     deferred_start_cb_.Reset(base::Bind(
296         &AUAudioInputStream::Start, base::Unretained(this), callback));
297     manager_->GetTaskRunner()->PostDelayedTask(
298         FROM_HERE,
299         deferred_start_cb_.callback(),
300         base::TimeDelta::FromSeconds(
301             AudioManagerMac::kStartDelayInSecsForPowerEvents));
302     return;
303   }
304 
305   sink_ = callback;
306   StartAgc();
307   OSStatus result = AudioOutputUnitStart(audio_unit_);
308   if (result == noErr) {
309     started_ = true;
310   }
311   OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
312       << "Failed to start acquiring data";
313 }
314 
Stop()315 void AUAudioInputStream::Stop() {
316   if (!started_)
317     return;
318   StopAgc();
319   OSStatus result = AudioOutputUnitStop(audio_unit_);
320   DCHECK_EQ(result, noErr);
321   started_ = false;
322   sink_ = NULL;
323 
324   OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
325       << "Failed to stop acquiring data";
326 }
327 
Close()328 void AUAudioInputStream::Close() {
329   // It is valid to call Close() before calling open or Start().
330   // It is also valid to call Close() after Start() has been called.
331   if (started_) {
332     Stop();
333   }
334   if (audio_unit_) {
335     // Deallocate the audio unit’s resources.
336     AudioUnitUninitialize(audio_unit_);
337 
338     // Terminates our connection to the AUHAL component.
339     CloseComponent(audio_unit_);
340     audio_unit_ = 0;
341   }
342 
343   // Inform the audio manager that we have been closed. This can cause our
344   // destruction.
345   manager_->ReleaseInputStream(this);
346 }
347 
GetMaxVolume()348 double AUAudioInputStream::GetMaxVolume() {
349   // Verify that we have a valid device.
350   if (input_device_id_ == kAudioObjectUnknown) {
351     NOTREACHED() << "Device ID is unknown";
352     return 0.0;
353   }
354 
355   // Query if any of the master, left or right channels has volume control.
356   for (int i = 0; i <= number_of_channels_in_frame_; ++i) {
357     // If the volume is settable, the  valid volume range is [0.0, 1.0].
358     if (IsVolumeSettableOnChannel(i))
359       return 1.0;
360   }
361 
362   // Volume control is not available for the audio stream.
363   return 0.0;
364 }
365 
SetVolume(double volume)366 void AUAudioInputStream::SetVolume(double volume) {
367   DVLOG(1) << "SetVolume(volume=" << volume << ")";
368   DCHECK_GE(volume, 0.0);
369   DCHECK_LE(volume, 1.0);
370 
371   // Verify that we have a valid device.
372   if (input_device_id_ == kAudioObjectUnknown) {
373     NOTREACHED() << "Device ID is unknown";
374     return;
375   }
376 
377   Float32 volume_float32 = static_cast<Float32>(volume);
378   AudioObjectPropertyAddress property_address = {
379     kAudioDevicePropertyVolumeScalar,
380     kAudioDevicePropertyScopeInput,
381     kAudioObjectPropertyElementMaster
382   };
383 
384   // Try to set the volume for master volume channel.
385   if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
386     OSStatus result = AudioObjectSetPropertyData(input_device_id_,
387                                                  &property_address,
388                                                  0,
389                                                  NULL,
390                                                  sizeof(volume_float32),
391                                                  &volume_float32);
392     if (result != noErr) {
393       DLOG(WARNING) << "Failed to set volume to " << volume_float32;
394     }
395     return;
396   }
397 
398   // There is no master volume control, try to set volume for each channel.
399   int successful_channels = 0;
400   for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
401     property_address.mElement = static_cast<UInt32>(i);
402     if (IsVolumeSettableOnChannel(i)) {
403       OSStatus result = AudioObjectSetPropertyData(input_device_id_,
404                                                    &property_address,
405                                                    0,
406                                                    NULL,
407                                                    sizeof(volume_float32),
408                                                    &volume_float32);
409       if (result == noErr)
410         ++successful_channels;
411     }
412   }
413 
414   DLOG_IF(WARNING, successful_channels == 0)
415       << "Failed to set volume to " << volume_float32;
416 
417   // Update the AGC volume level based on the last setting above. Note that,
418   // the volume-level resolution is not infinite and it is therefore not
419   // possible to assume that the volume provided as input parameter can be
420   // used directly. Instead, a new query to the audio hardware is required.
421   // This method does nothing if AGC is disabled.
422   UpdateAgcVolume();
423 }
424 
GetVolume()425 double AUAudioInputStream::GetVolume() {
426   // Verify that we have a valid device.
427   if (input_device_id_ == kAudioObjectUnknown){
428     NOTREACHED() << "Device ID is unknown";
429     return 0.0;
430   }
431 
432   AudioObjectPropertyAddress property_address = {
433     kAudioDevicePropertyVolumeScalar,
434     kAudioDevicePropertyScopeInput,
435     kAudioObjectPropertyElementMaster
436   };
437 
438   if (AudioObjectHasProperty(input_device_id_, &property_address)) {
439     // The device supports master volume control, get the volume from the
440     // master channel.
441     Float32 volume_float32 = 0.0;
442     UInt32 size = sizeof(volume_float32);
443     OSStatus result = AudioObjectGetPropertyData(input_device_id_,
444                                                  &property_address,
445                                                  0,
446                                                  NULL,
447                                                  &size,
448                                                  &volume_float32);
449     if (result == noErr)
450       return static_cast<double>(volume_float32);
451   } else {
452     // There is no master volume control, try to get the average volume of
453     // all the channels.
454     Float32 volume_float32 = 0.0;
455     int successful_channels = 0;
456     for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
457       property_address.mElement = static_cast<UInt32>(i);
458       if (AudioObjectHasProperty(input_device_id_, &property_address)) {
459         Float32 channel_volume = 0;
460         UInt32 size = sizeof(channel_volume);
461         OSStatus result = AudioObjectGetPropertyData(input_device_id_,
462                                                      &property_address,
463                                                      0,
464                                                      NULL,
465                                                      &size,
466                                                      &channel_volume);
467         if (result == noErr) {
468           volume_float32 += channel_volume;
469           ++successful_channels;
470         }
471       }
472     }
473 
474     // Get the average volume of the channels.
475     if (successful_channels != 0)
476       return static_cast<double>(volume_float32 / successful_channels);
477   }
478 
479   DLOG(WARNING) << "Failed to get volume";
480   return 0.0;
481 }
482 
483 // AUHAL AudioDeviceOutput unit callback
InputProc(void * user_data,AudioUnitRenderActionFlags * flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)484 OSStatus AUAudioInputStream::InputProc(void* user_data,
485                                        AudioUnitRenderActionFlags* flags,
486                                        const AudioTimeStamp* time_stamp,
487                                        UInt32 bus_number,
488                                        UInt32 number_of_frames,
489                                        AudioBufferList* io_data) {
490   // Verify that the correct bus is used (Input bus/Element 1)
491   DCHECK_EQ(bus_number, static_cast<UInt32>(1));
492   AUAudioInputStream* audio_input =
493       reinterpret_cast<AUAudioInputStream*>(user_data);
494   DCHECK(audio_input);
495   if (!audio_input)
496     return kAudioUnitErr_InvalidElement;
497 
498   // Receive audio from the AUHAL from the output scope of the Audio Unit.
499   OSStatus result = AudioUnitRender(audio_input->audio_unit(),
500                                     flags,
501                                     time_stamp,
502                                     bus_number,
503                                     number_of_frames,
504                                     audio_input->audio_buffer_list());
505   if (result)
506     return result;
507 
508   // Deliver recorded data to the consumer as a callback.
509   return audio_input->Provide(number_of_frames,
510                               audio_input->audio_buffer_list(),
511                               time_stamp);
512 }
513 
Provide(UInt32 number_of_frames,AudioBufferList * io_data,const AudioTimeStamp * time_stamp)514 OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
515                                      AudioBufferList* io_data,
516                                      const AudioTimeStamp* time_stamp) {
517   // Update the capture latency.
518   double capture_latency_frames = GetCaptureLatency(time_stamp);
519 
520   // The AGC volume level is updated once every second on a separate thread.
521   // Note that, |volume| is also updated each time SetVolume() is called
522   // through IPC by the render-side AGC.
523   double normalized_volume = 0.0;
524   GetAgcVolume(&normalized_volume);
525 
526   AudioBuffer& buffer = io_data->mBuffers[0];
527   uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
528   uint32 capture_delay_bytes = static_cast<uint32>
529       ((capture_latency_frames + 0.5) * format_.mBytesPerFrame);
530   // Account for the extra delay added by the FIFO.
531   capture_delay_bytes += fifo_delay_bytes_;
532   DCHECK(audio_data);
533   if (!audio_data)
534     return kAudioUnitErr_InvalidElement;
535 
536   // Accumulate captured audio in FIFO until we can match the output size
537   // requested by the client.
538   fifo_->Append(audio_data, buffer.mDataByteSize);
539 
540   // Deliver recorded data to the client as soon as the FIFO contains a
541   // sufficient amount.
542   if (fifo_->forward_bytes() >= requested_size_bytes_) {
543     // Read from FIFO into temporary data buffer.
544     fifo_->Read(data_->writable_data(), requested_size_bytes_);
545 
546     // Copy captured (and interleaved) data into deinterleaved audio bus.
547     audio_bus_->FromInterleaved(
548         data_->data(), audio_bus_->frames(), format_.mBitsPerChannel / 8);
549 
550     // Deliver data packet, delay estimation and volume level to the user.
551     sink_->OnData(
552         this, audio_bus_.get(), capture_delay_bytes, normalized_volume);
553   }
554 
555   return noErr;
556 }
557 
HardwareSampleRate()558 int AUAudioInputStream::HardwareSampleRate() {
559   // Determine the default input device's sample-rate.
560   AudioDeviceID device_id = kAudioObjectUnknown;
561   UInt32 info_size = sizeof(device_id);
562 
563   AudioObjectPropertyAddress default_input_device_address = {
564     kAudioHardwarePropertyDefaultInputDevice,
565     kAudioObjectPropertyScopeGlobal,
566     kAudioObjectPropertyElementMaster
567   };
568   OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
569                                                &default_input_device_address,
570                                                0,
571                                                0,
572                                                &info_size,
573                                                &device_id);
574   if (result != noErr)
575     return 0.0;
576 
577   Float64 nominal_sample_rate;
578   info_size = sizeof(nominal_sample_rate);
579 
580   AudioObjectPropertyAddress nominal_sample_rate_address = {
581     kAudioDevicePropertyNominalSampleRate,
582     kAudioObjectPropertyScopeGlobal,
583     kAudioObjectPropertyElementMaster
584   };
585   result = AudioObjectGetPropertyData(device_id,
586                                       &nominal_sample_rate_address,
587                                       0,
588                                       0,
589                                       &info_size,
590                                       &nominal_sample_rate);
591   if (result != noErr)
592     return 0.0;
593 
594   return static_cast<int>(nominal_sample_rate);
595 }
596 
GetHardwareLatency()597 double AUAudioInputStream::GetHardwareLatency() {
598   if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
599     DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
600     return 0.0;
601   }
602 
603   // Get audio unit latency.
604   Float64 audio_unit_latency_sec = 0.0;
605   UInt32 size = sizeof(audio_unit_latency_sec);
606   OSStatus result = AudioUnitGetProperty(audio_unit_,
607                                          kAudioUnitProperty_Latency,
608                                          kAudioUnitScope_Global,
609                                          0,
610                                          &audio_unit_latency_sec,
611                                          &size);
612   OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
613       << "Could not get audio unit latency";
614 
615   // Get input audio device latency.
616   AudioObjectPropertyAddress property_address = {
617     kAudioDevicePropertyLatency,
618     kAudioDevicePropertyScopeInput,
619     kAudioObjectPropertyElementMaster
620   };
621   UInt32 device_latency_frames = 0;
622   size = sizeof(device_latency_frames);
623   result = AudioObjectGetPropertyData(input_device_id_,
624                                       &property_address,
625                                       0,
626                                       NULL,
627                                       &size,
628                                       &device_latency_frames);
629   DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
630 
631   return static_cast<double>((audio_unit_latency_sec *
632       format_.mSampleRate) + device_latency_frames);
633 }
634 
GetCaptureLatency(const AudioTimeStamp * input_time_stamp)635 double AUAudioInputStream::GetCaptureLatency(
636     const AudioTimeStamp* input_time_stamp) {
637   // Get the delay between between the actual recording instant and the time
638   // when the data packet is provided as a callback.
639   UInt64 capture_time_ns = AudioConvertHostTimeToNanos(
640       input_time_stamp->mHostTime);
641   UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
642   double delay_frames = static_cast<double>
643       (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
644 
645   // Total latency is composed by the dynamic latency and the fixed
646   // hardware latency.
647   return (delay_frames + hardware_latency_frames_);
648 }
649 
GetNumberOfChannelsFromStream()650 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
651   // Get the stream format, to be able to read the number of channels.
652   AudioObjectPropertyAddress property_address = {
653     kAudioDevicePropertyStreamFormat,
654     kAudioDevicePropertyScopeInput,
655     kAudioObjectPropertyElementMaster
656   };
657   AudioStreamBasicDescription stream_format;
658   UInt32 size = sizeof(stream_format);
659   OSStatus result = AudioObjectGetPropertyData(input_device_id_,
660                                                &property_address,
661                                                0,
662                                                NULL,
663                                                &size,
664                                                &stream_format);
665   if (result != noErr) {
666     DLOG(WARNING) << "Could not get stream format";
667     return 0;
668   }
669 
670   return static_cast<int>(stream_format.mChannelsPerFrame);
671 }
672 
HandleError(OSStatus err)673 void AUAudioInputStream::HandleError(OSStatus err) {
674   NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
675                << " (" << err << ")";
676   if (sink_)
677     sink_->OnError(this);
678 }
679 
IsVolumeSettableOnChannel(int channel)680 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
681   Boolean is_settable = false;
682   AudioObjectPropertyAddress property_address = {
683     kAudioDevicePropertyVolumeScalar,
684     kAudioDevicePropertyScopeInput,
685     static_cast<UInt32>(channel)
686   };
687   OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
688                                                   &property_address,
689                                                   &is_settable);
690   return (result == noErr) ? is_settable : false;
691 }
692 
693 }  // namespace media
694