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/cancelable_callback.h" 24#include "base/compiler_specific.h" 25#include "base/synchronization/lock.h" 26#include "media/audio/audio_io.h" 27#include "media/audio/audio_parameters.h" 28 29namespace media { 30 31class AudioManagerMac; 32class AudioPullFifo; 33 34// Implementation of AudioOuputStream for Mac OS X using the 35// AUHAL Audio Unit present in OS 10.4 and later. 36// It is useful for low-latency output. 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 // Sets the stream format on the AUHAL to PCM Float32 non-interleaved 91 // for the given number of channels on the given scope and element. 92 // The created stream description will be stored in |desc|. 93 bool SetStreamFormat(AudioStreamBasicDescription* desc, 94 int channels, 95 UInt32 scope, 96 UInt32 element); 97 98 // Creates the AUHAL, sets its stream format, buffer-size, etc. 99 bool ConfigureAUHAL(); 100 101 // Creates the input and output busses. 102 void CreateIOBusses(); 103 104 // Gets the fixed playout device hardware latency and stores it. Returns 0 105 // if not available. 106 double GetHardwareLatency(); 107 108 // Gets the current playout latency value. 109 double GetPlayoutLatency(const AudioTimeStamp* output_time_stamp); 110 111 // Our creator, the audio manager needs to be notified when we close. 112 AudioManagerMac* const manager_; 113 114 const AudioParameters params_; 115 // For convenience - same as in params_. 116 const int output_channels_; 117 118 // Buffer-size. 119 const size_t number_of_frames_; 120 121 // Pointer to the object that will provide the audio samples. 122 AudioSourceCallback* source_; 123 124 // Protects |source_|. Necessary since Render() calls seem to be in flight 125 // when |audio_unit_| is supposedly stopped. See http://crbug.com/178765. 126 base::Lock source_lock_; 127 128 // Holds the stream format details such as bitrate. 129 AudioStreamBasicDescription output_format_; 130 131 // The audio device to use with the AUHAL. 132 // We can potentially handle both input and output with this device. 133 const AudioDeviceID device_; 134 135 // The AUHAL Audio Unit which talks to |device_|. 136 AudioUnit audio_unit_; 137 138 // Volume level from 0 to 1. 139 float volume_; 140 141 // Fixed playout hardware latency in frames. 142 double hardware_latency_frames_; 143 144 // The flag used to stop the streaming. 145 bool stopped_; 146 147 // Container for retrieving data from AudioSourceCallback::OnMoreData(). 148 scoped_ptr<AudioBus> output_bus_; 149 150 // Dynamically allocated FIFO used when CoreAudio asks for unexpected frame 151 // sizes. 152 scoped_ptr<AudioPullFifo> audio_fifo_; 153 154 // Current buffer delay. Set by Render(). 155 uint32 current_hardware_pending_bytes_; 156 157 // Used to defer Start() to workaround http://crbug.com/160920. 158 base::CancelableClosure deferred_start_cb_; 159 160 DISALLOW_COPY_AND_ASSIGN(AUHALStream); 161}; 162 163} // namespace media 164 165#endif // MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_ 166