// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Implementation notes: // // - It is recommended to first acquire the native sample rate of the default // output device and then use the same rate when creating this object. // Use AudioManagerMac::HardwareSampleRate() to retrieve the sample rate. // - Calling Close() also leads to self destruction. // - The latency consists of two parts: // 1) Hardware latency, which includes Audio Unit latency, audio device // latency; // 2) The delay between the moment getting the callback and the scheduled time // stamp that tells when the data is going to be played out. // #ifndef MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_ #define MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_ #include <AudioUnit/AudioUnit.h> #include <CoreAudio/CoreAudio.h> #include "base/cancelable_callback.h" #include "base/compiler_specific.h" #include "base/synchronization/lock.h" #include "media/audio/audio_io.h" #include "media/audio/audio_parameters.h" namespace media { class AudioManagerMac; class AudioPullFifo; // Implementation of AudioOuputStream for Mac OS X using the // AUHAL Audio Unit present in OS 10.4 and later. // It is useful for low-latency output with optional synchronized // input. // // Overview of operation: // 1) An object of AUHALStream is created by the AudioManager // factory: audio_man->MakeAudioStream(). // 2) Next some thread will call Open(), at that point the underlying // AUHAL Audio Unit is created and configured to use the |device|. // 3) Then some thread will call Start(source). // Then the AUHAL is started which creates its own thread which // periodically will call the source for more data as buffers are being // consumed. // 4) At some point some thread will call Stop(), which we handle by directly // stopping the default output Audio Unit. // 6) The same thread that called stop will call Close() where we cleanup // and notify the audio manager, which likely will destroy this object. class AUHALStream : public AudioOutputStream { public: // |manager| creates this object. // |device| is the CoreAudio device to use for the stream. // It will often be the default output device. AUHALStream(AudioManagerMac* manager, const AudioParameters& params, AudioDeviceID device); // The dtor is typically called by the AudioManager only and it is usually // triggered by calling AudioOutputStream::Close(). virtual ~AUHALStream(); // Implementation of AudioOutputStream. virtual bool Open() OVERRIDE; virtual void Close() OVERRIDE; virtual void Start(AudioSourceCallback* callback) OVERRIDE; virtual void Stop() OVERRIDE; virtual void SetVolume(double volume) OVERRIDE; virtual void GetVolume(double* volume) OVERRIDE; private: // AUHAL callback. static OSStatus InputProc(void* user_data, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time_stamp, UInt32 bus_number, UInt32 number_of_frames, AudioBufferList* io_data); OSStatus Render(AudioUnitRenderActionFlags* flags, const AudioTimeStamp* output_time_stamp, UInt32 bus_number, UInt32 number_of_frames, AudioBufferList* io_data); // Called by either |audio_fifo_| or Render() to provide audio data. void ProvideInput(int frame_delay, AudioBus* dest); // Helper method to enable input and output. bool EnableIO(bool enable, UInt32 scope); // Sets the stream format on the AUHAL to PCM Float32 non-interleaved // for the given number of channels on the given scope and element. // The created stream description will be stored in |desc|. bool SetStreamFormat(AudioStreamBasicDescription* desc, int channels, UInt32 scope, UInt32 element); // Creates the AUHAL, sets its stream format, buffer-size, etc. bool ConfigureAUHAL(); // Creates the input and output busses. void CreateIOBusses(); // Gets the fixed playout device hardware latency and stores it. Returns 0 // if not available. double GetHardwareLatency(); // Gets the current playout latency value. double GetPlayoutLatency(const AudioTimeStamp* output_time_stamp); // Our creator, the audio manager needs to be notified when we close. AudioManagerMac* const manager_; const AudioParameters params_; // For convenience - same as in params_. const int input_channels_; const int output_channels_; // Buffer-size. const size_t number_of_frames_; // Pointer to the object that will provide the audio samples. AudioSourceCallback* source_; // Protects |source_|. Necessary since Render() calls seem to be in flight // when |audio_unit_| is supposedly stopped. See http://crbug.com/178765. base::Lock source_lock_; // Holds the stream format details such as bitrate. AudioStreamBasicDescription input_format_; AudioStreamBasicDescription output_format_; // The audio device to use with the AUHAL. // We can potentially handle both input and output with this device. const AudioDeviceID device_; // The AUHAL Audio Unit which talks to |device_|. AudioUnit audio_unit_; // Volume level from 0 to 1. float volume_; // Fixed playout hardware latency in frames. double hardware_latency_frames_; // The flag used to stop the streaming. bool stopped_; // The input AudioUnit renders its data here. scoped_ptr<uint8[]> input_buffer_list_storage_; AudioBufferList* input_buffer_list_; // Holds the actual data for |input_buffer_list_|. scoped_ptr<AudioBus> input_bus_; // Container for retrieving data from AudioSourceCallback::OnMoreIOData(). scoped_ptr<AudioBus> output_bus_; // Dynamically allocated FIFO used when CoreAudio asks for unexpected frame // sizes. scoped_ptr<AudioPullFifo> audio_fifo_; // Current buffer delay. Set by Render(). uint32 current_hardware_pending_bytes_; // Used to defer Start() to workaround http://crbug.com/160920. base::CancelableClosure deferred_start_cb_; DISALLOW_COPY_AND_ASSIGN(AUHALStream); }; } // namespace media #endif // MEDIA_AUDIO_MAC_AUDIO_AUHAL_MAC_H_