• 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_synchronized_mac.h"
6 
7 #include <CoreServices/CoreServices.h>
8 #include <algorithm>
9 
10 #include "base/basictypes.h"
11 #include "base/debug/trace_event.h"
12 #include "base/logging.h"
13 #include "base/mac/mac_logging.h"
14 #include "media/audio/mac/audio_manager_mac.h"
15 #include "media/base/channel_mixer.h"
16 
17 namespace media {
18 
19 static const int kHardwareBufferSize = 128;
20 static const int kFifoSize = 16384;
21 
22 // TODO(crogers): handle the non-stereo case.
23 static const int kChannels = 2;
24 
25 // This value was determined empirically for minimum latency while still
26 // guarding against FIFO under-runs.
27 static const int kBaseTargetFifoFrames = 256 + 64;
28 
29 // If the input and output sample-rate don't match, then we need to maintain
30 // an additional safety margin due to the callback timing jitter and the
31 // varispeed buffering.  This value was empirically tuned.
32 static const int kAdditionalTargetFifoFrames = 128;
33 
ZeroBufferList(AudioBufferList * buffer_list)34 static void ZeroBufferList(AudioBufferList* buffer_list) {
35   for (size_t i = 0; i < buffer_list->mNumberBuffers; ++i)
36     memset(buffer_list->mBuffers[i].mData,
37            0,
38            buffer_list->mBuffers[i].mDataByteSize);
39 }
40 
WrapBufferList(AudioBufferList * buffer_list,AudioBus * bus,int frames)41 static void WrapBufferList(AudioBufferList* buffer_list,
42                            AudioBus* bus,
43                            int frames) {
44   DCHECK(buffer_list);
45   DCHECK(bus);
46   int channels = bus->channels();
47   int buffer_list_channels = buffer_list->mNumberBuffers;
48 
49   // Copy pointers from AudioBufferList.
50   int source_idx = 0;
51   for (int i = 0; i < channels; ++i) {
52     bus->SetChannelData(
53         i, static_cast<float*>(buffer_list->mBuffers[source_idx].mData));
54 
55     // It's ok to pass in a |buffer_list| with fewer channels, in which
56     // case we just duplicate the last channel.
57     if (source_idx < buffer_list_channels - 1)
58       ++source_idx;
59   }
60 
61   // Finally set the actual length.
62   bus->set_frames(frames);
63 }
64 
AudioSynchronizedStream(AudioManagerMac * manager,const AudioParameters & params,AudioDeviceID input_id,AudioDeviceID output_id)65 AudioSynchronizedStream::AudioSynchronizedStream(
66     AudioManagerMac* manager,
67     const AudioParameters& params,
68     AudioDeviceID input_id,
69     AudioDeviceID output_id)
70     : manager_(manager),
71       params_(params),
72       input_sample_rate_(0),
73       output_sample_rate_(0),
74       input_id_(input_id),
75       output_id_(output_id),
76       input_buffer_list_(NULL),
77       fifo_(kChannels, kFifoSize),
78       target_fifo_frames_(kBaseTargetFifoFrames),
79       average_delta_(0.0),
80       fifo_rate_compensation_(1.0),
81       input_unit_(0),
82       varispeed_unit_(0),
83       output_unit_(0),
84       first_input_time_(-1),
85       is_running_(false),
86       hardware_buffer_size_(kHardwareBufferSize),
87       channels_(kChannels) {
88   VLOG(1) << "AudioSynchronizedStream::AudioSynchronizedStream()";
89 }
90 
~AudioSynchronizedStream()91 AudioSynchronizedStream::~AudioSynchronizedStream() {
92   DCHECK(!input_unit_);
93   DCHECK(!output_unit_);
94   DCHECK(!varispeed_unit_);
95 }
96 
Open()97 bool AudioSynchronizedStream::Open() {
98   if (params_.channels() != kChannels) {
99     LOG(ERROR) << "Only stereo output is currently supported.";
100     return false;
101   }
102 
103   // Create the input, output, and varispeed AudioUnits.
104   OSStatus result = CreateAudioUnits();
105   if (result != noErr) {
106     LOG(ERROR) << "Cannot create AudioUnits.";
107     return false;
108   }
109 
110   result = SetupInput(input_id_);
111   if (result != noErr) {
112     LOG(ERROR) << "Error configuring input AudioUnit.";
113     return false;
114   }
115 
116   result = SetupOutput(output_id_);
117   if (result != noErr) {
118     LOG(ERROR) << "Error configuring output AudioUnit.";
119     return false;
120   }
121 
122   result = SetupCallbacks();
123   if (result != noErr) {
124     LOG(ERROR) << "Error setting up callbacks on AudioUnits.";
125     return false;
126   }
127 
128   result = SetupStreamFormats();
129   if (result != noErr) {
130     LOG(ERROR) << "Error configuring stream formats on AudioUnits.";
131     return false;
132   }
133 
134   AllocateInputData();
135 
136   // Final initialization of the AudioUnits.
137   result = AudioUnitInitialize(input_unit_);
138   if (result != noErr) {
139     LOG(ERROR) << "Error initializing input AudioUnit.";
140     return false;
141   }
142 
143   result = AudioUnitInitialize(output_unit_);
144   if (result != noErr) {
145     LOG(ERROR) << "Error initializing output AudioUnit.";
146     return false;
147   }
148 
149   result = AudioUnitInitialize(varispeed_unit_);
150   if (result != noErr) {
151     LOG(ERROR) << "Error initializing varispeed AudioUnit.";
152     return false;
153   }
154 
155   if (input_sample_rate_ != output_sample_rate_) {
156     // Add extra safety margin.
157     target_fifo_frames_ += kAdditionalTargetFifoFrames;
158   }
159 
160   // Buffer initial silence corresponding to target I/O buffering.
161   fifo_.Clear();
162   scoped_ptr<AudioBus> silence =
163       AudioBus::Create(channels_, target_fifo_frames_);
164   silence->Zero();
165   fifo_.Push(silence.get());
166 
167   return true;
168 }
169 
Close()170 void AudioSynchronizedStream::Close() {
171   DCHECK(!is_running_);
172 
173   if (input_buffer_list_) {
174     free(input_buffer_list_);
175     input_buffer_list_ = 0;
176     input_bus_.reset(NULL);
177     wrapper_bus_.reset(NULL);
178   }
179 
180   if (input_unit_) {
181     AudioUnitUninitialize(input_unit_);
182     CloseComponent(input_unit_);
183   }
184 
185   if (output_unit_) {
186     AudioUnitUninitialize(output_unit_);
187     CloseComponent(output_unit_);
188   }
189 
190   if (varispeed_unit_) {
191     AudioUnitUninitialize(varispeed_unit_);
192     CloseComponent(varispeed_unit_);
193   }
194 
195   input_unit_ = NULL;
196   output_unit_ = NULL;
197   varispeed_unit_ = NULL;
198 
199   // Inform the audio manager that we have been closed. This can cause our
200   // destruction.
201   manager_->ReleaseOutputStream(this);
202 }
203 
Start(AudioSourceCallback * callback)204 void AudioSynchronizedStream::Start(AudioSourceCallback* callback) {
205   DCHECK(callback);
206   DCHECK(input_unit_);
207   DCHECK(output_unit_);
208   DCHECK(varispeed_unit_);
209 
210   if (is_running_ || !input_unit_ || !output_unit_ || !varispeed_unit_)
211     return;
212 
213   source_ = callback;
214 
215   // Reset state variables each time we Start().
216   fifo_rate_compensation_ = 1.0;
217   average_delta_ = 0.0;
218 
219   OSStatus result = noErr;
220 
221   if (!is_running_) {
222     first_input_time_ = -1;
223 
224     result = AudioOutputUnitStart(input_unit_);
225     OSSTATUS_DCHECK(result == noErr, result);
226 
227     if (result == noErr) {
228       result = AudioOutputUnitStart(output_unit_);
229       OSSTATUS_DCHECK(result == noErr, result);
230     }
231   }
232 
233   is_running_ = true;
234 }
235 
Stop()236 void AudioSynchronizedStream::Stop() {
237   OSStatus result = noErr;
238   if (is_running_) {
239     result = AudioOutputUnitStop(input_unit_);
240     OSSTATUS_DCHECK(result == noErr, result);
241 
242     if (result == noErr) {
243       result = AudioOutputUnitStop(output_unit_);
244       OSSTATUS_DCHECK(result == noErr, result);
245     }
246   }
247 
248   if (result == noErr)
249     is_running_ = false;
250 }
251 
IsRunning()252 bool AudioSynchronizedStream::IsRunning() {
253   return is_running_;
254 }
255 
256 // TODO(crogers): implement - or remove from AudioOutputStream.
SetVolume(double volume)257 void AudioSynchronizedStream::SetVolume(double volume) {}
GetVolume(double * volume)258 void AudioSynchronizedStream::GetVolume(double* volume) {}
259 
SetOutputDeviceAsCurrent(AudioDeviceID output_id)260 OSStatus AudioSynchronizedStream::SetOutputDeviceAsCurrent(
261     AudioDeviceID output_id) {
262   OSStatus result = noErr;
263 
264   // Get the default output device if device is unknown.
265   if (output_id == kAudioDeviceUnknown) {
266     AudioObjectPropertyAddress pa;
267     pa.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
268     pa.mScope = kAudioObjectPropertyScopeGlobal;
269     pa.mElement = kAudioObjectPropertyElementMaster;
270     UInt32 size = sizeof(output_id);
271 
272     result = AudioObjectGetPropertyData(
273         kAudioObjectSystemObject,
274         &pa,
275         0,
276         0,
277         &size,
278         &output_id);
279 
280     OSSTATUS_DCHECK(result == noErr, result);
281     if (result != noErr)
282       return result;
283   }
284 
285   // Set the render frame size.
286   UInt32 frame_size = hardware_buffer_size_;
287   AudioObjectPropertyAddress pa;
288   pa.mSelector = kAudioDevicePropertyBufferFrameSize;
289   pa.mScope = kAudioDevicePropertyScopeInput;
290   pa.mElement = kAudioObjectPropertyElementMaster;
291   result = AudioObjectSetPropertyData(
292       output_id,
293       &pa,
294       0,
295       0,
296       sizeof(frame_size),
297       &frame_size);
298 
299   OSSTATUS_DCHECK(result == noErr, result);
300   if (result != noErr)
301     return result;
302 
303   output_info_.Initialize(output_id, false);
304 
305   // Set the Current Device to the Default Output Unit.
306   result = AudioUnitSetProperty(
307       output_unit_,
308       kAudioOutputUnitProperty_CurrentDevice,
309       kAudioUnitScope_Global,
310       0,
311       &output_info_.id_,
312       sizeof(output_info_.id_));
313 
314   OSSTATUS_DCHECK(result == noErr, result);
315   return result;
316 }
317 
SetInputDeviceAsCurrent(AudioDeviceID input_id)318 OSStatus AudioSynchronizedStream::SetInputDeviceAsCurrent(
319     AudioDeviceID input_id) {
320   OSStatus result = noErr;
321 
322   // Get the default input device if device is unknown.
323   if (input_id == kAudioDeviceUnknown) {
324     AudioObjectPropertyAddress pa;
325     pa.mSelector = kAudioHardwarePropertyDefaultInputDevice;
326     pa.mScope = kAudioObjectPropertyScopeGlobal;
327     pa.mElement = kAudioObjectPropertyElementMaster;
328     UInt32 size = sizeof(input_id);
329 
330     result = AudioObjectGetPropertyData(
331         kAudioObjectSystemObject,
332         &pa,
333         0,
334         0,
335         &size,
336         &input_id);
337 
338     OSSTATUS_DCHECK(result == noErr, result);
339     if (result != noErr)
340       return result;
341   }
342 
343   // Set the render frame size.
344   UInt32 frame_size = hardware_buffer_size_;
345   AudioObjectPropertyAddress pa;
346   pa.mSelector = kAudioDevicePropertyBufferFrameSize;
347   pa.mScope = kAudioDevicePropertyScopeInput;
348   pa.mElement = kAudioObjectPropertyElementMaster;
349   result = AudioObjectSetPropertyData(
350       input_id,
351       &pa,
352       0,
353       0,
354       sizeof(frame_size),
355       &frame_size);
356 
357   OSSTATUS_DCHECK(result == noErr, result);
358   if (result != noErr)
359     return result;
360 
361   input_info_.Initialize(input_id, true);
362 
363   // Set the Current Device to the AUHAL.
364   // This should be done only after I/O has been enabled on the AUHAL.
365   result = AudioUnitSetProperty(
366       input_unit_,
367       kAudioOutputUnitProperty_CurrentDevice,
368       kAudioUnitScope_Global,
369       0,
370       &input_info_.id_,
371       sizeof(input_info_.id_));
372 
373   OSSTATUS_DCHECK(result == noErr, result);
374   return result;
375 }
376 
CreateAudioUnits()377 OSStatus AudioSynchronizedStream::CreateAudioUnits() {
378   // Q: Why do we need a varispeed unit?
379   // A: If the input device and the output device are running at
380   // different sample rates and/or on different clocks, we will need
381   // to compensate to avoid a pitch change and
382   // to avoid buffer under and over runs.
383   ComponentDescription varispeed_desc;
384   varispeed_desc.componentType = kAudioUnitType_FormatConverter;
385   varispeed_desc.componentSubType = kAudioUnitSubType_Varispeed;
386   varispeed_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
387   varispeed_desc.componentFlags = 0;
388   varispeed_desc.componentFlagsMask = 0;
389 
390   Component varispeed_comp = FindNextComponent(NULL, &varispeed_desc);
391   if (varispeed_comp == NULL)
392     return -1;
393 
394   OSStatus result = OpenAComponent(varispeed_comp, &varispeed_unit_);
395   OSSTATUS_DCHECK(result == noErr, result);
396   if (result != noErr)
397     return result;
398 
399   // Open input AudioUnit.
400   ComponentDescription input_desc;
401   input_desc.componentType = kAudioUnitType_Output;
402   input_desc.componentSubType = kAudioUnitSubType_HALOutput;
403   input_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
404   input_desc.componentFlags = 0;
405   input_desc.componentFlagsMask = 0;
406 
407   Component input_comp = FindNextComponent(NULL, &input_desc);
408   if (input_comp == NULL)
409     return -1;
410 
411   result = OpenAComponent(input_comp, &input_unit_);
412   OSSTATUS_DCHECK(result == noErr, result);
413   if (result != noErr)
414     return result;
415 
416   // Open output AudioUnit.
417   ComponentDescription output_desc;
418   output_desc.componentType = kAudioUnitType_Output;
419   output_desc.componentSubType = kAudioUnitSubType_DefaultOutput;
420   output_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
421   output_desc.componentFlags = 0;
422   output_desc.componentFlagsMask = 0;
423 
424   Component output_comp = FindNextComponent(NULL, &output_desc);
425   if (output_comp == NULL)
426     return -1;
427 
428   result = OpenAComponent(output_comp, &output_unit_);
429   OSSTATUS_DCHECK(result == noErr, result);
430   if (result != noErr)
431     return result;
432 
433   return noErr;
434 }
435 
SetupInput(AudioDeviceID input_id)436 OSStatus AudioSynchronizedStream::SetupInput(AudioDeviceID input_id) {
437   // The AUHAL used for input needs to be initialized
438   // before anything is done to it.
439   OSStatus result = AudioUnitInitialize(input_unit_);
440   OSSTATUS_DCHECK(result == noErr, result);
441   if (result != noErr)
442     return result;
443 
444   // We must enable the Audio Unit (AUHAL) for input and disable output
445   // BEFORE setting the AUHAL's current device.
446   result = EnableIO();
447   OSSTATUS_DCHECK(result == noErr, result);
448   if (result != noErr)
449     return result;
450 
451   result = SetInputDeviceAsCurrent(input_id);
452   OSSTATUS_DCHECK(result == noErr, result);
453 
454   return result;
455 }
456 
EnableIO()457 OSStatus AudioSynchronizedStream::EnableIO() {
458   // Enable input on the AUHAL.
459   UInt32 enable_io = 1;
460   OSStatus result = AudioUnitSetProperty(
461       input_unit_,
462       kAudioOutputUnitProperty_EnableIO,
463       kAudioUnitScope_Input,
464       1,  // input element
465       &enable_io,
466       sizeof(enable_io));
467 
468   OSSTATUS_DCHECK(result == noErr, result);
469   if (result != noErr)
470     return result;
471 
472   // Disable Output on the AUHAL.
473   enable_io = 0;
474   result = AudioUnitSetProperty(
475       input_unit_,
476       kAudioOutputUnitProperty_EnableIO,
477       kAudioUnitScope_Output,
478       0,  // output element
479       &enable_io,
480       sizeof(enable_io));
481 
482   OSSTATUS_DCHECK(result == noErr, result);
483   return result;
484 }
485 
SetupOutput(AudioDeviceID output_id)486 OSStatus AudioSynchronizedStream::SetupOutput(AudioDeviceID output_id) {
487   OSStatus result = noErr;
488 
489   result = SetOutputDeviceAsCurrent(output_id);
490   OSSTATUS_DCHECK(result == noErr, result);
491   if (result != noErr)
492     return result;
493 
494   // Tell the output unit not to reset timestamps.
495   // Otherwise sample rate changes will cause sync loss.
496   UInt32 start_at_zero = 0;
497   result = AudioUnitSetProperty(
498       output_unit_,
499       kAudioOutputUnitProperty_StartTimestampsAtZero,
500       kAudioUnitScope_Global,
501       0,
502       &start_at_zero,
503       sizeof(start_at_zero));
504 
505   OSSTATUS_DCHECK(result == noErr, result);
506 
507   return result;
508 }
509 
SetupCallbacks()510 OSStatus AudioSynchronizedStream::SetupCallbacks() {
511   // Set the input callback.
512   AURenderCallbackStruct callback;
513   callback.inputProc = InputProc;
514   callback.inputProcRefCon = this;
515   OSStatus result = AudioUnitSetProperty(
516       input_unit_,
517       kAudioOutputUnitProperty_SetInputCallback,
518       kAudioUnitScope_Global,
519       0,
520       &callback,
521       sizeof(callback));
522 
523   OSSTATUS_DCHECK(result == noErr, result);
524   if (result != noErr)
525     return result;
526 
527   // Set the output callback.
528   callback.inputProc = OutputProc;
529   callback.inputProcRefCon = this;
530   result = AudioUnitSetProperty(
531       output_unit_,
532       kAudioUnitProperty_SetRenderCallback,
533       kAudioUnitScope_Input,
534       0,
535       &callback,
536       sizeof(callback));
537 
538   OSSTATUS_DCHECK(result == noErr, result);
539   if (result != noErr)
540     return result;
541 
542   // Set the varispeed callback.
543   callback.inputProc = VarispeedProc;
544   callback.inputProcRefCon = this;
545   result = AudioUnitSetProperty(
546       varispeed_unit_,
547       kAudioUnitProperty_SetRenderCallback,
548       kAudioUnitScope_Input,
549       0,
550       &callback,
551       sizeof(callback));
552 
553   OSSTATUS_DCHECK(result == noErr, result);
554 
555   return result;
556 }
557 
SetupStreamFormats()558 OSStatus AudioSynchronizedStream::SetupStreamFormats() {
559   AudioStreamBasicDescription asbd, asbd_dev1_in, asbd_dev2_out;
560 
561   // Get the Stream Format (Output client side).
562   UInt32 property_size = sizeof(asbd_dev1_in);
563   OSStatus result = AudioUnitGetProperty(
564       input_unit_,
565       kAudioUnitProperty_StreamFormat,
566       kAudioUnitScope_Input,
567       1,
568       &asbd_dev1_in,
569       &property_size);
570 
571   OSSTATUS_DCHECK(result == noErr, result);
572   if (result != noErr)
573     return result;
574 
575   // Get the Stream Format (client side).
576   property_size = sizeof(asbd);
577   result = AudioUnitGetProperty(
578       input_unit_,
579       kAudioUnitProperty_StreamFormat,
580       kAudioUnitScope_Output,
581       1,
582       &asbd,
583       &property_size);
584 
585   OSSTATUS_DCHECK(result == noErr, result);
586   if (result != noErr)
587     return result;
588 
589   // Get the Stream Format (Output client side).
590   property_size = sizeof(asbd_dev2_out);
591   result = AudioUnitGetProperty(
592       output_unit_,
593       kAudioUnitProperty_StreamFormat,
594       kAudioUnitScope_Output,
595       0,
596       &asbd_dev2_out,
597       &property_size);
598 
599   OSSTATUS_DCHECK(result == noErr, result);
600   if (result != noErr)
601     return result;
602 
603   // Set the format of all the AUs to the input/output devices channel count.
604   // For a simple case, you want to set this to
605   // the lower of count of the channels in the input device vs output device.
606   asbd.mChannelsPerFrame = std::min(asbd_dev1_in.mChannelsPerFrame,
607                                     asbd_dev2_out.mChannelsPerFrame);
608 
609   // We must get the sample rate of the input device and set it to the
610   // stream format of AUHAL.
611   Float64 rate = 0;
612   property_size = sizeof(rate);
613 
614   AudioObjectPropertyAddress pa;
615   pa.mSelector = kAudioDevicePropertyNominalSampleRate;
616   pa.mScope = kAudioObjectPropertyScopeWildcard;
617   pa.mElement = kAudioObjectPropertyElementMaster;
618   result = AudioObjectGetPropertyData(
619       input_info_.id_,
620       &pa,
621       0,
622       0,
623       &property_size,
624       &rate);
625 
626   OSSTATUS_DCHECK(result == noErr, result);
627   if (result != noErr)
628     return result;
629 
630   input_sample_rate_ = rate;
631 
632   asbd.mSampleRate = rate;
633   property_size = sizeof(asbd);
634 
635   // Set the new formats to the AUs...
636   result = AudioUnitSetProperty(
637       input_unit_,
638       kAudioUnitProperty_StreamFormat,
639       kAudioUnitScope_Output,
640       1,
641       &asbd,
642       property_size);
643 
644   OSSTATUS_DCHECK(result == noErr, result);
645   if (result != noErr)
646     return result;
647 
648   result = AudioUnitSetProperty(
649       varispeed_unit_,
650       kAudioUnitProperty_StreamFormat,
651       kAudioUnitScope_Input,
652       0,
653       &asbd,
654       property_size);
655 
656   OSSTATUS_DCHECK(result == noErr, result);
657   if (result != noErr)
658     return result;
659 
660   // Set the correct sample rate for the output device,
661   // but keep the channel count the same.
662   property_size = sizeof(rate);
663 
664   pa.mSelector = kAudioDevicePropertyNominalSampleRate;
665   pa.mScope = kAudioObjectPropertyScopeWildcard;
666   pa.mElement = kAudioObjectPropertyElementMaster;
667   result = AudioObjectGetPropertyData(
668       output_info_.id_,
669       &pa,
670       0,
671       0,
672       &property_size,
673       &rate);
674 
675   OSSTATUS_DCHECK(result == noErr, result);
676   if (result != noErr)
677     return result;
678 
679   output_sample_rate_ = rate;
680 
681   // The requested sample-rate must match the hardware sample-rate.
682   if (output_sample_rate_ != params_.sample_rate()) {
683     LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate()
684         <<  " must match the hardware sample-rate: " << output_sample_rate_;
685     return kAudioDeviceUnsupportedFormatError;
686   }
687 
688   asbd.mSampleRate = rate;
689   property_size = sizeof(asbd);
690 
691   // Set the new audio stream formats for the rest of the AUs...
692   result = AudioUnitSetProperty(
693       varispeed_unit_,
694       kAudioUnitProperty_StreamFormat,
695       kAudioUnitScope_Output,
696       0,
697       &asbd,
698       property_size);
699 
700   OSSTATUS_DCHECK(result == noErr, result);
701   if (result != noErr)
702     return result;
703 
704   result = AudioUnitSetProperty(
705       output_unit_,
706       kAudioUnitProperty_StreamFormat,
707       kAudioUnitScope_Input,
708       0,
709       &asbd,
710       property_size);
711 
712   OSSTATUS_DCHECK(result == noErr, result);
713   return result;
714 }
715 
AllocateInputData()716 void AudioSynchronizedStream::AllocateInputData() {
717   // Get the native number of input channels that the hardware supports.
718   int hardware_channels = 0;
719   bool got_hardware_channels = AudioManagerMac::GetDeviceChannels(
720       input_id_, kAudioDevicePropertyScopeInput, &hardware_channels);
721   if (!got_hardware_channels || hardware_channels > 2) {
722     // Only mono and stereo are supported on the input side. When it fails to
723     // get the native channel number or the native channel number is bigger
724     // than 2, we open the device in stereo mode.
725     hardware_channels = 2;
726   }
727 
728   // Allocate storage for the AudioBufferList used for the
729   // input data from the input AudioUnit.
730   // We allocate enough space for with one AudioBuffer per channel.
731   size_t malloc_size = offsetof(AudioBufferList, mBuffers[0]) +
732       (sizeof(AudioBuffer) * hardware_channels);
733 
734   input_buffer_list_ = static_cast<AudioBufferList*>(malloc(malloc_size));
735   input_buffer_list_->mNumberBuffers = hardware_channels;
736 
737   input_bus_ = AudioBus::Create(hardware_channels, hardware_buffer_size_);
738   wrapper_bus_ = AudioBus::CreateWrapper(channels_);
739   if (hardware_channels != params_.input_channels()) {
740     ChannelLayout hardware_channel_layout =
741         GuessChannelLayout(hardware_channels);
742     ChannelLayout requested_channel_layout =
743         GuessChannelLayout(params_.input_channels());
744     channel_mixer_.reset(new ChannelMixer(hardware_channel_layout,
745                                           requested_channel_layout));
746     mixer_bus_ = AudioBus::Create(params_.input_channels(),
747                                   hardware_buffer_size_);
748   }
749 
750   // Allocate buffers for AudioBufferList.
751   UInt32 buffer_size_bytes = input_bus_->frames() * sizeof(Float32);
752   for (size_t i = 0; i < input_buffer_list_->mNumberBuffers; ++i) {
753     input_buffer_list_->mBuffers[i].mNumberChannels = 1;
754     input_buffer_list_->mBuffers[i].mDataByteSize = buffer_size_bytes;
755     input_buffer_list_->mBuffers[i].mData = input_bus_->channel(i);
756   }
757 }
758 
HandleInputCallback(AudioUnitRenderActionFlags * io_action_flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)759 OSStatus AudioSynchronizedStream::HandleInputCallback(
760     AudioUnitRenderActionFlags* io_action_flags,
761     const AudioTimeStamp* time_stamp,
762     UInt32 bus_number,
763     UInt32 number_of_frames,
764     AudioBufferList* io_data) {
765   TRACE_EVENT0("audio", "AudioSynchronizedStream::HandleInputCallback");
766 
767   if (first_input_time_ < 0.0)
768     first_input_time_ = time_stamp->mSampleTime;
769 
770   // Get the new audio input data.
771   OSStatus result = AudioUnitRender(
772       input_unit_,
773       io_action_flags,
774       time_stamp,
775       bus_number,
776       number_of_frames,
777       input_buffer_list_);
778 
779   // TODO(xians): Add back the DCHECK after synchronize IO supports all
780   // combination of input and output params. See http://issue/246521.
781   if (result != noErr)
782     return result;
783 
784   // Buffer input into FIFO.
785   int available_frames = fifo_.max_frames() - fifo_.frames();
786   if (input_bus_->frames() <= available_frames) {
787     if (channel_mixer_) {
788       channel_mixer_->Transform(input_bus_.get(), mixer_bus_.get());
789       fifo_.Push(mixer_bus_.get());
790     } else {
791       fifo_.Push(input_bus_.get());
792     }
793   }
794 
795   return result;
796 }
797 
HandleVarispeedCallback(AudioUnitRenderActionFlags * io_action_flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)798 OSStatus AudioSynchronizedStream::HandleVarispeedCallback(
799     AudioUnitRenderActionFlags* io_action_flags,
800     const AudioTimeStamp* time_stamp,
801     UInt32 bus_number,
802     UInt32 number_of_frames,
803     AudioBufferList* io_data) {
804   // Create a wrapper bus on the AudioBufferList.
805   WrapBufferList(io_data, wrapper_bus_.get(), number_of_frames);
806 
807   if (fifo_.frames() < static_cast<int>(number_of_frames)) {
808     // We don't DCHECK here, since this is a possible run-time condition
809     // if the machine is bogged down.
810     wrapper_bus_->Zero();
811     return noErr;
812   }
813 
814   // Read from the FIFO to feed the varispeed.
815   fifo_.Consume(wrapper_bus_.get(), 0, number_of_frames);
816 
817   return noErr;
818 }
819 
HandleOutputCallback(AudioUnitRenderActionFlags * io_action_flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)820 OSStatus AudioSynchronizedStream::HandleOutputCallback(
821     AudioUnitRenderActionFlags* io_action_flags,
822     const AudioTimeStamp* time_stamp,
823     UInt32 bus_number,
824     UInt32 number_of_frames,
825     AudioBufferList* io_data) {
826   // Input callback hasn't run yet or we've suddenly changed sample-rates
827   // -> silence.
828   if (first_input_time_ < 0.0 ||
829       static_cast<int>(number_of_frames) != params_.frames_per_buffer()) {
830     ZeroBufferList(io_data);
831     return noErr;
832   }
833 
834   // Use the varispeed playback rate to offset small discrepancies
835   // in hardware clocks, and also any differences in sample-rate
836   // between input and output devices.
837 
838   // Calculate a varispeed rate scalar factor to compensate for drift between
839   // input and output.  We use the actual number of frames still in the FIFO
840   // compared with the ideal value of |target_fifo_frames_|.
841   int delta = fifo_.frames() - target_fifo_frames_;
842 
843   // Average |delta| because it can jitter back/forth quite frequently
844   // by +/- the hardware buffer-size *if* the input and output callbacks are
845   // happening at almost exactly the same time.  Also, if the input and output
846   // sample-rates are different then |delta| will jitter quite a bit due to
847   // the rate conversion happening in the varispeed, plus the jittering of
848   // the callbacks.  The average value is what's important here.
849   average_delta_ += (delta - average_delta_) * 0.1;
850 
851   // Compute a rate compensation which always attracts us back to the
852   // |target_fifo_frames_| over a period of kCorrectionTimeSeconds.
853   const double kCorrectionTimeSeconds = 0.1;
854   double correction_time_frames = kCorrectionTimeSeconds * output_sample_rate_;
855   fifo_rate_compensation_ =
856       (correction_time_frames + average_delta_) / correction_time_frames;
857 
858   // Adjust for FIFO drift.
859   OSStatus result = AudioUnitSetParameter(
860       varispeed_unit_,
861       kVarispeedParam_PlaybackRate,
862       kAudioUnitScope_Global,
863       0,
864       fifo_rate_compensation_,
865       0);
866 
867   OSSTATUS_DCHECK(result == noErr, result);
868   if (result != noErr)
869     return result;
870 
871   // Render to the output using the varispeed.
872   result = AudioUnitRender(
873       varispeed_unit_,
874       io_action_flags,
875       time_stamp,
876       0,
877       number_of_frames,
878       io_data);
879 
880   OSSTATUS_DCHECK(result == noErr, result);
881   if (result != noErr)
882     return result;
883 
884   // Create a wrapper bus on the AudioBufferList.
885   WrapBufferList(io_data, wrapper_bus_.get(), number_of_frames);
886 
887   // Process in-place!
888   source_->OnMoreIOData(wrapper_bus_.get(),
889                         wrapper_bus_.get(),
890                         AudioBuffersState(0, 0));
891 
892   return noErr;
893 }
894 
InputProc(void * user_data,AudioUnitRenderActionFlags * io_action_flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)895 OSStatus AudioSynchronizedStream::InputProc(
896     void* user_data,
897     AudioUnitRenderActionFlags* io_action_flags,
898     const AudioTimeStamp* time_stamp,
899     UInt32 bus_number,
900     UInt32 number_of_frames,
901     AudioBufferList* io_data) {
902   AudioSynchronizedStream* stream =
903       static_cast<AudioSynchronizedStream*>(user_data);
904   DCHECK(stream);
905 
906   return stream->HandleInputCallback(
907       io_action_flags,
908       time_stamp,
909       bus_number,
910       number_of_frames,
911       io_data);
912 }
913 
VarispeedProc(void * user_data,AudioUnitRenderActionFlags * io_action_flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)914 OSStatus AudioSynchronizedStream::VarispeedProc(
915     void* user_data,
916     AudioUnitRenderActionFlags* io_action_flags,
917     const AudioTimeStamp* time_stamp,
918     UInt32 bus_number,
919     UInt32 number_of_frames,
920     AudioBufferList* io_data) {
921   AudioSynchronizedStream* stream =
922       static_cast<AudioSynchronizedStream*>(user_data);
923   DCHECK(stream);
924 
925   return stream->HandleVarispeedCallback(
926       io_action_flags,
927       time_stamp,
928       bus_number,
929       number_of_frames,
930       io_data);
931 }
932 
OutputProc(void * user_data,AudioUnitRenderActionFlags * io_action_flags,const AudioTimeStamp * time_stamp,UInt32 bus_number,UInt32 number_of_frames,AudioBufferList * io_data)933 OSStatus AudioSynchronizedStream::OutputProc(
934     void* user_data,
935     AudioUnitRenderActionFlags* io_action_flags,
936     const AudioTimeStamp* time_stamp,
937     UInt32 bus_number,
938     UInt32 number_of_frames,
939     AudioBufferList* io_data) {
940   AudioSynchronizedStream* stream =
941       static_cast<AudioSynchronizedStream*>(user_data);
942   DCHECK(stream);
943 
944   return stream->HandleOutputCallback(
945       io_action_flags,
946       time_stamp,
947       bus_number,
948       number_of_frames,
949       io_data);
950 }
951 
Initialize(AudioDeviceID id,bool is_input)952 void AudioSynchronizedStream::AudioDeviceInfo::Initialize(
953     AudioDeviceID id, bool is_input) {
954   id_ = id;
955   is_input_ = is_input;
956   if (id_ == kAudioDeviceUnknown)
957     return;
958 
959   UInt32 property_size = sizeof(buffer_size_frames_);
960 
961   AudioObjectPropertyAddress pa;
962   pa.mSelector = kAudioDevicePropertyBufferFrameSize;
963   pa.mScope = kAudioObjectPropertyScopeWildcard;
964   pa.mElement = kAudioObjectPropertyElementMaster;
965   OSStatus result = AudioObjectGetPropertyData(
966       id_,
967       &pa,
968       0,
969       0,
970       &property_size,
971       &buffer_size_frames_);
972 
973   OSSTATUS_DCHECK(result == noErr, result);
974 }
975 
976 }  // namespace media
977