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