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 #ifndef MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ 6 #define MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ 7 8 #include <AudioToolbox/AudioToolbox.h> 9 #include <AudioUnit/AudioUnit.h> 10 #include <CoreAudio/CoreAudio.h> 11 12 #include "base/compiler_specific.h" 13 #include "base/synchronization/lock.h" 14 #include "media/audio/audio_io.h" 15 #include "media/audio/audio_parameters.h" 16 #include "media/base/audio_bus.h" 17 #include "media/base/audio_fifo.h" 18 19 namespace media { 20 21 class AudioManagerMac; 22 class ChannelMixer; 23 24 // AudioSynchronizedStream allows arbitrary combinations of input and output 25 // devices running off different clocks and using different drivers, with 26 // potentially differing sample-rates. It implements AudioOutputStream 27 // and shuttles its synchronized I/O data using AudioSourceCallback. 28 // 29 // It is required to first acquire the native sample rate of the selected 30 // output device and then use the same rate when creating this object. 31 // 32 // ............................................................................ 33 // Theory of Operation: 34 // . 35 // INPUT THREAD . OUTPUT THREAD 36 // +-----------------+ +------+ . 37 // | Input AudioUnit | --> | | . 38 // +-----------------+ | | . 39 // | FIFO | . 40 // | | +-----------+ 41 // | | -----> | Varispeed | 42 // | | +-----------+ 43 // +------+ . | 44 // . | +-----------+ 45 // . OnMoreIOData() --> | Output AU | 46 // . +-----------+ 47 // 48 // The input AudioUnit's InputProc is called on one thread which feeds the 49 // FIFO. The output AudioUnit's OutputProc is called on a second thread 50 // which pulls on the varispeed to get the current input data. The varispeed 51 // handles mismatches between input and output sample-rate and also clock drift 52 // between the input and output drivers. The varispeed consumes its data from 53 // the FIFO and adjusts its rate dynamically according to the amount 54 // of data buffered in the FIFO. If the FIFO starts getting too much data 55 // buffered then the varispeed will speed up slightly to compensate 56 // and similarly if the FIFO doesn't have enough data buffered then the 57 // varispeed will slow down slightly. 58 // 59 // Finally, once the input data is available then OnMoreIOData() is called 60 // which is given this input, and renders the output which is finally sent 61 // to the Output AudioUnit. 62 class AudioSynchronizedStream : public AudioOutputStream { 63 public: 64 // The ctor takes all the usual parameters, plus |manager| which is the 65 // the audio manager who is creating this object. 66 AudioSynchronizedStream(AudioManagerMac* manager, 67 const AudioParameters& params, 68 AudioDeviceID input_id, 69 AudioDeviceID output_id); 70 71 virtual ~AudioSynchronizedStream(); 72 73 // Implementation of AudioOutputStream. 74 virtual bool Open() OVERRIDE; 75 virtual void Close() OVERRIDE; 76 virtual void Start(AudioSourceCallback* callback) OVERRIDE; 77 virtual void Stop() OVERRIDE; 78 79 virtual void SetVolume(double volume) OVERRIDE; 80 virtual void GetVolume(double* volume) OVERRIDE; 81 82 OSStatus SetInputDeviceAsCurrent(AudioDeviceID input_id); 83 OSStatus SetOutputDeviceAsCurrent(AudioDeviceID output_id); 84 AudioDeviceID GetInputDeviceID() { return input_info_.id_; } 85 AudioDeviceID GetOutputDeviceID() { return output_info_.id_; } 86 87 bool IsRunning(); 88 89 private: 90 // Initialization. 91 OSStatus CreateAudioUnits(); 92 OSStatus SetupInput(AudioDeviceID input_id); 93 OSStatus EnableIO(); 94 OSStatus SetupOutput(AudioDeviceID output_id); 95 OSStatus SetupCallbacks(); 96 OSStatus SetupStreamFormats(); 97 void AllocateInputData(); 98 99 // Handlers for the AudioUnit callbacks. 100 OSStatus HandleInputCallback(AudioUnitRenderActionFlags* io_action_flags, 101 const AudioTimeStamp* time_stamp, 102 UInt32 bus_number, 103 UInt32 number_of_frames, 104 AudioBufferList* io_data); 105 106 OSStatus HandleVarispeedCallback(AudioUnitRenderActionFlags* io_action_flags, 107 const AudioTimeStamp* time_stamp, 108 UInt32 bus_number, 109 UInt32 number_of_frames, 110 AudioBufferList* io_data); 111 112 OSStatus HandleOutputCallback(AudioUnitRenderActionFlags* io_action_flags, 113 const AudioTimeStamp* time_stamp, 114 UInt32 bus_number, 115 UInt32 number_of_frames, 116 AudioBufferList* io_data); 117 118 // AudioUnit callbacks. 119 static OSStatus InputProc(void* user_data, 120 AudioUnitRenderActionFlags* io_action_flags, 121 const AudioTimeStamp* time_stamp, 122 UInt32 bus_number, 123 UInt32 number_of_frames, 124 AudioBufferList* io_data); 125 126 static OSStatus VarispeedProc(void* user_data, 127 AudioUnitRenderActionFlags* io_action_flags, 128 const AudioTimeStamp* time_stamp, 129 UInt32 bus_number, 130 UInt32 number_of_frames, 131 AudioBufferList* io_data); 132 133 static OSStatus OutputProc(void* user_data, 134 AudioUnitRenderActionFlags* io_action_flags, 135 const AudioTimeStamp* time_stamp, 136 UInt32 bus_number, 137 UInt32 number_of_frames, 138 AudioBufferList* io_data); 139 140 // Our creator. 141 AudioManagerMac* manager_; 142 143 // Client parameters. 144 AudioParameters params_; 145 146 double input_sample_rate_; 147 double output_sample_rate_; 148 149 // Pointer to the object that will provide the audio samples. 150 AudioSourceCallback* source_; 151 152 // Values used in Open(). 153 AudioDeviceID input_id_; 154 AudioDeviceID output_id_; 155 156 // The input AudioUnit renders its data here. 157 AudioBufferList* input_buffer_list_; 158 159 // Holds the actual data for |input_buffer_list_|. 160 scoped_ptr<AudioBus> input_bus_; 161 162 // Used to overlay AudioBufferLists. 163 scoped_ptr<AudioBus> wrapper_bus_; 164 165 class AudioDeviceInfo { 166 public: 167 AudioDeviceInfo() 168 : id_(kAudioDeviceUnknown), 169 is_input_(false), 170 buffer_size_frames_(0) {} 171 void Initialize(AudioDeviceID inID, bool isInput); 172 bool IsInitialized() const { return id_ != kAudioDeviceUnknown; } 173 174 AudioDeviceID id_; 175 bool is_input_; 176 UInt32 buffer_size_frames_; 177 }; 178 179 AudioDeviceInfo input_info_; 180 AudioDeviceInfo output_info_; 181 182 // Used for input to output buffering. 183 AudioFifo fifo_; 184 185 // The optimal number of frames we'd like to keep in the FIFO at all times. 186 int target_fifo_frames_; 187 188 // A running average of the measured delta between actual number of frames 189 // in the FIFO versus |target_fifo_frames_|. 190 double average_delta_; 191 192 // A varispeed rate scalar which is calculated based on FIFO drift. 193 double fifo_rate_compensation_; 194 195 // AudioUnits. 196 AudioUnit input_unit_; 197 AudioUnit varispeed_unit_; 198 AudioUnit output_unit_; 199 200 double first_input_time_; 201 202 bool is_running_; 203 int hardware_buffer_size_; 204 int channels_; 205 206 // Channel mixer used to transform mono to stereo data. It is only created 207 // if the input_hardware_channels is mono. 208 scoped_ptr<ChannelMixer> channel_mixer_; 209 scoped_ptr<AudioBus> mixer_bus_; 210 211 DISALLOW_COPY_AND_ASSIGN(AudioSynchronizedStream); 212 }; 213 214 } // namespace media 215 216 #endif // MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ 217