diff options
author | skobes@google.com <skobes@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 22:08:05 +0000 |
---|---|---|
committer | skobes@google.com <skobes@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 22:08:05 +0000 |
commit | ab2066f6062f3acec61bce9b2cb52910549d051d (patch) | |
tree | a7120570dff5c48844cb0b312cf362f5ab41666e /media/audio/win/audio_unified_win.h | |
parent | 0cfa96c53fc8f28c5c60c950fb278db89a05d9ad (diff) | |
download | chromium_src-ab2066f6062f3acec61bce9b2cb52910549d051d.zip chromium_src-ab2066f6062f3acec61bce9b2cb52910549d051d.tar.gz chromium_src-ab2066f6062f3acec61bce9b2cb52910549d051d.tar.bz2 |
Revert 249790 "Remove the unified IO code on the browser."
http://build.chromium.org/p/chromium.chromiumos/builders/ChromiumOS%20%28amd64%29/builds/14117
chromeos-chrome-34.0.1829.0_alpha-r1: ../../../../../../../home/chrome-bot/chrome_root/src/media/audio/linux/audio_manager_linux.cc: In function 'media::AudioManager* media::CreateAudioManager(media::AudioLogFactory*)':
chromeos-chrome-34.0.1829.0_alpha-r1: ../../../../../../../home/chrome-bot/chrome_root/src/media/audio/linux/audio_manager_linux.cc:33:50: error: cannot allocate an object of abstract type 'media::AudioManagerCras'
chromeos-chrome-34.0.1829.0_alpha-r1: return new AudioManagerCras(audio_log_factory);
chromeos-chrome-34.0.1829.0_alpha-r1: ^
> Remove the unified IO code on the browser.
>
> Unified IO is not used any more and it should be removed.
>
>
> BUG=337096
> TEST=bots, and nothing breaks.
>
> Review URL: https://codereview.chromium.org/153623004
TBR=xians@chromium.org
Review URL: https://codereview.chromium.org/136233005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249811 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio/win/audio_unified_win.h')
-rw-r--r-- | media/audio/win/audio_unified_win.h | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/media/audio/win/audio_unified_win.h b/media/audio/win/audio_unified_win.h new file mode 100644 index 0000000..76c5329 --- /dev/null +++ b/media/audio/win/audio_unified_win.h @@ -0,0 +1,352 @@ +// 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_WIN_AUDIO_UNIFIED_WIN_H_ +#define MEDIA_AUDIO_WIN_AUDIO_UNIFIED_WIN_H_ + +#include <Audioclient.h> +#include <MMDeviceAPI.h> + +#include <string> + +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "base/threading/platform_thread.h" +#include "base/threading/simple_thread.h" +#include "base/win/scoped_co_mem.h" +#include "base/win/scoped_comptr.h" +#include "base/win/scoped_handle.h" +#include "media/audio/audio_io.h" +#include "media/audio/audio_parameters.h" +#include "media/base/audio_fifo.h" +#include "media/base/channel_mixer.h" +#include "media/base/media_export.h" +#include "media/base/multi_channel_resampler.h" + +namespace media { + +class AudioManagerWin; + +// Implementation of AudioOutputStream for Windows using the Core Audio API +// where both capturing and rendering takes place on the same thread to enable +// audio I/O. This class allows arbitrary combinations of input and output +// devices running off different clocks and using different drivers, with +// potentially differing sample-rates. +// +// 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. +// The inner operation depends on the input sample rate which is determined +// during construction. Three different main modes are supported: +// +// 1) input rate == output rate => input side drives output side directly. +// 2) input rate != output rate => both sides are driven independently by +// events and a FIFO plus a resampling unit is used to compensate for +// differences in sample rates between the two sides. +// 3) input rate == output rate but native buffer sizes are not identical => +// same inner functionality as in (2) to compensate for the differences +// in buffer sizes and also compensate for any potential clock drift +// between the two devices. +// +// Mode detection is is done at construction and using mode (1) will lead to +// best performance (lower delay and no "varispeed distortion"), i.e., it is +// recommended to use same sample rates for input and output. Mode (2) uses a +// resampler which supports rate adjustments to fine tune for things like +// clock drift and differences in sample rates between different devices. +// Mode (2) - which uses a FIFO and a adjustable multi-channel resampler - +// is also called the varispeed mode and it is used for case (3) as well to +// compensate for the difference in buffer sizes mainly. +// Mode (3) can happen if two different audio devices are used. +// As an example: some devices needs a buffer size of 441 @ 44.1kHz and others +// 448 @ 44.1kHz. This is a rare case and will only happen for sample rates +// which are even multiples of 11025 Hz (11025, 22050, 44100, 88200 etc.). +// +// Implementation notes: +// +// - Open() can fail if the input and output parameters do not fulfill +// certain conditions. See source for Open() for more details. +// - Channel mixing will be performed if the clients asks for a larger +// number of channels than the native audio layer provides. +// Example: client wants stereo but audio layer provides mono. In this case +// upmixing from mono to stereo (1->2) will be done. +// +// TODO(henrika): +// +// - Add support for exclusive mode. +// - Add support for KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, i.e., 32-bit float +// as internal sample-value representation. +// - Perform fine-tuning for non-matching sample rates to reduce latency. +// +class MEDIA_EXPORT WASAPIUnifiedStream + : public AudioOutputStream, + public base::DelegateSimpleThread::Delegate { + public: + // The ctor takes all the usual parameters, plus |manager| which is the + // the audio manager who is creating this object. + WASAPIUnifiedStream(AudioManagerWin* manager, + const AudioParameters& params, + const std::string& input_device_id); + + // The dtor is typically called by the AudioManager only and it is usually + // triggered by calling AudioOutputStream::Close(). + virtual ~WASAPIUnifiedStream(); + + // Implementation of AudioOutputStream. + virtual bool Open() OVERRIDE; + virtual void Start(AudioSourceCallback* callback) OVERRIDE; + virtual void Stop() OVERRIDE; + virtual void Close() OVERRIDE; + virtual void SetVolume(double volume) OVERRIDE; + virtual void GetVolume(double* volume) OVERRIDE; + + bool started() const { + return audio_io_thread_.get() != NULL; + } + + // Returns true if input sample rate differs from the output sample rate. + // A FIFO and a adjustable multi-channel resampler are utilized in this mode. + bool VarispeedMode() const { return (fifo_ && resampler_); } + + private: + enum { + // Time in milliseconds between two successive delay measurements. + // We save resources by not updating the delay estimates for each capture + // event (typically 100Hz rate). + kTimeDiffInMillisecondsBetweenDelayMeasurements = 1000, + + // Max possible FIFO size. + kFifoSize = 16384, + + // This value was determined empirically for minimum latency while still + // guarding against FIFO under-runs. The actual target size will be equal + // to kTargetFifoSafetyFactor * (native input buffer size). + // TODO(henrika): tune this value for lowest possible latency for all + // possible sample rate combinations. + kTargetFifoSafetyFactor = 2 + }; + + // Additional initialization required when input and output sample rate + // differs. Allocates resources for |fifo_|, |resampler_|, |render_event_|, + // and the |capture_bus_| and configures the |input_format_| structure + // given the provided input and output audio parameters. + void DoVarispeedInitialization(const AudioParameters& input_params, + const AudioParameters& output_params); + + // Clears varispeed related components such as the FIFO and the resampler. + void ResetVarispeed(); + + // Builds WAVEFORMATEX structures for input and output based on input and + // output audio parameters. + void SetIOFormats(const AudioParameters& input_params, + const AudioParameters& output_params); + + // DelegateSimpleThread::Delegate implementation. + virtual void Run() OVERRIDE; + + // MultiChannelResampler::MultiChannelAudioSourceProvider implementation. + // Callback for providing more data into the resampler. + // Only used in varispeed mode, i.e., when input rate != output rate. + virtual void ProvideInput(int frame_delay, AudioBus* audio_bus); + + // Issues the OnError() callback to the |source_|. + void HandleError(HRESULT err); + + // Stops and joins the audio thread in case of an error. + void StopAndJoinThread(HRESULT err); + + // Converts unique endpoint ID to user-friendly device name. + std::string GetDeviceName(LPCWSTR device_id) const; + + // Called on the audio IO thread for each capture event. + // Buffers captured audio into a FIFO if varispeed is used or into an audio + // bus if input and output sample rates are identical. + void ProcessInputAudio(); + + // Called on the audio IO thread for each render event when varispeed is + // active or for each capture event when varispeed is not used. + // In varispeed mode, it triggers a resampling callback, which reads from the + // FIFO, and calls AudioSourceCallback::OnMoreIOData using the resampled + // input signal and at the same time asks for data to play out. + // If input and output rates are the same - instead of reading from the FIFO + // and do resampling - we read directly from the audio bus used to store + // captured data in ProcessInputAudio. + void ProcessOutputAudio(IAudioClock* audio_output_clock); + + // Contains the thread ID of the creating thread. + base::PlatformThreadId creating_thread_id_; + + // Our creator, the audio manager needs to be notified when we close. + AudioManagerWin* manager_; + + // Contains the audio parameter structure provided at construction. + AudioParameters params_; + // For convenience, same as in params_. + int input_channels_; + int output_channels_; + + // Unique ID of the input device to be opened. + const std::string input_device_id_; + + // The sharing mode for the streams. + // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE + // where AUDCLNT_SHAREMODE_SHARED is the default. + AUDCLNT_SHAREMODE share_mode_; + + // Rendering and capturing is driven by this thread (no message loop). + // All OnMoreIOData() callbacks will be called from this thread. + scoped_ptr<base::DelegateSimpleThread> audio_io_thread_; + + // Contains the desired audio output format which is set up at construction. + // 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. + WAVEFORMATPCMEX output_format_; + + // Contains the native audio input format which is set up at construction + // if varispeed mode is utilized. + WAVEFORMATPCMEX input_format_; + + // True when successfully opened. + bool opened_; + + // Volume level from 0 to 1 used for output scaling. + double volume_; + + // Size in audio frames of each audio packet where an audio packet + // is defined as the block of data which the destination is expected to + // receive in each OnMoreIOData() callback. + size_t output_buffer_size_frames_; + + // Size in audio frames of each audio packet where an audio packet + // is defined as the block of data which the source is expected to + // deliver in each OnMoreIOData() callback. + size_t input_buffer_size_frames_; + + // Length of the audio endpoint buffer. + uint32 endpoint_render_buffer_size_frames_; + uint32 endpoint_capture_buffer_size_frames_; + + // Counts the number of audio frames written to the endpoint buffer. + uint64 num_written_frames_; + + // Time stamp for last delay measurement. + base::TimeTicks last_delay_sample_time_; + + // Contains the total (sum of render and capture) delay in milliseconds. + double total_delay_ms_; + + // Contains the total (sum of render and capture and possibly FIFO) delay + // in bytes. The update frequency is set by a constant called + // |kTimeDiffInMillisecondsBetweenDelayMeasurements|. + int total_delay_bytes_; + + // Pointer to the client that will deliver audio samples to be played out. + AudioSourceCallback* source_; + + // IMMDevice interfaces which represents audio endpoint devices. + base::win::ScopedComPtr<IMMDevice> endpoint_render_device_; + base::win::ScopedComPtr<IMMDevice> endpoint_capture_device_; + + // IAudioClient interfaces which enables a client to create and initialize + // an audio stream between an audio application and the audio engine. + base::win::ScopedComPtr<IAudioClient> audio_output_client_; + base::win::ScopedComPtr<IAudioClient> audio_input_client_; + + // IAudioRenderClient interfaces enables a client to write output + // data to a rendering endpoint buffer. + base::win::ScopedComPtr<IAudioRenderClient> audio_render_client_; + + // IAudioCaptureClient interfaces enables a client to read input + // data from a capturing endpoint buffer. + base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_; + + // The audio engine will signal this event each time a buffer has been + // recorded. + base::win::ScopedHandle capture_event_; + + // The audio engine will signal this event each time it needs a new + // audio buffer to play out. + // Only utilized in varispeed mode. + base::win::ScopedHandle render_event_; + + // This event will be signaled when streaming shall stop. + base::win::ScopedHandle stop_streaming_event_; + + // Container for retrieving data from AudioSourceCallback::OnMoreIOData(). + scoped_ptr<AudioBus> output_bus_; + + // Container for sending data to AudioSourceCallback::OnMoreIOData(). + scoped_ptr<AudioBus> input_bus_; + + // Container for storing output from the channel mixer. + scoped_ptr<AudioBus> channel_bus_; + + // All members below are only allocated, or used, in varispeed mode: + + // Temporary storage of resampled input audio data. + scoped_ptr<AudioBus> resampled_bus_; + + // Set to true first time a capture event has been received in varispeed + // mode. + bool input_callback_received_; + + // MultiChannelResampler is a multi channel wrapper for SincResampler; + // allowing high quality sample rate conversion of multiple channels at once. + scoped_ptr<MultiChannelResampler> resampler_; + + // Resampler I/O ratio. + double io_sample_rate_ratio_; + + // Used for input to output buffering. + scoped_ptr<AudioFifo> fifo_; + + // The channel mixer is only created and utilized if number of input channels + // is larger than the native number of input channels (e.g client wants + // stereo but the audio device only supports mono). + scoped_ptr<ChannelMixer> channel_mixer_; + + // The optimal number of frames we'd like to keep in the FIFO at all times. + int target_fifo_frames_; + + // A running average of the measured delta between actual number of frames + // in the FIFO versus |target_fifo_frames_|. + double average_delta_; + + // A varispeed rate scalar which is calculated based on FIFO drift. + double fifo_rate_compensation_; + + // Set to true when input side signals output side that a new delay + // estimate is needed. + bool update_output_delay_; + + // Capture side stores its delay estimate so the sum can be derived in + // the render side. + double capture_delay_ms_; + + // TODO(henrika): possibly remove these members once the performance is + // properly tuned. Only used for off-line debugging. +#ifndef NDEBUG + enum LogElementNames { + INPUT_TIME_STAMP, + NUM_FRAMES_IN_FIFO, + RESAMPLER_MARGIN, + RATE_COMPENSATION + }; + + scoped_ptr<int64[]> input_time_stamps_; + scoped_ptr<int[]> num_frames_in_fifo_; + scoped_ptr<int[]> resampler_margin_; + scoped_ptr<double[]> fifo_rate_comps_; + scoped_ptr<int[]> num_elements_; + scoped_ptr<int[]> input_params_; + scoped_ptr<int[]> output_params_; + + FILE* data_file_; + FILE* param_file_; +#endif + + DISALLOW_COPY_AND_ASSIGN(WASAPIUnifiedStream); +}; + +} // namespace media + +#endif // MEDIA_AUDIO_WIN_AUDIO_UNIFIED_WIN_H_ |