audio_auhal_mac.h revision f2477e01787aa58f445919b809d89e252beef54f
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 28namespace media { 29 30class AudioManagerMac; 31class 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 52class 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