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 #include "media/audio/mac/audio_low_latency_input_mac.h"
5
6 #include <CoreAudio/AudioHardware.h>
7 #include <CoreServices/CoreServices.h>
8 #include <dlfcn.h>
9 #include <mach-o/loader.h>
10 #include <mach/mach.h>
11 #include <string>
12
13 #include "base/bind.h"
14 #include "base/logging.h"
15 #include "base/mac/foundation_util.h"
16 #include "base/mac/mac_logging.h"
17 #include "base/mac/mac_util.h"
18 #include "base/mac/scoped_cftyperef.h"
19 #include "base/mac/scoped_mach_port.h"
20 #include "base/metrics/histogram_functions.h"
21 #include "base/metrics/histogram_macros.h"
22 #include "base/strings/strcat.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/strings/sys_string_conversions.h"
25 #include "base/system/sys_info.h"
26 #include "base/time/time.h"
27 #include "base/trace_event/trace_event.h"
28 #include "media/audio/mac/core_audio_util_mac.h"
29 #include "media/audio/mac/scoped_audio_unit.h"
30 #include "media/base/audio_bus.h"
31 #include "media/base/audio_timestamp_helper.h"
32 #include "media/base/data_buffer.h"
33
34 namespace {
35 extern "C" {
36 // See:
37 // https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/PAL/pal/spi/cf/CoreAudioSPI.h?rev=228264
38 OSStatus AudioDeviceDuck(AudioDeviceID inDevice,
39 Float32 inDuckedLevel,
40 const AudioTimeStamp* __nullable inStartTime,
41 Float32 inRampDuration) __attribute__((weak_import));
42 }
43
UndoDucking(AudioDeviceID output_device_id)44 void UndoDucking(AudioDeviceID output_device_id) {
45 if (AudioDeviceDuck != nullptr) {
46 // Ramp the volume back up over half a second.
47 AudioDeviceDuck(output_device_id, 1.0, nullptr, 0.5);
48 }
49 }
50
51 } // namespace
52
53 namespace media {
54
55 // Number of blocks of buffers used in the |fifo_|.
56 const int kNumberOfBlocksBufferInFifo = 2;
57
58 // Max length of sequence of TooManyFramesToProcessError errors.
59 // The stream will be stopped as soon as this time limit is passed.
60 const int kMaxErrorTimeoutInSeconds = 1;
61
62 // A one-shot timer is created and started in Start() and it triggers
63 // CheckInputStartupSuccess() after this amount of time. UMA stats marked
64 // Media.Audio.InputStartupSuccessMac is then updated where true is added
65 // if input callbacks have started, and false otherwise.
66 const int kInputCallbackStartTimeoutInSeconds = 5;
67
68 // Returns true if the format flags in |format_flags| has the "non-interleaved"
69 // flag (kAudioFormatFlagIsNonInterleaved) cleared (set to 0).
FormatIsInterleaved(UInt32 format_flags)70 static bool FormatIsInterleaved(UInt32 format_flags) {
71 return !(format_flags & kAudioFormatFlagIsNonInterleaved);
72 }
73
74 // Converts the 32-bit non-terminated 4 byte string into an std::string.
75 // Example: code=1735354734 <=> 'goin' <=> kAudioDevicePropertyDeviceIsRunning.
FourCharFormatCodeToString(UInt32 code)76 static std::string FourCharFormatCodeToString(UInt32 code) {
77 char code_string[5];
78 // Converts a 32-bit integer from the host’s native byte order to big-endian.
79 UInt32 code_id = CFSwapInt32HostToBig(code);
80 bcopy(&code_id, code_string, 4);
81 code_string[4] = '\0';
82 return std::string(code_string);
83 }
84
operator <<(std::ostream & os,const AudioStreamBasicDescription & format)85 static std::ostream& operator<<(std::ostream& os,
86 const AudioStreamBasicDescription& format) {
87 std::string format_string = FourCharFormatCodeToString(format.mFormatID);
88 os << "sample rate : " << format.mSampleRate << std::endl
89 << "format ID : " << format_string << std::endl
90 << "format flags : " << format.mFormatFlags << std::endl
91 << "bytes per packet : " << format.mBytesPerPacket << std::endl
92 << "frames per packet : " << format.mFramesPerPacket << std::endl
93 << "bytes per frame : " << format.mBytesPerFrame << std::endl
94 << "channels per frame: " << format.mChannelsPerFrame << std::endl
95 << "bits per channel : " << format.mBitsPerChannel << std::endl
96 << "reserved : " << format.mReserved << std::endl
97 << "interleaved : "
98 << (FormatIsInterleaved(format.mFormatFlags) ? "yes" : "no");
99 return os;
100 }
101
OnGetPlayoutData(void * in_ref_con,AudioUnitRenderActionFlags * flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 num_frames,AudioBufferList * io_data)102 static OSStatus OnGetPlayoutData(void* in_ref_con,
103 AudioUnitRenderActionFlags* flags,
104 const AudioTimeStamp* time_stamp,
105 UInt32 bus_number,
106 UInt32 num_frames,
107 AudioBufferList* io_data) {
108 *flags |= kAudioUnitRenderAction_OutputIsSilence;
109 return noErr;
110 }
111
GetInputDeviceStreamFormat(AudioUnit audio_unit,AudioStreamBasicDescription * format)112 static OSStatus GetInputDeviceStreamFormat(
113 AudioUnit audio_unit,
114 AudioStreamBasicDescription* format) {
115 DCHECK(audio_unit);
116 UInt32 property_size = sizeof(*format);
117 // Get the audio stream data format on the input scope of the input element
118 // since it is connected to the current input device.
119 OSStatus result =
120 AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat,
121 kAudioUnitScope_Input, 1, format, &property_size);
122 DVLOG(1) << "Input device stream format: " << *format;
123 return result;
124 }
125
126 // Returns the number of physical processors on the device.
NumberOfPhysicalProcessors()127 static int NumberOfPhysicalProcessors() {
128 base::mac::ScopedMachSendRight mach_host(mach_host_self());
129 host_basic_info hbi = {};
130 mach_msg_type_number_t info_count = HOST_BASIC_INFO_COUNT;
131 kern_return_t kr =
132 host_info(mach_host.get(), HOST_BASIC_INFO,
133 reinterpret_cast<host_info_t>(&hbi), &info_count);
134
135 int n_physical_cores = 0;
136 if (kr != KERN_SUCCESS) {
137 n_physical_cores = 1;
138 LOG(ERROR) << "Failed to determine number of physical cores, assuming 1";
139 } else {
140 n_physical_cores = hbi.physical_cpu;
141 }
142 DCHECK_EQ(HOST_BASIC_INFO_COUNT, info_count);
143 return n_physical_cores;
144 }
145
146 // Adds extra system information to Media.AudioXXXMac UMA statistics.
147 // Only called when it has been detected that audio callbacks does not start
148 // as expected.
AddSystemInfoToUMA()149 static void AddSystemInfoToUMA() {
150 // Number of logical processors/cores on the current machine.
151 UMA_HISTOGRAM_COUNTS_1M("Media.Audio.LogicalProcessorsMac",
152 base::SysInfo::NumberOfProcessors());
153 // Number of physical processors/cores on the current machine.
154 UMA_HISTOGRAM_COUNTS_1M("Media.Audio.PhysicalProcessorsMac",
155 NumberOfPhysicalProcessors());
156 DVLOG(1) << "logical processors: " << base::SysInfo::NumberOfProcessors();
157 DVLOG(1) << "physical processors: " << NumberOfPhysicalProcessors();
158 }
159
160 // Finds the first subdevice, in an aggregate device, with output streams.
FindFirstOutputSubdevice(AudioDeviceID aggregate_device_id)161 static AudioDeviceID FindFirstOutputSubdevice(
162 AudioDeviceID aggregate_device_id) {
163 const AudioObjectPropertyAddress property_address = {
164 kAudioAggregateDevicePropertyFullSubDeviceList,
165 kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
166 base::ScopedCFTypeRef<CFArrayRef> subdevices;
167 UInt32 size = sizeof(subdevices);
168 OSStatus result = AudioObjectGetPropertyData(
169 aggregate_device_id, &property_address, 0 /* inQualifierDataSize */,
170 nullptr /* inQualifierData */, &size, subdevices.InitializeInto());
171
172 if (result != noErr) {
173 OSSTATUS_LOG(WARNING, result)
174 << "Failed to read property "
175 << kAudioAggregateDevicePropertyFullSubDeviceList << " for device "
176 << aggregate_device_id;
177 return kAudioObjectUnknown;
178 }
179
180 AudioDeviceID output_subdevice_id = kAudioObjectUnknown;
181 DCHECK_EQ(CFGetTypeID(subdevices), CFArrayGetTypeID());
182 const CFIndex count = CFArrayGetCount(subdevices);
183 for (CFIndex i = 0; i != count; ++i) {
184 CFStringRef value =
185 base::mac::CFCast<CFStringRef>(CFArrayGetValueAtIndex(subdevices, i));
186 if (value) {
187 std::string uid = base::SysCFStringRefToUTF8(value);
188 output_subdevice_id = AudioManagerMac::GetAudioDeviceIdByUId(false, uid);
189 if (output_subdevice_id != kAudioObjectUnknown &&
190 core_audio_mac::GetNumStreams(output_subdevice_id, false) > 0) {
191 break;
192 }
193 }
194 }
195
196 return output_subdevice_id;
197 }
198
199 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit"
200 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
201 // for more details and background regarding this implementation.
202
AUAudioInputStream(AudioManagerMac * manager,const AudioParameters & input_params,AudioDeviceID audio_device_id,const AudioManager::LogCallback & log_callback,AudioManagerBase::VoiceProcessingMode voice_processing_mode)203 AUAudioInputStream::AUAudioInputStream(
204 AudioManagerMac* manager,
205 const AudioParameters& input_params,
206 AudioDeviceID audio_device_id,
207 const AudioManager::LogCallback& log_callback,
208 AudioManagerBase::VoiceProcessingMode voice_processing_mode)
209 : manager_(manager),
210 input_params_(input_params),
211 number_of_frames_provided_(0),
212 io_buffer_frame_size_(0),
213 sink_(nullptr),
214 audio_unit_(0),
215 input_device_id_(audio_device_id),
216 number_of_channels_in_frame_(0),
217 fifo_(input_params.channels(),
218 input_params.frames_per_buffer(),
219 kNumberOfBlocksBufferInFifo),
220 got_input_callback_(false),
221 input_callback_is_active_(false),
222 buffer_size_was_changed_(false),
223 audio_unit_render_has_worked_(false),
224 noise_reduction_suppressed_(false),
225 use_voice_processing_(voice_processing_mode ==
226 AudioManagerBase::VoiceProcessingMode::kEnabled),
227 output_device_id_for_aec_(kAudioObjectUnknown),
228 last_sample_time_(0.0),
229 last_number_of_frames_(0),
230 total_lost_frames_(0),
231 largest_glitch_frames_(0),
232 glitches_detected_(0),
233 log_callback_(log_callback) {
234 DCHECK(manager_);
235 CHECK(log_callback_ != AudioManager::LogCallback());
236 if (use_voice_processing_) {
237 DCHECK(input_params.channels() == 1 || input_params.channels() == 2);
238 const bool got_default_device =
239 AudioManagerMac::GetDefaultOutputDevice(&output_device_id_for_aec_);
240 DCHECK(got_default_device);
241 }
242
243 const SampleFormat kSampleFormat = kSampleFormatS16;
244
245 // Set up the desired (output) format specified by the client.
246 format_.mSampleRate = input_params.sample_rate();
247 format_.mFormatID = kAudioFormatLinearPCM;
248 format_.mFormatFlags =
249 kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
250 DCHECK(FormatIsInterleaved(format_.mFormatFlags));
251 format_.mBitsPerChannel = SampleFormatToBitsPerChannel(kSampleFormat);
252 format_.mChannelsPerFrame = input_params.channels();
253 format_.mFramesPerPacket = 1; // uncompressed audio
254 format_.mBytesPerPacket = format_.mBytesPerFrame =
255 input_params.GetBytesPerFrame(kSampleFormat);
256 format_.mReserved = 0;
257
258 DVLOG(1) << "ctor";
259 DVLOG(1) << "device ID: 0x" << std::hex << audio_device_id;
260 DVLOG(1) << "buffer size : " << input_params.frames_per_buffer();
261 DVLOG(1) << "channels : " << input_params.channels();
262 DVLOG(1) << "desired output format: " << format_;
263
264 // Derive size (in bytes) of the buffers that we will render to.
265 UInt32 data_byte_size =
266 input_params.frames_per_buffer() * format_.mBytesPerFrame;
267 DVLOG(1) << "size of data buffer in bytes : " << data_byte_size;
268
269 // Allocate AudioBuffers to be used as storage for the received audio.
270 // The AudioBufferList structure works as a placeholder for the
271 // AudioBuffer structure, which holds a pointer to the actual data buffer.
272 audio_data_buffer_.reset(new uint8_t[data_byte_size]);
273 // We ask for noninterleaved audio.
274 audio_buffer_list_.mNumberBuffers = 1;
275
276 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
277 audio_buffer->mNumberChannels = input_params.channels();
278 audio_buffer->mDataByteSize = data_byte_size;
279 audio_buffer->mData = audio_data_buffer_.get();
280 }
281
~AUAudioInputStream()282 AUAudioInputStream::~AUAudioInputStream() {
283 DVLOG(1) << "~dtor";
284 ReportAndResetStats();
285 }
286
287 // Obtain and open the AUHAL AudioOutputUnit for recording.
Open()288 bool AUAudioInputStream::Open() {
289 DCHECK(thread_checker_.CalledOnValidThread());
290 DVLOG(1) << "Open";
291 DCHECK(!audio_unit_);
292
293 // Verify that we have a valid device. Send appropriate error code to
294 // HandleError() to ensure that the error type is added to UMA stats.
295 if (input_device_id_ == kAudioObjectUnknown) {
296 NOTREACHED() << "Device ID is unknown";
297 HandleError(kAudioUnitErr_InvalidElement);
298 return false;
299 }
300
301 // The requested sample-rate must match the hardware sample-rate.
302 const int sample_rate =
303 AudioManagerMac::HardwareSampleRateForDevice(input_device_id_);
304 DCHECK_EQ(sample_rate, format_.mSampleRate);
305
306 log_callback_.Run(base::StrCat(
307 {"AU in: Open using ", use_voice_processing_ ? "VPAU" : "AUHAL"}));
308
309 const bool success =
310 use_voice_processing_ ? OpenVoiceProcessingAU() : OpenAUHAL();
311
312 if (!success)
313 return false;
314
315 // The hardware latency is fixed and will not change during the call.
316 hardware_latency_ = AudioManagerMac::GetHardwareLatency(
317 audio_unit_, input_device_id_, kAudioDevicePropertyScopeInput,
318 format_.mSampleRate);
319
320 // The master channel is 0, Left and right are channels 1 and 2.
321 // And the master channel is not counted in |number_of_channels_in_frame_|.
322 number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
323
324 return true;
325 }
326
OpenAUHAL()327 bool AUAudioInputStream::OpenAUHAL() {
328 // Start by obtaining an AudioOuputUnit using an AUHAL component description.
329
330 // Description for the Audio Unit we want to use (AUHAL in this case).
331 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device.
332 // The user specifies which audio device to track. The audio unit can do
333 // input from the device as well as output to the device. Bus 0 is used for
334 // the output side, bus 1 is used to get audio input from the device.
335 AudioComponentDescription desc = {kAudioUnitType_Output,
336 kAudioUnitSubType_HALOutput,
337 kAudioUnitManufacturer_Apple, 0, 0};
338
339 // Find a component that meets the description in |desc|.
340 AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
341 DCHECK(comp);
342 if (!comp) {
343 HandleError(kAudioUnitErr_NoConnection);
344 return false;
345 }
346
347 // Get access to the service provided by the specified Audio Unit.
348 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_);
349 if (result) {
350 HandleError(result);
351 return false;
352 }
353
354 // Initialize the AUHAL before making any changes or using it. The audio
355 // unit will be initialized once more as last operation in this method but
356 // that is intentional. This approach is based on a comment in the
357 // CAPlayThrough example from Apple, which states that "AUHAL needs to be
358 // initialized *before* anything is done to it".
359 // TODO(henrika): remove this extra call if we are unable to see any
360 // positive effects of it in our UMA stats.
361 result = AudioUnitInitialize(audio_unit_);
362 if (result != noErr) {
363 HandleError(result);
364 return false;
365 }
366
367 // Enable IO on the input scope of the Audio Unit.
368 // Note that, these changes must be done *before* setting the AUHAL's
369 // current device.
370
371 // After creating the AUHAL object, we must enable IO on the input scope
372 // of the Audio Unit to obtain the device input. Input must be explicitly
373 // enabled with the kAudioOutputUnitProperty_EnableIO property on Element 1
374 // of the AUHAL. Because the AUHAL can be used for both input and output,
375 // we must also disable IO on the output scope.
376
377 // kAudioOutputUnitProperty_EnableIO is not a writable property of the
378 // voice processing unit (we'd get kAudioUnitErr_PropertyNotWritable returned
379 // back to us). IO is always enabled.
380
381 // Enable input on the AUHAL.
382 {
383 const UInt32 enableIO = 1;
384 result = AudioUnitSetProperty(
385 audio_unit_, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
386 AUElement::INPUT, &enableIO, sizeof(enableIO));
387 if (result != noErr) {
388 HandleError(result);
389 return false;
390 }
391 }
392
393 // Disable output on the AUHAL.
394 {
395 const UInt32 disableIO = 0;
396 result = AudioUnitSetProperty(
397 audio_unit_, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
398 AUElement::OUTPUT, &disableIO, sizeof(disableIO));
399 if (result != noErr) {
400 HandleError(result);
401 return false;
402 }
403 }
404
405 // Next, set the audio device to be the Audio Unit's current device.
406 // Note that, devices can only be set to the AUHAL after enabling IO.
407 result =
408 AudioUnitSetProperty(audio_unit_, kAudioOutputUnitProperty_CurrentDevice,
409 kAudioUnitScope_Global, AUElement::OUTPUT,
410 &input_device_id_, sizeof(input_device_id_));
411
412 if (result != noErr) {
413 HandleError(result);
414 return false;
415 }
416
417 // Register the input procedure for the AUHAL. This procedure will be called
418 // when the AUHAL has received new data from the input device.
419 AURenderCallbackStruct callback;
420 callback.inputProc = &DataIsAvailable;
421 callback.inputProcRefCon = this;
422 result = AudioUnitSetProperty(
423 audio_unit_, kAudioOutputUnitProperty_SetInputCallback,
424 kAudioUnitScope_Global, AUElement::OUTPUT, &callback, sizeof(callback));
425
426 if (result != noErr) {
427 HandleError(result);
428 return false;
429 }
430
431 // Get the stream format for the selected input device and ensure that the
432 // sample rate of the selected input device matches the desired (given at
433 // construction) sample rate. We should not rely on sample rate conversion
434 // in the AUHAL, only *simple* conversions, e.g., 32-bit float to 16-bit
435 // signed integer format.
436 AudioStreamBasicDescription input_device_format = {0};
437 GetInputDeviceStreamFormat(audio_unit_, &input_device_format);
438 if (input_device_format.mSampleRate != format_.mSampleRate) {
439 LOG(ERROR) << "Input device's sample rate does not match the client's "
440 "sample rate; input_device_format="
441 << input_device_format;
442 result = kAudioUnitErr_FormatNotSupported;
443 HandleError(result);
444 return false;
445 }
446
447 // Modify the IO buffer size if not already set correctly for the selected
448 // device. The status of other active audio input and output streams is
449 // involved in the final setting.
450 // TODO(henrika): we could make io_buffer_frame_size a member and add it to
451 // the UMA stats tied to the Media.Audio.InputStartupSuccessMac record.
452 size_t io_buffer_frame_size = 0;
453 if (!manager_->MaybeChangeBufferSize(
454 input_device_id_, audio_unit_, 1, input_params_.frames_per_buffer(),
455 &buffer_size_was_changed_, &io_buffer_frame_size)) {
456 result = kAudioUnitErr_FormatNotSupported;
457 HandleError(result);
458 return false;
459 }
460
461 // Store current I/O buffer frame size for UMA stats stored in combination
462 // with failing input callbacks.
463 DCHECK(!io_buffer_frame_size_);
464 io_buffer_frame_size_ = io_buffer_frame_size;
465
466 // If the requested number of frames is out of range, the closest valid buffer
467 // size will be set instead. Check the current setting and log a warning for a
468 // non perfect match. Any such mismatch will be compensated for in
469 // OnDataIsAvailable().
470 UInt32 buffer_frame_size = 0;
471 UInt32 property_size = sizeof(buffer_frame_size);
472 result = AudioUnitGetProperty(
473 audio_unit_, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global,
474 AUElement::OUTPUT, &buffer_frame_size, &property_size);
475 LOG_IF(WARNING, buffer_frame_size !=
476 static_cast<UInt32>(input_params_.frames_per_buffer()))
477 << "AUHAL is using best match of IO buffer size: " << buffer_frame_size;
478
479 // Channel mapping should be supported but add a warning just in case.
480 // TODO(henrika): perhaps add to UMA stat to track if this can happen.
481 DLOG_IF(WARNING,
482 input_device_format.mChannelsPerFrame != format_.mChannelsPerFrame)
483 << "AUHAL's audio converter must do channel conversion";
484
485 // Set up the the desired (output) format.
486 // For obtaining input from a device, the device format is always expressed
487 // on the output scope of the AUHAL's Element 1.
488 result = AudioUnitSetProperty(audio_unit_, kAudioUnitProperty_StreamFormat,
489 kAudioUnitScope_Output, 1, &format_,
490 sizeof(format_));
491 if (result != noErr) {
492 HandleError(result);
493 return false;
494 }
495
496 // Finally, initialize the audio unit and ensure that it is ready to render.
497 // Allocates memory according to the maximum number of audio frames
498 // it can produce in response to a single render call.
499 result = AudioUnitInitialize(audio_unit_);
500 if (result != noErr) {
501 HandleError(result);
502 return false;
503 }
504
505 return true;
506 }
507
OpenVoiceProcessingAU()508 bool AUAudioInputStream::OpenVoiceProcessingAU() {
509 // Start by obtaining an AudioOuputUnit using an AUHAL component description.
510
511 // Description for the Audio Unit we want to use (AUHAL in this case).
512 // The kAudioUnitSubType_HALOutput audio unit interfaces to any audio device.
513 // The user specifies which audio device to track. The audio unit can do
514 // input from the device as well as output to the device. Bus 0 is used for
515 // the output side, bus 1 is used to get audio input from the device.
516 AudioComponentDescription desc = {kAudioUnitType_Output,
517 kAudioUnitSubType_VoiceProcessingIO,
518 kAudioUnitManufacturer_Apple, 0, 0};
519
520 // Find a component that meets the description in |desc|.
521 AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
522 DCHECK(comp);
523 if (!comp) {
524 HandleError(kAudioUnitErr_NoConnection);
525 return false;
526 }
527
528 // Get access to the service provided by the specified Audio Unit.
529 OSStatus result = AudioComponentInstanceNew(comp, &audio_unit_);
530 if (result) {
531 HandleError(result);
532 return false;
533 }
534
535 // Next, set the audio device to be the Audio Unit's input device.
536 result =
537 AudioUnitSetProperty(audio_unit_, kAudioOutputUnitProperty_CurrentDevice,
538 kAudioUnitScope_Global, AUElement::INPUT,
539 &input_device_id_, sizeof(input_device_id_));
540
541 if (result != noErr) {
542 HandleError(result);
543 return false;
544 }
545
546 // Followed by the audio device to be the Audio Unit's output device.
547 result = AudioUnitSetProperty(
548 audio_unit_, kAudioOutputUnitProperty_CurrentDevice,
549 kAudioUnitScope_Global, AUElement::OUTPUT, &output_device_id_for_aec_,
550 sizeof(output_device_id_for_aec_));
551
552 if (result != noErr) {
553 HandleError(result);
554 return false;
555 }
556
557 // Register the input procedure for the AUHAL. This procedure will be called
558 // when the AUHAL has received new data from the input device.
559 AURenderCallbackStruct callback;
560 callback.inputProc = &DataIsAvailable;
561 callback.inputProcRefCon = this;
562
563 result = AudioUnitSetProperty(
564 audio_unit_, kAudioOutputUnitProperty_SetInputCallback,
565 kAudioUnitScope_Global, AUElement::INPUT, &callback, sizeof(callback));
566 if (result != noErr) {
567 HandleError(result);
568 return false;
569 }
570
571 callback.inputProc = OnGetPlayoutData;
572 callback.inputProcRefCon = this;
573 result = AudioUnitSetProperty(
574 audio_unit_, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
575 AUElement::OUTPUT, &callback, sizeof(callback));
576 if (result != noErr) {
577 HandleError(result);
578 return false;
579 }
580
581 // Get the stream format for the selected input device and ensure that the
582 // sample rate of the selected input device matches the desired (given at
583 // construction) sample rate. We should not rely on sample rate conversion
584 // in the AUHAL, only *simple* conversions, e.g., 32-bit float to 16-bit
585 // signed integer format.
586 AudioStreamBasicDescription input_device_format = {0};
587 GetInputDeviceStreamFormat(audio_unit_, &input_device_format);
588 if (input_device_format.mSampleRate != format_.mSampleRate) {
589 LOG(ERROR)
590 << "Input device's sample rate does not match the client's sample rate";
591 result = kAudioUnitErr_FormatNotSupported;
592 HandleError(result);
593 return false;
594 }
595
596 // Modify the IO buffer size if not already set correctly for the selected
597 // device. The status of other active audio input and output streams is
598 // involved in the final setting.
599 // TODO(henrika): we could make io_buffer_frame_size a member and add it to
600 // the UMA stats tied to the Media.Audio.InputStartupSuccessMac record.
601 size_t io_buffer_frame_size = 0;
602 if (!manager_->MaybeChangeBufferSize(
603 input_device_id_, audio_unit_, 1, input_params_.frames_per_buffer(),
604 &buffer_size_was_changed_, &io_buffer_frame_size)) {
605 result = kAudioUnitErr_FormatNotSupported;
606 HandleError(result);
607 return false;
608 }
609
610 // Store current I/O buffer frame size for UMA stats stored in combination
611 // with failing input callbacks.
612 DCHECK(!io_buffer_frame_size_);
613 io_buffer_frame_size_ = io_buffer_frame_size;
614
615 // If the requested number of frames is out of range, the closest valid buffer
616 // size will be set instead. Check the current setting and log a warning for a
617 // non perfect match. Any such mismatch will be compensated for in
618 // OnDataIsAvailable().
619 UInt32 buffer_frame_size = 0;
620 UInt32 property_size = sizeof(buffer_frame_size);
621 result = AudioUnitGetProperty(
622 audio_unit_, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global,
623 AUElement::OUTPUT, &buffer_frame_size, &property_size);
624 LOG_IF(WARNING, buffer_frame_size !=
625 static_cast<UInt32>(input_params_.frames_per_buffer()))
626 << "AUHAL is using best match of IO buffer size: " << buffer_frame_size;
627
628 // The built-in device claims to be stereo. VPAU claims 5 channels (for me)
629 // but refuses to work in stereo. Just accept stero for now, use mono
630 // internally and upmix.
631 AudioStreamBasicDescription mono_format = format_;
632 if (format_.mChannelsPerFrame == 2) {
633 mono_format.mChannelsPerFrame = 1;
634 mono_format.mBytesPerPacket = mono_format.mBitsPerChannel / 8;
635 mono_format.mBytesPerFrame = mono_format.mBytesPerPacket;
636 }
637
638 // Set up the the desired (output) format.
639 // For obtaining input from a device, the device format is always expressed
640 // on the output scope of the AUHAL's Element 1.
641 result = AudioUnitSetProperty(audio_unit_, kAudioUnitProperty_StreamFormat,
642 kAudioUnitScope_Output, AUElement::INPUT,
643 &mono_format, sizeof(mono_format));
644 if (result != noErr) {
645 HandleError(result);
646 return false;
647 }
648
649 result = AudioUnitSetProperty(audio_unit_, kAudioUnitProperty_StreamFormat,
650 kAudioUnitScope_Input, AUElement::OUTPUT,
651 &mono_format, sizeof(mono_format));
652 if (result != noErr) {
653 HandleError(result);
654 return false;
655 }
656
657 // Finally, initialize the audio unit and ensure that it is ready to render.
658 // Allocates memory according to the maximum number of audio frames
659 // it can produce in response to a single render call.
660 result = AudioUnitInitialize(audio_unit_);
661 if (result != noErr) {
662 HandleError(result);
663 return false;
664 }
665
666 UndoDucking(output_device_id_for_aec_);
667
668 return true;
669 }
670
Start(AudioInputCallback * callback)671 void AUAudioInputStream::Start(AudioInputCallback* callback) {
672 DCHECK(thread_checker_.CalledOnValidThread());
673 DVLOG(1) << "Start";
674 DCHECK(callback);
675 DCHECK(!sink_);
676 DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully";
677 if (IsRunning())
678 return;
679
680 // Check if we should defer Start() for http://crbug.com/160920.
681 if (manager_->ShouldDeferStreamStart()) {
682 LOG(WARNING) << "Start of input audio is deferred";
683 // Use a cancellable closure so that if Stop() is called before Start()
684 // actually runs, we can cancel the pending start.
685 deferred_start_cb_.Reset(base::BindOnce(&AUAudioInputStream::Start,
686 base::Unretained(this), callback));
687 manager_->GetTaskRunner()->PostDelayedTask(
688 FROM_HERE, deferred_start_cb_.callback(),
689 base::TimeDelta::FromSeconds(
690 AudioManagerMac::kStartDelayInSecsForPowerEvents));
691 return;
692 }
693
694 sink_ = callback;
695 last_success_time_ = base::TimeTicks::Now();
696 audio_unit_render_has_worked_ = false;
697
698 // Don't disable built-in noise suppression when using VPAU.
699 if (!use_voice_processing_ &&
700 !(input_params_.effects() & AudioParameters::NOISE_SUPPRESSION) &&
701 manager_->DeviceSupportsAmbientNoiseReduction(input_device_id_)) {
702 noise_reduction_suppressed_ =
703 manager_->SuppressNoiseReduction(input_device_id_);
704 }
705 StartAgc();
706 OSStatus result = AudioOutputUnitStart(audio_unit_);
707 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
708 << "Failed to start acquiring data";
709 if (result != noErr) {
710 Stop();
711 return;
712 }
713 DCHECK(IsRunning()) << "Audio unit started OK but is not yet running";
714
715 // For UMA stat purposes, start a one-shot timer which detects when input
716 // callbacks starts indicating if input audio recording starts as intended.
717 // CheckInputStartupSuccess() will check if |input_callback_is_active_| is
718 // true when the timer expires.
719 input_callback_timer_.reset(new base::OneShotTimer());
720 input_callback_timer_->Start(
721 FROM_HERE,
722 base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this,
723 &AUAudioInputStream::CheckInputStartupSuccess);
724 DCHECK(input_callback_timer_->IsRunning());
725 }
726
Stop()727 void AUAudioInputStream::Stop() {
728 DCHECK(thread_checker_.CalledOnValidThread());
729 deferred_start_cb_.Cancel();
730 DVLOG(1) << "Stop";
731 StopAgc();
732 if (noise_reduction_suppressed_) {
733 manager_->UnsuppressNoiseReduction(input_device_id_);
734 noise_reduction_suppressed_ = false;
735 }
736 if (input_callback_timer_ != nullptr) {
737 input_callback_timer_->Stop();
738 input_callback_timer_.reset();
739 }
740
741 if (audio_unit_ != nullptr) {
742 // Stop the I/O audio unit.
743 OSStatus result = AudioOutputUnitStop(audio_unit_);
744 DCHECK_EQ(result, noErr);
745 // Add a DCHECK here just in case. AFAIK, the call to AudioOutputUnitStop()
746 // seems to set this state synchronously, hence it should always report
747 // false after a successful call.
748 DCHECK(!IsRunning()) << "Audio unit is stopped but still running";
749
750 // Reset the audio unit’s render state. This function clears memory.
751 // It does not allocate or free memory resources.
752 result = AudioUnitReset(audio_unit_, kAudioUnitScope_Global, 0);
753 DCHECK_EQ(result, noErr);
754 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
755 << "Failed to stop acquiring data";
756 }
757
758 SetInputCallbackIsActive(false);
759 ReportAndResetStats();
760 sink_ = nullptr;
761 fifo_.Clear();
762 io_buffer_frame_size_ = 0;
763 got_input_callback_ = false;
764 }
765
Close()766 void AUAudioInputStream::Close() {
767 DCHECK(thread_checker_.CalledOnValidThread());
768 DVLOG(1) << "Close";
769
770 // It is valid to call Close() before calling open or Start().
771 // It is also valid to call Close() after Start() has been called.
772 if (IsRunning()) {
773 Stop();
774 }
775
776 // Uninitialize and dispose the audio unit.
777 CloseAudioUnit();
778
779 // Inform the audio manager that we have been closed. This will cause our
780 // destruction.
781 manager_->ReleaseInputStream(this);
782 }
783
GetMaxVolume()784 double AUAudioInputStream::GetMaxVolume() {
785 // Verify that we have a valid device.
786 if (input_device_id_ == kAudioObjectUnknown) {
787 NOTREACHED() << "Device ID is unknown";
788 return 0.0;
789 }
790
791 // Query if any of the master, left or right channels has volume control.
792 for (int i = 0; i <= number_of_channels_in_frame_; ++i) {
793 // If the volume is settable, the valid volume range is [0.0, 1.0].
794 if (IsVolumeSettableOnChannel(i))
795 return 1.0;
796 }
797
798 // Volume control is not available for the audio stream.
799 return 0.0;
800 }
801
SetVolume(double volume)802 void AUAudioInputStream::SetVolume(double volume) {
803 DVLOG(1) << "SetVolume(volume=" << volume << ")";
804 DCHECK_GE(volume, 0.0);
805 DCHECK_LE(volume, 1.0);
806
807 // Verify that we have a valid device.
808 if (input_device_id_ == kAudioObjectUnknown) {
809 NOTREACHED() << "Device ID is unknown";
810 return;
811 }
812
813 Float32 volume_float32 = static_cast<Float32>(volume);
814 AudioObjectPropertyAddress property_address = {
815 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput,
816 kAudioObjectPropertyElementMaster};
817
818 // Try to set the volume for master volume channel.
819 if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
820 OSStatus result = AudioObjectSetPropertyData(
821 input_device_id_, &property_address, 0, nullptr, sizeof(volume_float32),
822 &volume_float32);
823 if (result != noErr) {
824 DLOG(WARNING) << "Failed to set volume to " << volume_float32;
825 }
826 return;
827 }
828
829 // There is no master volume control, try to set volume for each channel.
830 int successful_channels = 0;
831 for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
832 property_address.mElement = static_cast<UInt32>(i);
833 if (IsVolumeSettableOnChannel(i)) {
834 OSStatus result = AudioObjectSetPropertyData(
835 input_device_id_, &property_address, 0, NULL, sizeof(volume_float32),
836 &volume_float32);
837 if (result == noErr)
838 ++successful_channels;
839 }
840 }
841
842 DLOG_IF(WARNING, successful_channels == 0)
843 << "Failed to set volume to " << volume_float32;
844
845 // Update the AGC volume level based on the last setting above. Note that,
846 // the volume-level resolution is not infinite and it is therefore not
847 // possible to assume that the volume provided as input parameter can be
848 // used directly. Instead, a new query to the audio hardware is required.
849 // This method does nothing if AGC is disabled.
850 UpdateAgcVolume();
851 }
852
GetVolume()853 double AUAudioInputStream::GetVolume() {
854 // Verify that we have a valid device.
855 if (input_device_id_ == kAudioObjectUnknown) {
856 NOTREACHED() << "Device ID is unknown";
857 return 0.0;
858 }
859
860 AudioObjectPropertyAddress property_address = {
861 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput,
862 kAudioObjectPropertyElementMaster};
863
864 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
865 // The device supports master volume control, get the volume from the
866 // master channel.
867 Float32 volume_float32 = 0.0;
868 UInt32 size = sizeof(volume_float32);
869 OSStatus result =
870 AudioObjectGetPropertyData(input_device_id_, &property_address, 0,
871 nullptr, &size, &volume_float32);
872 if (result == noErr)
873 return static_cast<double>(volume_float32);
874 } else {
875 // There is no master volume control, try to get the average volume of
876 // all the channels.
877 Float32 volume_float32 = 0.0;
878 int successful_channels = 0;
879 for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
880 property_address.mElement = static_cast<UInt32>(i);
881 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
882 Float32 channel_volume = 0;
883 UInt32 size = sizeof(channel_volume);
884 OSStatus result =
885 AudioObjectGetPropertyData(input_device_id_, &property_address, 0,
886 nullptr, &size, &channel_volume);
887 if (result == noErr) {
888 volume_float32 += channel_volume;
889 ++successful_channels;
890 }
891 }
892 }
893
894 // Get the average volume of the channels.
895 if (successful_channels != 0)
896 return static_cast<double>(volume_float32 / successful_channels);
897 }
898
899 DLOG(WARNING) << "Failed to get volume";
900 return 0.0;
901 }
902
IsMuted()903 bool AUAudioInputStream::IsMuted() {
904 // Verify that we have a valid device.
905 DCHECK_NE(input_device_id_, kAudioObjectUnknown) << "Device ID is unknown";
906
907 AudioObjectPropertyAddress property_address = {
908 kAudioDevicePropertyMute, kAudioDevicePropertyScopeInput,
909 kAudioObjectPropertyElementMaster};
910
911 if (!AudioObjectHasProperty(input_device_id_, &property_address)) {
912 DLOG(ERROR) << "Device does not support checking master mute state";
913 return false;
914 }
915
916 UInt32 muted = 0;
917 UInt32 size = sizeof(muted);
918 OSStatus result = AudioObjectGetPropertyData(
919 input_device_id_, &property_address, 0, nullptr, &size, &muted);
920 DLOG_IF(WARNING, result != noErr) << "Failed to get mute state";
921 return result == noErr && muted != 0;
922 }
923
SetOutputDeviceForAec(const std::string & output_device_id)924 void AUAudioInputStream::SetOutputDeviceForAec(
925 const std::string& output_device_id) {
926 if (!use_voice_processing_)
927 return;
928
929 AudioDeviceID audio_device_id =
930 AudioManagerMac::GetAudioDeviceIdByUId(false, output_device_id);
931 if (audio_device_id == output_device_id_for_aec_)
932 return;
933
934 if (audio_device_id == kAudioObjectUnknown) {
935 log_callback_.Run(
936 base::StringPrintf("AU in: Unable to resolve output device id '%s'",
937 output_device_id.c_str()));
938 return;
939 }
940
941 // If the selected device is an aggregate device, try to use the first output
942 // device of the aggregate device instead.
943 if (core_audio_mac::GetDeviceTransportType(audio_device_id) ==
944 kAudioDeviceTransportTypeAggregate) {
945 const AudioDeviceID output_subdevice_id =
946 FindFirstOutputSubdevice(audio_device_id);
947
948 if (output_subdevice_id == kAudioObjectUnknown) {
949 log_callback_.Run(base::StringPrintf(
950 "AU in: Unable to find an output subdevice in aggregate device '%s'",
951 output_device_id.c_str()));
952 return;
953 }
954 audio_device_id = output_subdevice_id;
955 }
956
957 if (audio_device_id != output_device_id_for_aec_) {
958 output_device_id_for_aec_ = audio_device_id;
959 log_callback_.Run(base::StringPrintf(
960 "AU in: Output device for AEC changed to '%s' (%d)",
961 output_device_id.c_str(), output_device_id_for_aec_));
962 // Only restart the stream if it has previously been started.
963 if (audio_unit_)
964 ReinitializeVoiceProcessingAudioUnit();
965 }
966 }
967
ReinitializeVoiceProcessingAudioUnit()968 void AUAudioInputStream::ReinitializeVoiceProcessingAudioUnit() {
969 DCHECK(use_voice_processing_);
970 DCHECK(audio_unit_);
971
972 const bool was_running = IsRunning();
973 OSStatus result = noErr;
974
975 if (was_running) {
976 result = AudioOutputUnitStop(audio_unit_);
977 DCHECK_EQ(result, noErr);
978 }
979
980 CloseAudioUnit();
981
982 // Reset things to a state similar to before the audio unit was opened.
983 // Most of these will be no-ops if the audio unit was opened but not started.
984 SetInputCallbackIsActive(false);
985 ReportAndResetStats();
986 io_buffer_frame_size_ = 0;
987 got_input_callback_ = false;
988
989 OpenVoiceProcessingAU();
990
991 if (was_running) {
992 result = AudioOutputUnitStart(audio_unit_);
993 if (result != noErr) {
994 OSSTATUS_DLOG(ERROR, result) << "Failed to start acquiring data";
995 Stop();
996 return;
997 }
998 }
999
1000 log_callback_.Run(base::StringPrintf(
1001 "AU in: Successfully reinitialized AEC for output device id=%d.",
1002 output_device_id_for_aec_));
1003 }
1004
1005 // static
DataIsAvailable(void * context,AudioUnitRenderActionFlags * flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)1006 OSStatus AUAudioInputStream::DataIsAvailable(void* context,
1007 AudioUnitRenderActionFlags* flags,
1008 const AudioTimeStamp* time_stamp,
1009 UInt32 bus_number,
1010 UInt32 number_of_frames,
1011 AudioBufferList* io_data) {
1012 DCHECK(context);
1013 // Recorded audio is always on the input bus (=1).
1014 DCHECK_EQ(bus_number, 1u);
1015 // No data buffer should be allocated at this stage.
1016 DCHECK(!io_data);
1017 AUAudioInputStream* self = reinterpret_cast<AUAudioInputStream*>(context);
1018 // Propagate render action flags, time stamp, bus number and number
1019 // of frames requested to the AudioUnitRender() call where the actual data
1020 // is received from the input device via the output scope of the audio unit.
1021 return self->OnDataIsAvailable(flags, time_stamp, bus_number,
1022 number_of_frames);
1023 }
1024
OnDataIsAvailable(AudioUnitRenderActionFlags * flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames)1025 OSStatus AUAudioInputStream::OnDataIsAvailable(
1026 AudioUnitRenderActionFlags* flags,
1027 const AudioTimeStamp* time_stamp,
1028 UInt32 bus_number,
1029 UInt32 number_of_frames) {
1030 TRACE_EVENT0("audio", "AUAudioInputStream::OnDataIsAvailable");
1031
1032 // Indicate that input callbacks have started.
1033 if (!got_input_callback_) {
1034 got_input_callback_ = true;
1035 SetInputCallbackIsActive(true);
1036 }
1037
1038 // Update the |mDataByteSize| value in the audio_buffer_list() since
1039 // |number_of_frames| can be changed on the fly.
1040 // |mDataByteSize| needs to be exactly mapping to |number_of_frames|,
1041 // otherwise it will put CoreAudio into bad state and results in
1042 // AudioUnitRender() returning -50 for the new created stream.
1043 // We have also seen kAudioUnitErr_TooManyFramesToProcess (-10874) and
1044 // kAudioUnitErr_CannotDoInCurrentContext (-10863) as error codes.
1045 // See crbug/428706 for details.
1046 UInt32 new_size = number_of_frames * format_.mBytesPerFrame;
1047 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
1048 bool new_buffer_size_detected = false;
1049 if (new_size != audio_buffer->mDataByteSize) {
1050 new_buffer_size_detected = true;
1051 DVLOG(1) << "New size of number_of_frames detected: " << number_of_frames;
1052 io_buffer_frame_size_ = static_cast<size_t>(number_of_frames);
1053 if (new_size > audio_buffer->mDataByteSize) {
1054 // This can happen if the device is unplugged during recording. We
1055 // allocate enough memory here to avoid depending on how CoreAudio
1056 // handles it.
1057 // See See http://www.crbug.com/434681 for one example when we can enter
1058 // this scope.
1059 audio_data_buffer_.reset(new uint8_t[new_size]);
1060 audio_buffer->mData = audio_data_buffer_.get();
1061 }
1062
1063 // Update the |mDataByteSize| to match |number_of_frames|.
1064 audio_buffer->mDataByteSize = new_size;
1065 }
1066
1067 // Obtain the recorded audio samples by initiating a rendering cycle.
1068 // Since it happens on the input bus, the |&audio_buffer_list_| parameter is
1069 // a reference to the preallocated audio buffer list that the audio unit
1070 // renders into.
1071 OSStatus result;
1072 if (use_voice_processing_ && format_.mChannelsPerFrame != 1) {
1073 // Use the first part of the output buffer for mono data...
1074 AudioBufferList mono_buffer_list;
1075 mono_buffer_list.mNumberBuffers = 1;
1076 AudioBuffer* mono_buffer = mono_buffer_list.mBuffers;
1077 mono_buffer->mNumberChannels = 1;
1078 mono_buffer->mDataByteSize =
1079 audio_buffer->mDataByteSize / audio_buffer->mNumberChannels;
1080 mono_buffer->mData = audio_buffer->mData;
1081
1082 TRACE_EVENT_BEGIN0("audio", "AudioUnitRender");
1083 result = AudioUnitRender(audio_unit_, flags, time_stamp, bus_number,
1084 number_of_frames, &mono_buffer_list);
1085 TRACE_EVENT_END0("audio", "AudioUnitRender");
1086 // ... then upmix it by copying it out to two channels.
1087 UpmixMonoToStereoInPlace(audio_buffer, format_.mBitsPerChannel / 8);
1088 } else {
1089 TRACE_EVENT_BEGIN0("audio", "AudioUnitRender");
1090 result = AudioUnitRender(audio_unit_, flags, time_stamp, bus_number,
1091 number_of_frames, &audio_buffer_list_);
1092 TRACE_EVENT_END0("audio", "AudioUnitRender");
1093 }
1094
1095 if (result == noErr) {
1096 audio_unit_render_has_worked_ = true;
1097 }
1098 if (result) {
1099 TRACE_EVENT_INSTANT0("audio", "AudioUnitRender error",
1100 TRACE_EVENT_SCOPE_THREAD);
1101 // Only upload UMA histograms for the case when AGC is enabled. The reason
1102 // is that we want to compare these stats with others in this class and
1103 // they are only stored for "AGC streams", e.g. WebRTC audio streams.
1104 const bool add_uma_histogram = GetAutomaticGainControl();
1105 if (add_uma_histogram) {
1106 base::UmaHistogramSparse("Media.AudioInputCbErrorMac", result);
1107 }
1108 OSSTATUS_LOG(ERROR, result) << "AudioUnitRender() failed ";
1109 if (result == kAudioUnitErr_TooManyFramesToProcess ||
1110 result == kAudioUnitErr_CannotDoInCurrentContext) {
1111 DCHECK(!last_success_time_.is_null());
1112 // We delay stopping the stream for kAudioUnitErr_TooManyFramesToProcess
1113 // since it has been observed that some USB headsets can cause this error
1114 // but only for a few initial frames at startup and then then the stream
1115 // returns to a stable state again. See b/19524368 for details.
1116 // Instead, we measure time since last valid audio frame and call
1117 // HandleError() only if a too long error sequence is detected. We do
1118 // this to avoid ending up in a non recoverable bad core audio state.
1119 // Also including kAudioUnitErr_CannotDoInCurrentContext since long
1120 // sequences can be produced in combination with e.g. sample-rate changes
1121 // for input devices.
1122 base::TimeDelta time_since_last_success =
1123 base::TimeTicks::Now() - last_success_time_;
1124 if ((time_since_last_success >
1125 base::TimeDelta::FromSeconds(kMaxErrorTimeoutInSeconds))) {
1126 const char* err = (result == kAudioUnitErr_TooManyFramesToProcess)
1127 ? "kAudioUnitErr_TooManyFramesToProcess"
1128 : "kAudioUnitErr_CannotDoInCurrentContext";
1129 LOG(ERROR) << "Too long sequence of " << err << " errors!";
1130 HandleError(result);
1131 }
1132
1133 // Add some extra UMA stat to track down if we see this particular error
1134 // in combination with a previous change of buffer size "on the fly".
1135 if (result == kAudioUnitErr_CannotDoInCurrentContext &&
1136 add_uma_histogram) {
1137 UMA_HISTOGRAM_BOOLEAN("Media.Audio.RenderFailsWhenBufferSizeChangesMac",
1138 new_buffer_size_detected);
1139 UMA_HISTOGRAM_BOOLEAN("Media.Audio.AudioUnitRenderHasWorkedMac",
1140 audio_unit_render_has_worked_);
1141 }
1142 } else {
1143 // We have also seen kAudioUnitErr_NoConnection in some cases. Bailing
1144 // out for this error for now.
1145 HandleError(result);
1146 }
1147 return result;
1148 }
1149 // Update time of successful call to AudioUnitRender().
1150 last_success_time_ = base::TimeTicks::Now();
1151
1152 // Deliver recorded data to the consumer as a callback.
1153 return Provide(number_of_frames, &audio_buffer_list_, time_stamp);
1154 }
1155
Provide(UInt32 number_of_frames,AudioBufferList * io_data,const AudioTimeStamp * time_stamp)1156 OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
1157 AudioBufferList* io_data,
1158 const AudioTimeStamp* time_stamp) {
1159 TRACE_EVENT1("audio", "AUAudioInputStream::Provide", "number_of_frames",
1160 number_of_frames);
1161 UpdateCaptureTimestamp(time_stamp);
1162 last_number_of_frames_ = number_of_frames;
1163
1164 // TODO(grunell): We'll only care about the first buffer size change, any
1165 // further changes will be ignored. This is in line with output side stats.
1166 // It would be nice to have all changes reflected in UMA stats.
1167 if (number_of_frames !=
1168 static_cast<UInt32>(input_params_.frames_per_buffer()) &&
1169 number_of_frames_provided_ == 0)
1170 number_of_frames_provided_ = number_of_frames;
1171
1172 base::TimeTicks capture_time = GetCaptureTime(time_stamp);
1173
1174 // The AGC volume level is updated once every second on a separate thread.
1175 // Note that, |volume| is also updated each time SetVolume() is called
1176 // through IPC by the render-side AGC.
1177 double normalized_volume = 0.0;
1178 GetAgcVolume(&normalized_volume);
1179
1180 AudioBuffer& buffer = io_data->mBuffers[0];
1181 uint8_t* audio_data = reinterpret_cast<uint8_t*>(buffer.mData);
1182 DCHECK(audio_data);
1183 if (!audio_data)
1184 return kAudioUnitErr_InvalidElement;
1185
1186 // Dynamically increase capacity of the FIFO to handle larger buffers from
1187 // CoreAudio. This can happen in combination with Apple Thunderbolt Displays
1188 // when the Display Audio is used as capture source and the cable is first
1189 // remove and then inserted again.
1190 // See http://www.crbug.com/434681 for details.
1191 if (static_cast<int>(number_of_frames) > fifo_.GetUnfilledFrames()) {
1192 // Derive required increase in number of FIFO blocks. The increase is
1193 // typically one block.
1194 const int blocks =
1195 static_cast<int>((number_of_frames - fifo_.GetUnfilledFrames()) /
1196 input_params_.frames_per_buffer()) +
1197 1;
1198 DLOG(WARNING) << "Increasing FIFO capacity by " << blocks << " blocks";
1199 TRACE_EVENT_INSTANT1("audio", "Increasing FIFO capacity",
1200 TRACE_EVENT_SCOPE_THREAD, "increased by", blocks);
1201 fifo_.IncreaseCapacity(blocks);
1202 }
1203
1204 // Compensate the capture time for the FIFO before pushing an new frames.
1205 capture_time -= AudioTimestampHelper::FramesToTime(fifo_.GetAvailableFrames(),
1206 format_.mSampleRate);
1207
1208 // Copy captured (and interleaved) data into FIFO.
1209 fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8);
1210
1211 // Consume and deliver the data when the FIFO has a block of available data.
1212 while (fifo_.available_blocks()) {
1213 const AudioBus* audio_bus = fifo_.Consume();
1214 DCHECK_EQ(audio_bus->frames(),
1215 static_cast<int>(input_params_.frames_per_buffer()));
1216
1217 sink_->OnData(audio_bus, capture_time, normalized_volume);
1218
1219 // Move the capture time forward for each vended block.
1220 capture_time += AudioTimestampHelper::FramesToTime(audio_bus->frames(),
1221 format_.mSampleRate);
1222 }
1223
1224 return noErr;
1225 }
1226
HardwareSampleRate()1227 int AUAudioInputStream::HardwareSampleRate() {
1228 // Determine the default input device's sample-rate.
1229 AudioDeviceID device_id = kAudioObjectUnknown;
1230 UInt32 info_size = sizeof(device_id);
1231
1232 AudioObjectPropertyAddress default_input_device_address = {
1233 kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
1234 kAudioObjectPropertyElementMaster};
1235 OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
1236 &default_input_device_address, 0,
1237 0, &info_size, &device_id);
1238 if (result != noErr)
1239 return 0.0;
1240
1241 Float64 nominal_sample_rate;
1242 info_size = sizeof(nominal_sample_rate);
1243
1244 AudioObjectPropertyAddress nominal_sample_rate_address = {
1245 kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal,
1246 kAudioObjectPropertyElementMaster};
1247 result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address,
1248 0, 0, &info_size, &nominal_sample_rate);
1249 if (result != noErr)
1250 return 0.0;
1251
1252 return static_cast<int>(nominal_sample_rate);
1253 }
1254
GetCaptureTime(const AudioTimeStamp * input_time_stamp)1255 base::TimeTicks AUAudioInputStream::GetCaptureTime(
1256 const AudioTimeStamp* input_time_stamp) {
1257 // Total latency is composed by the dynamic latency and the fixed
1258 // hardware latency.
1259 // https://lists.apple.com/archives/coreaudio-api/2017/Jul/msg00035.html
1260 return (input_time_stamp->mFlags & kAudioTimeStampHostTimeValid
1261 ? base::TimeTicks::FromMachAbsoluteTime(
1262 input_time_stamp->mHostTime)
1263 : base::TimeTicks::Now()) -
1264 hardware_latency_;
1265 }
1266
GetNumberOfChannelsFromStream()1267 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
1268 // Get the stream format, to be able to read the number of channels.
1269 AudioObjectPropertyAddress property_address = {
1270 kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput,
1271 kAudioObjectPropertyElementMaster};
1272 AudioStreamBasicDescription stream_format;
1273 UInt32 size = sizeof(stream_format);
1274 OSStatus result = AudioObjectGetPropertyData(
1275 input_device_id_, &property_address, 0, nullptr, &size, &stream_format);
1276 if (result != noErr) {
1277 DLOG(WARNING) << "Could not get stream format";
1278 return 0;
1279 }
1280
1281 return static_cast<int>(stream_format.mChannelsPerFrame);
1282 }
1283
IsRunning()1284 bool AUAudioInputStream::IsRunning() {
1285 DCHECK(thread_checker_.CalledOnValidThread());
1286 if (!audio_unit_)
1287 return false;
1288 UInt32 is_running = 0;
1289 UInt32 size = sizeof(is_running);
1290 OSStatus error =
1291 AudioUnitGetProperty(audio_unit_, kAudioOutputUnitProperty_IsRunning,
1292 kAudioUnitScope_Global, 0, &is_running, &size);
1293 OSSTATUS_DLOG_IF(ERROR, error != noErr, error)
1294 << "AudioUnitGetProperty(kAudioOutputUnitProperty_IsRunning) failed";
1295 DVLOG(1) << "IsRunning: " << is_running;
1296 return (error == noErr && is_running);
1297 }
1298
HandleError(OSStatus err)1299 void AUAudioInputStream::HandleError(OSStatus err) {
1300 // Log the latest OSStatus error message and also change the sign of the
1301 // error if no callbacks are active. I.e., the sign of the error message
1302 // carries one extra level of information.
1303 base::UmaHistogramSparse("Media.InputErrorMac",
1304 GetInputCallbackIsActive() ? err : (err * -1));
1305 NOTREACHED() << "error " << logging::DescriptionFromOSStatus(err) << " ("
1306 << err << ")";
1307 if (sink_)
1308 sink_->OnError();
1309 }
1310
IsVolumeSettableOnChannel(int channel)1311 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
1312 Boolean is_settable = false;
1313 AudioObjectPropertyAddress property_address = {
1314 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput,
1315 static_cast<UInt32>(channel)};
1316 OSStatus result = AudioObjectIsPropertySettable(
1317 input_device_id_, &property_address, &is_settable);
1318 return (result == noErr) ? is_settable : false;
1319 }
1320
SetInputCallbackIsActive(bool enabled)1321 void AUAudioInputStream::SetInputCallbackIsActive(bool enabled) {
1322 base::subtle::Release_Store(&input_callback_is_active_, enabled);
1323 }
1324
GetInputCallbackIsActive()1325 bool AUAudioInputStream::GetInputCallbackIsActive() {
1326 return (base::subtle::Acquire_Load(&input_callback_is_active_) != false);
1327 }
1328
CheckInputStartupSuccess()1329 void AUAudioInputStream::CheckInputStartupSuccess() {
1330 DCHECK(thread_checker_.CalledOnValidThread());
1331 DCHECK(IsRunning());
1332 // Only add UMA stat related to failing input audio for streams where
1333 // the AGC has been enabled, e.g. WebRTC audio input streams.
1334 if (GetAutomaticGainControl()) {
1335 // Check if we have called Start() and input callbacks have actually
1336 // started in time as they should. If that is not the case, we have a
1337 // problem and the stream is considered dead.
1338 const bool input_callback_is_active = GetInputCallbackIsActive();
1339 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartupSuccessMac",
1340 input_callback_is_active);
1341 DVLOG(1) << "input_callback_is_active: " << input_callback_is_active;
1342 if (!input_callback_is_active) {
1343 // Now when we know that startup has failed for some reason, add extra
1344 // UMA stats in an attempt to figure out the exact reason.
1345 AddHistogramsForFailedStartup();
1346 }
1347 }
1348 }
1349
CloseAudioUnit()1350 void AUAudioInputStream::CloseAudioUnit() {
1351 DCHECK(thread_checker_.CalledOnValidThread());
1352 DVLOG(1) << "CloseAudioUnit";
1353 if (!audio_unit_)
1354 return;
1355 OSStatus result = AudioUnitUninitialize(audio_unit_);
1356 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
1357 << "AudioUnitUninitialize() failed.";
1358 result = AudioComponentInstanceDispose(audio_unit_);
1359 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
1360 << "AudioComponentInstanceDispose() failed.";
1361 audio_unit_ = 0;
1362 }
1363
AddHistogramsForFailedStartup()1364 void AUAudioInputStream::AddHistogramsForFailedStartup() {
1365 DCHECK(thread_checker_.CalledOnValidThread());
1366 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac",
1367 buffer_size_was_changed_);
1368 // |input_params_.frames_per_buffer()| is set at construction and corresponds
1369 // to the requested (by the client) number of audio frames per I/O buffer
1370 // connected to the selected input device. Ideally, this size will be the same
1371 // as the native I/O buffer size given by |io_buffer_frame_size_|.
1372 base::UmaHistogramSparse("Media.Audio.RequestedInputBufferFrameSizeMac",
1373 input_params_.frames_per_buffer());
1374 DVLOG(1) << "number_of_frames_: " << input_params_.frames_per_buffer();
1375 // This value indicates the number of frames in the IO buffers connected to
1376 // the selected input device. It has been set by the audio manger in Open()
1377 // and can be the same as |input_params_.frames_per_buffer()|, which is the
1378 // desired buffer size. These two values might differ if other streams are
1379 // using the same device and any of these streams have asked for a smaller
1380 // buffer size.
1381 base::UmaHistogramSparse("Media.Audio.ActualInputBufferFrameSizeMac",
1382 io_buffer_frame_size_);
1383 DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_;
1384 // Add information about things like number of logical processors etc.
1385 AddSystemInfoToUMA();
1386 }
1387
UpdateCaptureTimestamp(const AudioTimeStamp * timestamp)1388 void AUAudioInputStream::UpdateCaptureTimestamp(
1389 const AudioTimeStamp* timestamp) {
1390 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0)
1391 return;
1392
1393 if (last_sample_time_) {
1394 DCHECK_NE(0U, last_number_of_frames_);
1395 UInt32 diff =
1396 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_);
1397 if (diff != last_number_of_frames_) {
1398 DCHECK_GT(diff, last_number_of_frames_);
1399 // We were given samples post what we expected. Update the glitch count
1400 // etc. and keep a record of the largest glitch.
1401 auto lost_frames = diff - last_number_of_frames_;
1402 total_lost_frames_ += lost_frames;
1403 if (lost_frames > largest_glitch_frames_)
1404 largest_glitch_frames_ = lost_frames;
1405 ++glitches_detected_;
1406 }
1407 }
1408
1409 // Store the last sample time for use next time we get called back.
1410 last_sample_time_ = timestamp->mSampleTime;
1411 }
1412
ReportAndResetStats()1413 void AUAudioInputStream::ReportAndResetStats() {
1414 if (last_sample_time_ == 0)
1415 return; // No stats gathered to report.
1416
1417 // A value of 0 indicates that we got the buffer size we asked for.
1418 UMA_HISTOGRAM_COUNTS_10000("Media.Audio.Capture.FramesProvided",
1419 number_of_frames_provided_);
1420 // Even if there aren't any glitches, we want to record it to get a feel for
1421 // how often we get no glitches vs the alternative.
1422 UMA_HISTOGRAM_COUNTS_1M("Media.Audio.Capture.Glitches", glitches_detected_);
1423
1424 auto lost_frames_ms = (total_lost_frames_ * 1000) / format_.mSampleRate;
1425 std::string log_message = base::StringPrintf(
1426 "AU in: Total glitches=%d. Total frames lost=%d (%.0lf ms).",
1427 glitches_detected_, total_lost_frames_, lost_frames_ms);
1428 log_callback_.Run(log_message);
1429
1430 if (glitches_detected_ != 0) {
1431 UMA_HISTOGRAM_LONG_TIMES("Media.Audio.Capture.LostFramesInMs",
1432 base::TimeDelta::FromMilliseconds(lost_frames_ms));
1433 auto largest_glitch_ms =
1434 (largest_glitch_frames_ * 1000) / format_.mSampleRate;
1435 UMA_HISTOGRAM_CUSTOM_TIMES(
1436 "Media.Audio.Capture.LargestGlitchMs",
1437 base::TimeDelta::FromMilliseconds(largest_glitch_ms),
1438 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
1439 50);
1440 DLOG(WARNING) << log_message;
1441 }
1442
1443 number_of_frames_provided_ = 0;
1444 glitches_detected_ = 0;
1445 last_sample_time_ = 0;
1446 last_number_of_frames_ = 0;
1447 total_lost_frames_ = 0;
1448 largest_glitch_frames_ = 0;
1449 }
1450
1451 // TODO(ossu): Ideally, we'd just use the mono stream directly. However, since
1452 // mono or stereo (may) depend on if we want to run the echo canceller, and
1453 // since we can't provide two sets of AudioParameters for a device, this is the
1454 // best we can do right now.
1455 //
1456 // The algorithm works by copying a sample at offset N to 2*N and 2*N + 1, e.g.:
1457 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
1458 // | a1 | a2 | a3 | b1 | b2 | b3 | c1 | c2 | c3 | -- | -- | -- | -- | -- | ...
1459 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
1460 // into
1461 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
1462 // | a1 | a2 | a3 | a1 | a2 | a3 | b1 | b2 | b3 | b1 | b2 | b3 | c1 | c2 | ...
1463 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
1464 //
1465 // To support various different sample sizes, this is done byte-by-byte. Only
1466 // the first half of the buffer will be used as input. It is expected to contain
1467 // mono audio. The second half is output only. Since the data is expanding, the
1468 // algorithm starts copying from the last sample. Otherwise it would overwrite
1469 // data not already copied.
UpmixMonoToStereoInPlace(AudioBuffer * audio_buffer,int bytes_per_sample)1470 void AUAudioInputStream::UpmixMonoToStereoInPlace(AudioBuffer* audio_buffer,
1471 int bytes_per_sample) {
1472 constexpr int channels = 2;
1473 DCHECK_EQ(audio_buffer->mNumberChannels, static_cast<UInt32>(channels));
1474 const int total_bytes = audio_buffer->mDataByteSize;
1475 const int frames = total_bytes / bytes_per_sample / channels;
1476 char* byte_ptr = reinterpret_cast<char*>(audio_buffer->mData);
1477 for (int i = frames - 1; i >= 0; --i) {
1478 int in_offset = (bytes_per_sample * i);
1479 int out_offset = (channels * bytes_per_sample * i);
1480 for (int b = 0; b < bytes_per_sample; ++b) {
1481 const char byte = byte_ptr[in_offset + b];
1482 byte_ptr[out_offset + b] = byte;
1483 byte_ptr[out_offset + bytes_per_sample + b] = byte;
1484 }
1485 }
1486 }
1487
1488 } // namespace media
1489