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; 31 32// Implementation of AudioOuputStream for Mac OS X using the 33// AUHAL Audio Unit present in OS 10.4 and later. 34// It is useful for low-latency output with optional synchronized 35// input. 36// 37// Overview of operation: 38// 1) An object of AUHALStream is created by the AudioManager 39// factory: audio_man->MakeAudioStream(). 40// 2) Next some thread will call Open(), at that point the underlying 41// AUHAL Audio Unit is created and configured to use the |device|. 42// 3) Then some thread will call Start(source). 43// Then the AUHAL is started which creates its own thread which 44// periodically will call the source for more data as buffers are being 45// consumed. 46// 4) At some point some thread will call Stop(), which we handle by directly 47// stopping the default output Audio Unit. 48// 6) The same thread that called stop will call Close() where we cleanup 49// and notify the audio manager, which likely will destroy this object. 50 51class AUHALStream : public AudioOutputStream { 52 public: 53 // |manager| creates this object. 54 // |device| is the CoreAudio device to use for the stream. 55 // It will often be the default output device. 56 AUHALStream(AudioManagerMac* manager, 57 const AudioParameters& params, 58 AudioDeviceID device); 59 // The dtor is typically called by the AudioManager only and it is usually 60 // triggered by calling AudioOutputStream::Close(). 61 virtual ~AUHALStream(); 62 63 // Implementation of AudioOutputStream. 64 virtual bool Open() OVERRIDE; 65 virtual void Close() OVERRIDE; 66 virtual void Start(AudioSourceCallback* callback) OVERRIDE; 67 virtual void Stop() OVERRIDE; 68 virtual void SetVolume(double volume) OVERRIDE; 69 virtual void GetVolume(double* volume) OVERRIDE; 70 71 private: 72 // AUHAL callback. 73 static OSStatus InputProc(void* user_data, 74 AudioUnitRenderActionFlags* flags, 75 const AudioTimeStamp* time_stamp, 76 UInt32 bus_number, 77 UInt32 number_of_frames, 78 AudioBufferList* io_data); 79 80 OSStatus Render(AudioUnitRenderActionFlags* flags, 81 const AudioTimeStamp* output_time_stamp, 82 UInt32 bus_number, 83 UInt32 number_of_frames, 84 AudioBufferList* io_data); 85 86 // Helper method to enable input and output. 87 bool EnableIO(bool enable, UInt32 scope); 88 89 // Sets the stream format on the AUHAL to PCM Float32 non-interleaved 90 // for the given number of channels on the given scope and element. 91 // The created stream description will be stored in |desc|. 92 bool SetStreamFormat(AudioStreamBasicDescription* desc, 93 int channels, 94 UInt32 scope, 95 UInt32 element); 96 97 // Creates the AUHAL, sets its stream format, buffer-size, etc. 98 bool ConfigureAUHAL(); 99 100 // Creates the input and output busses. 101 void CreateIOBusses(); 102 103 // Gets the fixed playout device hardware latency and stores it. Returns 0 104 // if not available. 105 double GetHardwareLatency(); 106 107 // Gets the current playout latency value. 108 double GetPlayoutLatency(const AudioTimeStamp* output_time_stamp); 109 110 // Our creator, the audio manager needs to be notified when we close. 111 AudioManagerMac* manager_; 112 113 AudioParameters params_; 114 // For convenience - same as in params_. 115 int input_channels_; 116 int output_channels_; 117 118 // Buffer-size. 119 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 input_format_; 130 AudioStreamBasicDescription output_format_; 131 132 // The audio device to use with the AUHAL. 133 // We can potentially handle both input and output with this device. 134 AudioDeviceID device_; 135 136 // The AUHAL Audio Unit which talks to |device_|. 137 AudioUnit audio_unit_; 138 139 // Volume level from 0 to 1. 140 float volume_; 141 142 // Fixed playout hardware latency in frames. 143 double hardware_latency_frames_; 144 145 // The flag used to stop the streaming. 146 bool stopped_; 147 148 // The flag used to indicate if the AudioManager has been notified of a 149 // potential device change. Reset to false during Start(). 150 bool notified_for_possible_device_change_; 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 DISALLOW_COPY_AND_ASSIGN(AUHALStream); 163}; 164 165} // namespace media 166 167#endif // MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_ 168