1 // Copyright 2013 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 notes: 6 // 7 // - It is recommended to first acquire the native sample rate of the default 8 // output device and then use the same rate when creating this object. 9 // Use AudioManagerMac::HardwareSampleRate() to retrieve the sample rate. 10 // - Calling Close() also leads to self destruction. 11 // - The latency consists of two parts: 12 // 1) Hardware latency, which includes Audio Unit latency, audio device 13 // latency; 14 // 2) The delay between the moment getting the callback and the scheduled time 15 // stamp that tells when the data is going to be played out. 16 // 17 #ifndef MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_ 18 #define MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_ 19 20 #include <AudioUnit/AudioUnit.h> 21 #include <CoreAudio/CoreAudio.h> 22 23 #include "base/compiler_specific.h" 24 #include "base/synchronization/lock.h" 25 #include "media/audio/audio_io.h" 26 #include "media/audio/audio_parameters.h" 27 28 namespace media { 29 30 class AudioManagerMac; 31 class AudioPullFifo; 32 33 // Implementation of AudioOuputStream for Mac OS X using the 34 // AUHAL Audio Unit present in OS 10.4 and later. 35 // It is useful for low-latency output with optional synchronized 36 // input. 37 // 38 // Overview of operation: 39 // 1) An object of AUHALStream is created by the AudioManager 40 // factory: audio_man->MakeAudioStream(). 41 // 2) Next some thread will call Open(), at that point the underlying 42 // AUHAL Audio Unit is created and configured to use the |device|. 43 // 3) Then some thread will call Start(source). 44 // Then the AUHAL is started which creates its own thread which 45 // periodically will call the source for more data as buffers are being 46 // consumed. 47 // 4) At some point some thread will call Stop(), which we handle by directly 48 // stopping the default output Audio Unit. 49 // 6) The same thread that called stop will call Close() where we cleanup 50 // and notify the audio manager, which likely will destroy this object. 51 52 class AUHALStream : public AudioOutputStream { 53 public: 54 // |manager| creates this object. 55 // |device| is the CoreAudio device to use for the stream. 56 // It will often be the default output device. 57 AUHALStream(AudioManagerMac* manager, 58 const AudioParameters& params, 59 AudioDeviceID device); 60 // The dtor is typically called by the AudioManager only and it is usually 61 // triggered by calling AudioOutputStream::Close(). 62 virtual ~AUHALStream(); 63 64 // Implementation of AudioOutputStream. 65 virtual bool Open() OVERRIDE; 66 virtual void Close() OVERRIDE; 67 virtual void Start(AudioSourceCallback* callback) OVERRIDE; 68 virtual void Stop() OVERRIDE; 69 virtual void SetVolume(double volume) OVERRIDE; 70 virtual void GetVolume(double* volume) OVERRIDE; 71 72 private: 73 // AUHAL callback. 74 static OSStatus InputProc(void* user_data, 75 AudioUnitRenderActionFlags* flags, 76 const AudioTimeStamp* time_stamp, 77 UInt32 bus_number, 78 UInt32 number_of_frames, 79 AudioBufferList* io_data); 80 81 OSStatus Render(AudioUnitRenderActionFlags* flags, 82 const AudioTimeStamp* output_time_stamp, 83 UInt32 bus_number, 84 UInt32 number_of_frames, 85 AudioBufferList* io_data); 86 87 // Called by either |audio_fifo_| or Render() to provide audio data. 88 void ProvideInput(int frame_delay, AudioBus* dest); 89 90 // Helper method to enable input and output. 91 bool EnableIO(bool enable, UInt32 scope); 92 93 // Sets the stream format on the AUHAL to PCM Float32 non-interleaved 94 // for the given number of channels on the given scope and element. 95 // The created stream description will be stored in |desc|. 96 bool SetStreamFormat(AudioStreamBasicDescription* desc, 97 int channels, 98 UInt32 scope, 99 UInt32 element); 100 101 // Creates the AUHAL, sets its stream format, buffer-size, etc. 102 bool ConfigureAUHAL(); 103 104 // Creates the input and output busses. 105 void CreateIOBusses(); 106 107 // Gets the fixed playout device hardware latency and stores it. Returns 0 108 // if not available. 109 double GetHardwareLatency(); 110 111 // Gets the current playout latency value. 112 double GetPlayoutLatency(const AudioTimeStamp* output_time_stamp); 113 114 // Our creator, the audio manager needs to be notified when we close. 115 AudioManagerMac* const manager_; 116 117 const AudioParameters params_; 118 // For convenience - same as in params_. 119 const int input_channels_; 120 const int output_channels_; 121 122 // Buffer-size. 123 const size_t number_of_frames_; 124 125 // Pointer to the object that will provide the audio samples. 126 AudioSourceCallback* source_; 127 128 // Protects |source_|. Necessary since Render() calls seem to be in flight 129 // when |audio_unit_| is supposedly stopped. See http://crbug.com/178765. 130 base::Lock source_lock_; 131 132 // Holds the stream format details such as bitrate. 133 AudioStreamBasicDescription input_format_; 134 AudioStreamBasicDescription output_format_; 135 136 // The audio device to use with the AUHAL. 137 // We can potentially handle both input and output with this device. 138 const AudioDeviceID device_; 139 140 // The AUHAL Audio Unit which talks to |device_|. 141 AudioUnit audio_unit_; 142 143 // Volume level from 0 to 1. 144 float volume_; 145 146 // Fixed playout hardware latency in frames. 147 double hardware_latency_frames_; 148 149 // The flag used to stop the streaming. 150 bool stopped_; 151 152 // The input AudioUnit renders its data here. 153 scoped_ptr<uint8[]> input_buffer_list_storage_; 154 AudioBufferList* input_buffer_list_; 155 156 // Holds the actual data for |input_buffer_list_|. 157 scoped_ptr<AudioBus> input_bus_; 158 159 // Container for retrieving data from AudioSourceCallback::OnMoreIOData(). 160 scoped_ptr<AudioBus> output_bus_; 161 162 // Dynamically allocated FIFO used when CoreAudio asks for unexpected frame 163 // sizes. 164 scoped_ptr<AudioPullFifo> audio_fifo_; 165 166 // Current buffer delay. Set by Render(). 167 uint32 current_hardware_pending_bytes_; 168 169 DISALLOW_COPY_AND_ASSIGN(AUHALStream); 170 }; 171 172 } // namespace media 173 174 #endif // MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_ 175