Chromium Code Reviews| Index: media/audio/mac/audio_synchronized_mac.h |
| =================================================================== |
| --- media/audio/mac/audio_synchronized_mac.h (revision 0) |
| +++ media/audio/mac/audio_synchronized_mac.h (revision 0) |
| @@ -0,0 +1,203 @@ |
| +// Copyright (c) 2012 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. |
| + |
| +#ifndef MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ |
| +#define MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ |
| + |
| +#include <AudioToolbox/AudioToolbox.h> |
| +#include <AudioUnit/AudioUnit.h> |
| +#include <CoreAudio/CoreAudio.h> |
| + |
| +#include "base/compiler_specific.h" |
| +#include "base/synchronization/lock.h" |
| +#include "media/audio/audio_io.h" |
| +#include "media/audio/audio_parameters.h" |
| +#include "media/base/audio_fifo.h" |
| + |
| +namespace media { |
| + |
| +class AudioManagerMac; |
| + |
| +// AudioSynchronizedStream allows arbitrary combinations of input and output |
| +// devices running off different clocks and using different drivers, with |
| +// potentially differing sample-rates. It implements AudioOutputStream |
| +// and shuttles its synchronized I/O data using AudioSourceCallback. |
| +// |
| +// It is required to first acquire the native sample rate of the selected |
| +// output device and then use the same rate when creating this object. |
| +// |
| +// ............................................................................ |
| +// Theory of Operation: |
| +// . |
| +// INPUT THREAD . OUTPUT THREAD |
| +// +-----------------+ +------+ . |
| +// | Input AudioUnit | --> | | . |
| +// +-----------------+ | | . |
| +// | FIFO | . |
| +// | | +-----------+ |
| +// | | -----> | Varispeed | |
| +// | | +-----------+ |
| +// +------+ . | |
| +// . | +-----------+ |
| +// . OnMoreIOData() --> | Output AU | |
| +// . +-----------+ |
| +// |
| +// The input AudioUnit's InputProc is called on one thread which feeds the |
| +// FIFO. The output AudioUnit's OutputProc is called on a second thread |
| +// which pulls on the varispeed to get the current input data. The varispeed |
| +// handles mismatches between input and output sample-rate and also clock drift |
| +// between the input and output drivers. The varispeed consumes its data from |
| +// the FIFO and adjusts its rate dynamically according to the amount |
| +// of data buffered in the FIFO. If the FIFO starts getting too much data |
| +// buffered then the varispeed will speed up slightly to compensate |
| +// and similarly if the FIFO doesn't have enough data buffered then the |
| +// varispeed will slow down slightly. |
| +// |
| +// Finally, once the input data is available then OnMoreIOData() is called |
| +// which is given this input, and renders the output which is finally sent |
| +// to the Output AudioUnit. |
| +// |
| +class AudioSynchronizedStream : public AudioOutputStream { |
| + public: |
| + // The ctor takes all the usual parameters, plus |manager| which is the |
| + // the audio manager who is creating this object. |
| + AudioSynchronizedStream(AudioManagerMac* manager, |
| + const AudioParameters& params, |
| + AudioDeviceID input_id, |
| + AudioDeviceID output_id); |
| + |
| + virtual ~AudioSynchronizedStream(); |
| + |
| + // 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; |
| + |
| + OSStatus SetInputDeviceAsCurrent(AudioDeviceID input_id); |
| + OSStatus SetOutputDeviceAsCurrent(AudioDeviceID output_id); |
| + AudioDeviceID GetInputDeviceID() { return input_info_.id_; } |
| + AudioDeviceID GetOutputDeviceID() { return output_info_.id_; } |
| + |
| + bool IsRunning(); |
| + |
| + private: |
| + // Initialization. |
| + OSStatus CreateAudioUnits(); |
| + OSStatus SetupInput(AudioDeviceID input_id); |
| + OSStatus EnableIO(); |
| + OSStatus SetupOutput(AudioDeviceID output_id); |
| + OSStatus SetupCallbacks(); |
| + OSStatus SetupStreamFormats(); |
| + void AllocateInputData(); |
| + |
| + void ComputeThruOffset(); |
| + |
| + // Handlers for the AudioUnit callbacks. |
| + OSStatus HandleInputCallback(AudioUnitRenderActionFlags* io_action_flags, |
| + const AudioTimeStamp* time_stamp, |
| + UInt32 bus_number, |
| + UInt32 number_of_frames, |
| + AudioBufferList* io_data); |
| + |
| + OSStatus HandleVarispeedCallback(AudioUnitRenderActionFlags* io_action_flags, |
| + const AudioTimeStamp* time_stamp, |
| + UInt32 bus_number, |
| + UInt32 number_of_frames, |
| + AudioBufferList* io_data); |
| + |
| + OSStatus HandleOutputCallback(AudioUnitRenderActionFlags* io_action_flags, |
| + const AudioTimeStamp* time_stamp, |
| + UInt32 bus_number, |
| + UInt32 number_of_frames, |
| + AudioBufferList* io_data); |
| + |
| + // AudioUnit callbacks. |
| + static OSStatus InputProc(void* user_data, |
| + AudioUnitRenderActionFlags* io_action_flags, |
| + const AudioTimeStamp* time_stamp, |
| + UInt32 bus_number, |
| + UInt32 number_of_frames, |
| + AudioBufferList* io_data); |
| + |
| + static OSStatus VarispeedProc(void* user_data, |
| + AudioUnitRenderActionFlags* io_action_flags, |
| + const AudioTimeStamp* time_stamp, |
| + UInt32 bus_number, |
| + UInt32 number_of_frames, |
| + AudioBufferList* io_data); |
| + |
| + static OSStatus OutputProc(void* user_data, |
| + AudioUnitRenderActionFlags* io_action_flags, |
| + const AudioTimeStamp* time_stamp, |
| + UInt32 bus_number, |
| + UInt32 number_of_frames, |
| + AudioBufferList* io_data); |
| + |
| + // Our creator. |
| + AudioManagerMac* manager_; |
| + |
| + // Pointer to the object that will provide the audio samples. |
| + AudioSourceCallback* source_; |
| + |
| + // Values used in Open(). |
| + AudioDeviceID input_id_; |
| + AudioDeviceID output_id_; |
| + |
| + // The input AudioUnit renders its data here. |
| + AudioBufferList* input_data_; |
| + |
| + class AudioDeviceInfo { |
| + public: |
| + AudioDeviceInfo() |
| + : id_(kAudioDeviceUnknown), |
|
scherkus (not reviewing)
2012/09/13 13:06:03
should be indented by two more spaces
Chris Rogers
2012/09/15 00:06:08
Done.
|
| + is_input_(false), |
| + buffer_size_frames_(0) {} |
| + void Initialize(AudioDeviceID inID, bool isInput); |
| + bool IsInitialized() const { return id_ != kAudioDeviceUnknown; } |
| + |
| + AudioDeviceID id_; |
| + bool is_input_; |
| + UInt32 buffer_size_frames_; |
| + }; |
| + |
| + AudioDeviceInfo input_info_; |
| + AudioDeviceInfo output_info_; |
| + |
| + // Used for input to output buffering. |
| + AudioFifo fifo_; |
| + |
| + // Protect FIFO access. |
| + // TODO(crogers): the correct solution is to make AudioFifo thread-safe. |
| + // This lock is just a stop-gap, and is not good since it can cause glitches |
| + // if the lock is contended. |
| + base::Lock fifo_lock_; |
| + |
| + bool is_fifo_initialized_; |
| + double fifo_rate_compensation_; |
| + double output_sample_rate_; |
| + |
| + // AudioUnits. |
| + AudioUnit input_unit_; |
| + AudioUnit varispeed_unit_; |
| + AudioUnit output_unit_; |
| + |
| + // Initial latency estimation. |
| + double first_input_time_; |
| + double first_output_time_; |
| + double in_to_out_sample_offset_; |
| + |
| + bool is_running_; |
| + UInt32 hardware_buffer_size_; |
|
scherkus (not reviewing)
2012/09/13 13:06:03
any chance we can swap UInt32 for int, size_t, uin
Chris Rogers
2012/09/15 00:06:08
Removed here and in a few other places. But there
|
| + int channels_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(AudioSynchronizedStream); |
| +}; |
| + |
| +} // namespace media |
| + |
| +#endif // MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ |