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// Implementation of AudioInputStream for Mac OS X using the special AUHAL 6// input Audio Unit present in OS 10.4 and later. 7// The AUHAL input Audio Unit is for low-latency audio I/O. 8// 9// Overview of operation: 10// 11// - An object of AUAudioInputStream is created by the AudioManager 12// factory: audio_man->MakeAudioInputStream(). 13// - Next some thread will call Open(), at that point the underlying 14// AUHAL output Audio Unit is created and configured. 15// - Then some thread will call Start(sink). 16// Then the Audio Unit is started which creates its own thread which 17// periodically will provide the sink with more data as buffers are being 18// produced/recorded. 19// - At some point some thread will call Stop(), which we handle by directly 20// stopping the AUHAL output Audio Unit. 21// - The same thread that called stop will call Close() where we cleanup 22// and notify the audio manager, which likely will destroy this object. 23// 24// Implementation notes: 25// 26// - It is recommended to first acquire the native sample rate of the default 27// input device and then use the same rate when creating this object. 28// Use AUAudioInputStream::HardwareSampleRate() to retrieve the sample rate. 29// - Calling Close() also leads to self destruction. 30// - The latency consists of two parts: 31// 1) Hardware latency, which includes Audio Unit latency, audio device 32// latency; 33// 2) The delay between the actual recording instant and the time when the 34// data packet is provided as a callback. 35// 36#ifndef MEDIA_AUDIO_MAC_AUDIO_LOW_LATENCY_INPUT_MAC_H_ 37#define MEDIA_AUDIO_MAC_AUDIO_LOW_LATENCY_INPUT_MAC_H_ 38 39#include <AudioUnit/AudioUnit.h> 40#include <CoreAudio/CoreAudio.h> 41 42#include "base/cancelable_callback.h" 43#include "base/memory/scoped_ptr.h" 44#include "base/synchronization/lock.h" 45#include "media/audio/agc_audio_stream.h" 46#include "media/audio/audio_io.h" 47#include "media/audio/audio_parameters.h" 48#include "media/base/audio_block_fifo.h" 49 50namespace media { 51 52class AudioBus; 53class AudioManagerMac; 54class DataBuffer; 55 56class AUAudioInputStream : public AgcAudioStream<AudioInputStream> { 57 public: 58 // The ctor takes all the usual parameters, plus |manager| which is the 59 // the audio manager who is creating this object. 60 AUAudioInputStream(AudioManagerMac* manager, 61 const AudioParameters& input_params, 62 AudioDeviceID audio_device_id); 63 // The dtor is typically called by the AudioManager only and it is usually 64 // triggered by calling AudioInputStream::Close(). 65 virtual ~AUAudioInputStream(); 66 67 // Implementation of AudioInputStream. 68 virtual bool Open() OVERRIDE; 69 virtual void Start(AudioInputCallback* callback) OVERRIDE; 70 virtual void Stop() OVERRIDE; 71 virtual void Close() OVERRIDE; 72 virtual double GetMaxVolume() OVERRIDE; 73 virtual void SetVolume(double volume) OVERRIDE; 74 virtual double GetVolume() OVERRIDE; 75 virtual bool IsMuted() OVERRIDE; 76 77 // Returns the current hardware sample rate for the default input device. 78 MEDIA_EXPORT static int HardwareSampleRate(); 79 80 bool started() const { return started_; } 81 AudioUnit audio_unit() { return audio_unit_; } 82 AudioBufferList* audio_buffer_list() { return &audio_buffer_list_; } 83 84 private: 85 // AudioOutputUnit callback. 86 static OSStatus InputProc(void* user_data, 87 AudioUnitRenderActionFlags* flags, 88 const AudioTimeStamp* time_stamp, 89 UInt32 bus_number, 90 UInt32 number_of_frames, 91 AudioBufferList* io_data); 92 93 // Pushes recorded data to consumer of the input audio stream. 94 OSStatus Provide(UInt32 number_of_frames, AudioBufferList* io_data, 95 const AudioTimeStamp* time_stamp); 96 97 // Gets the fixed capture hardware latency and store it during initialization. 98 // Returns 0 if not available. 99 double GetHardwareLatency(); 100 101 // Gets the current capture delay value. 102 double GetCaptureLatency(const AudioTimeStamp* input_time_stamp); 103 104 // Gets the number of channels for a stream of audio data. 105 int GetNumberOfChannelsFromStream(); 106 107 // Issues the OnError() callback to the |sink_|. 108 void HandleError(OSStatus err); 109 110 // Helper function to check if the volume control is avialable on specific 111 // channel. 112 bool IsVolumeSettableOnChannel(int channel); 113 114 // Our creator, the audio manager needs to be notified when we close. 115 AudioManagerMac* manager_; 116 117 // Contains the desired number of audio frames in each callback. 118 const size_t number_of_frames_; 119 120 // Pointer to the object that will receive the recorded audio samples. 121 AudioInputCallback* sink_; 122 123 // Structure that holds the desired output format of the stream. 124 // Note that, this format can differ from the device(=input) format. 125 AudioStreamBasicDescription format_; 126 127 // The special Audio Unit called AUHAL, which allows us to pass audio data 128 // directly from a microphone, through the HAL, and to our application. 129 // The AUHAL also enables selection of non default devices. 130 AudioUnit audio_unit_; 131 132 // The UID refers to the current input audio device. 133 AudioDeviceID input_device_id_; 134 135 // Provides a mechanism for encapsulating one or more buffers of audio data. 136 AudioBufferList audio_buffer_list_; 137 138 // Temporary storage for recorded data. The InputProc() renders into this 139 // array as soon as a frame of the desired buffer size has been recorded. 140 scoped_ptr<uint8[]> audio_data_buffer_; 141 142 // True after successfull Start(), false after successful Stop(). 143 bool started_; 144 145 // Fixed capture hardware latency in frames. 146 double hardware_latency_frames_; 147 148 // The number of channels in each frame of audio data, which is used 149 // when querying the volume of each channel. 150 int number_of_channels_in_frame_; 151 152 // FIFO used to accumulates recorded data. 153 media::AudioBlockFifo fifo_; 154 155 // Used to defer Start() to workaround http://crbug.com/160920. 156 base::CancelableClosure deferred_start_cb_; 157 158 DISALLOW_COPY_AND_ASSIGN(AUAudioInputStream); 159}; 160 161} // namespace media 162 163#endif // MEDIA_AUDIO_MAC_AUDIO_LOW_LATENCY_INPUT_MAC_H_ 164